freeipa-3.3.4/0000775000175000017500000000000012271707517012513 5ustar mkosekmkosekfreeipa-3.3.4/.tx/0000775000175000017500000000000012271663206013220 5ustar mkosekmkosekfreeipa-3.3.4/.tx/config0000664000175000017500000000021512271663206014406 0ustar mkosekmkosek[main] host = https://www.transifex.com [freeipa.ipa] file_filter = install/po/.po source_file = install/po/ipa.pot source_lang = en freeipa-3.3.4/TODO0000664000175000017500000000611112202434255013170 0ustar mkosekmkosekGeneral ipalib/ipaserver improvements ------------------------------------- * Port any commands still using old crud base classes to new crud base classes, and then remove old crud base classes. * Add a Command.backend convenience attribute that checks if the class uses_backend attribute is sets the Command.backend attribute like this: self.backend = self.Backend[self.uses_backend] * Possibly generalize current Plugin.call() method (makes subprocess calls). Probably should renamed this so it's not confused with Command.execute()... maybe Plugin.subprocess_call()?. * Add special logging methods to Plugin baseclass for authorization events (escalation, de-escalation, and denial)... need to talk to John about this. * Implement remaining missing features for full gettext service. * Add ability to register pre-op, post-op plugins per command. * Change Command so it filters args/options according to the Param.limit_to kwarg (used to restrict certain params only to client or only to server). * Add ability to have a post-processing step that only gets called client-side. It should have a signature like output_for_cli() minus the textui argument. Need to decide whether we allow this method to modify the return value. (Use case still isn't very defined.) * Improve CLI help to take advantange of the fact that command docstrings are now split into summary and details. * Remove remaining __getattr__() use in ipalib.plugable. CRUD base classes ----------------- * The Retrieve method should add in the common Flag('all') option for retrieving all attributes. * We probably need some LDAP centric crud method base classes, like LDAPCreate, etc. Or other options it to have an LDAPObject base class and have the crud Method plugins rely more on their corresponding Object plugin. Existing plugins ---------------- * Many existing plugins that are doing crud-type operations aren't using the Object + Method way of defining their parameters, and are therefore defining the exact same parameter several times in a module. This should be fixed one way or another... if there are deficiencies in the crud base classes, they need to be improved. Command Line interface ---------------------- * Further enhance textui plugin * Make possible Enum values self-documenting... this might require writing our own replacement for optparse. The isn't way to make optparse deal with the global options the way Jason would like, so that's another motivation. * Add a File param type so an argument may be read from a file. This is needed for cert-request to pass along the CSR. * Replace RequiresRoot() with more fine-grained control based on the files that need to be read/written Packaging --------- * Use setuptools instead of plain distutils * Make setup.py generate dev-docs and run unit tests * Package for deb/apt (debian/ dir) Migration --------- * Add the IPAService objectclass to existing principals * Move existng host/ principals from cn=services to cn=computers? freeipa-3.3.4/make-lint0000775000175000017500000002240212271663206014316 0ustar mkosekmkosek#!/usr/bin/python # # Authors: # Jakub Hrozek # Jan Cholasta # # Copyright (C) 2011 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 . import os import sys from optparse import OptionParser from fnmatch import fnmatch, fnmatchcase try: from pylint import checkers from pylint.lint import PyLinter from pylint.checkers.typecheck import TypeChecker try: # Pylint 1.0 from astroid import Class, Instance, InferenceError from pylint.reporters.text import TextReporter have_pylint_1_0 = True except ImportError: # Older Pylint from logilab.astng import Class, Instance, InferenceError from pylint.reporters.text import ParseableTextReporter have_pylint_1_0 = False except ImportError: print >> sys.stderr, "To use {0}, please install pylint.".format(sys.argv[0]) sys.exit(32) # File names to ignore when searching for python source files IGNORE_FILES = ('.*', '*~', '*.in', '*.pyc', '*.pyo') IGNORE_PATHS = ('build', 'rpmbuild', 'dist', 'install/po/test_i18n.py', 'lite-server.py', 'make-lint', 'make-test', 'ipatests') class IPATypeChecker(TypeChecker): NAMESPACE_ATTRS = ['Command', 'Object', 'Method', 'Property', 'Backend', 'Updater', 'Advice'] LOGGING_ATTRS = ['log', 'debug', 'info', 'warning', 'error', 'exception', 'critical'] # 'class': ['generated', 'properties'] ignore = { # Python standard library & 3rd party classes 'krbV.Principal': ['name'], 'socket._socketobject': ['sendall'], # should be 'subprocess.Popen' '.Popen': ['stdin', 'stdout', 'stderr', 'pid', 'returncode', 'poll', 'wait', 'communicate'], 'urlparse.ResultMixin': ['scheme', 'netloc', 'path', 'query', 'fragment', 'username', 'password', 'hostname', 'port'], 'urlparse.ParseResult': ['params'], # IPA classes 'ipalib.base.NameSpace': ['add', 'mod', 'del', 'show', 'find'], 'ipalib.cli.Collector': ['__options'], 'ipalib.config.Env': ['*'], 'ipalib.krb_utils.KRB5_CCache': LOGGING_ATTRS, 'ipalib.parameters.Param': ['cli_name', 'cli_short_name', 'label', 'default', 'doc', 'required', 'multivalue', 'primary_key', 'normalizer', 'default_from', 'autofill', 'query', 'attribute', 'include', 'exclude', 'flags', 'hint', 'alwaysask', 'sortorder', 'csv', 'option_group'], 'ipalib.parameters.Bool': ['truths', 'falsehoods'], 'ipalib.parameters.Data': ['minlength', 'maxlength', 'length', 'pattern', 'pattern_errmsg'], 'ipalib.parameters.Str': ['noextrawhitespace'], 'ipalib.parameters.Password': ['confirm'], 'ipalib.parameters.File': ['stdin_if_missing'], 'ipalib.plugins.dns.DNSRecord': ['validatedns', 'normalizedns'], 'ipalib.parameters.Enum': ['values'], 'ipalib.parameters.Number': ['minvalue', 'maxvalue'], 'ipalib.parameters.Decimal': ['precision', 'exponential', 'numberclass'], 'ipalib.plugable.API': NAMESPACE_ATTRS + LOGGING_ATTRS, 'ipalib.plugable.Plugin': ['api', 'env'] + NAMESPACE_ATTRS + LOGGING_ATTRS, 'ipalib.session.AuthManager': LOGGING_ATTRS, 'ipalib.session.SessionAuthManager': LOGGING_ATTRS, 'ipalib.session.SessionManager': LOGGING_ATTRS, 'ipaserver.install.ldapupdate.LDAPUpdate': LOGGING_ATTRS, 'ipaserver.rpcserver.KerberosSession': ['api'] + LOGGING_ATTRS, } def _related_classes(self, klass): yield klass for base in klass.ancestors(): yield base def _class_full_name(self, klass): return klass.root().name + '.' + klass.name def _find_ignored_attrs(self, owner): attrs = [] for klass in self._related_classes(owner): name = self._class_full_name(klass) if name in self.ignore: attrs += self.ignore[name] return attrs def visit_getattr(self, node): try: inferred = list(node.expr.infer()) except InferenceError: inferred = [] for owner in inferred: if not isinstance(owner, Class) and type(owner) is not Instance: continue ignored = self._find_ignored_attrs(owner) for pattern in ignored: if fnmatchcase(node.attrname, pattern): return super(IPATypeChecker, self).visit_getattr(node) class IPALinter(PyLinter): ignore = (TypeChecker,) def __init__(self): super(IPALinter, self).__init__() self.missing = set() def register_checker(self, checker): if type(checker) in self.ignore: return super(IPALinter, self).register_checker(checker) def add_message(self, msg_id, line=None, node=None, args=None): if line is None and node is not None: line = node.fromlineno # Record missing packages if msg_id == 'F0401' and self.is_message_enabled(msg_id, line): self.missing.add(args) super(IPALinter, self).add_message(msg_id, line, node, args) def find_files(path, basepath): entries = os.listdir(path) # If this directory is a python package, look no further if '__init__.py' in entries: return [path] result = [] for filename in entries: filepath = os.path.join(path, filename) for pattern in IGNORE_FILES: if fnmatch(filename, pattern): filename = None break if filename is None: continue for pattern in IGNORE_PATHS: patpath = os.path.join(basepath, pattern).replace(os.sep, '/') if filepath == patpath: filename = None break if filename is None: continue if os.path.islink(filepath): continue # Recurse into subdirectories if os.path.isdir(filepath): result += find_files(filepath, basepath) continue # Add all *.py files if filename.endswith('.py'): result.append(filepath) continue # Add any other files beginning with a shebang and having # the word "python" on the first line file = open(filepath, 'r') line = file.readline(128) file.close() if line[:2] == '#!' and line.find('python') >= 0: result.append(filepath) return result def main(): optparser = OptionParser() optparser.add_option('--no-fail', help='report success even if errors were found', dest='fail', default=True, action='store_false') optparser.add_option('--enable-noerror', help='enable warnings and other non-error messages', dest='errors_only', default=True, action='store_false') options, args = optparser.parse_args() cwd = os.getcwd() if len(args) == 0: files = find_files(cwd, cwd) else: files = args for filename in files: dirname = os.path.dirname(filename) if dirname not in sys.path: sys.path.insert(0, dirname) linter = IPALinter() checkers.initialize(linter) linter.register_checker(IPATypeChecker(linter)) if options.errors_only: linter.disable_noerror_messages() linter.enable('F') if have_pylint_1_0: linter.set_reporter(TextReporter()) linter.set_option('msg-template', '{path}:{line}: [{msg_id}({symbol}), {obj}] {msg})') else: linter.set_reporter(ParseableTextReporter()) linter.set_option('include-ids', True) linter.set_option('reports', False) linter.set_option('persistent', False) linter.check(files) if linter.msg_status != 0: print >> sys.stderr, """ =============================================================================== Errors were found during the static code check. """ if len(linter.missing) > 0: print >> sys.stderr, "There are some missing imports:" for mod in sorted(linter.missing): print >> sys.stderr, " " + mod print >> sys.stderr, """ Please make sure all of the required and optional (python-krbV, python-rhsm) python packages are installed. """ print >> sys.stderr, """\ If you are certain that any of the reported errors are false positives, please mark them in the source code according to the pylint documentation. =============================================================================== """ if options.fail: return linter.msg_status else: return 0 if __name__ == "__main__": sys.exit(main()) freeipa-3.3.4/Makefile0000664000175000017500000002105412271663206014151 0ustar mkosekmkosekinclude VERSION SUBDIRS=daemons install ipapython ipa-client CLIENTDIRS=ipapython ipa-client PRJ_PREFIX=freeipa RPMBUILD ?= $(PWD)/rpmbuild TARGET ?= master SUPPORTED_PLATFORM ?= redhat IPA_NUM_VERSION ?= $(shell printf %d%02d%02d $(IPA_VERSION_MAJOR) $(IPA_VERSION_MINOR) $(IPA_VERSION_RELEASE)) # After updating the version in VERSION you should run the version-update # target. ifeq ($(IPA_VERSION_IS_GIT_SNAPSHOT),"yes") GIT_VERSION=$(shell git show --pretty=format:"%h" --stat HEAD 2>/dev/null|head -1) ifneq ($(GIT_VERSION),) IPA_VERSION=$(IPA_VERSION_MAJOR).$(IPA_VERSION_MINOR).$(IPA_VERSION_RELEASE)GIT$(GIT_VERSION) endif # in a git tree and git returned a version endif # git ifndef IPA_VERSION ifdef IPA_VERSION_PRE_RELEASE IPA_VERSION=$(IPA_VERSION_MAJOR).$(IPA_VERSION_MINOR).$(IPA_VERSION_RELEASE).pre$(IPA_VERSION_PRE_RELEASE) else ifdef IPA_VERSION_BETA_RELEASE IPA_VERSION=$(IPA_VERSION_MAJOR).$(IPA_VERSION_MINOR).$(IPA_VERSION_RELEASE).beta$(IPA_VERSION_BETA_RELEASE) else ifdef IPA_VERSION_RC_RELEASE IPA_VERSION=$(IPA_VERSION_MAJOR).$(IPA_VERSION_MINOR).$(IPA_VERSION_RELEASE).rc$(IPA_VERSION_RC_RELEASE) else IPA_VERSION=$(IPA_VERSION_MAJOR).$(IPA_VERSION_MINOR).$(IPA_VERSION_RELEASE) endif # rc endif # beta endif # pre endif # ipa_version TARBALL_PREFIX=freeipa-$(IPA_VERSION) TARBALL=$(TARBALL_PREFIX).tar.gz IPA_RPM_RELEASE=$(shell cat RELEASE) LIBDIR ?= /usr/lib DEVELOPER_MODE ?= 0 ifneq ($(DEVELOPER_MODE),0) LINT_OPTIONS=--no-fail endif PYTHON ?= $(shell rpm -E %__python) # Uncomment to increase Java stack size for Web UI build in case it fails # because of stack overflow exception. Default should be OK for most platforms. #JAVA_STACK_SIZE ?= 8m #export JAVA_STACK_SIZE all: bootstrap-autogen server tests @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ done client: client-autogen @for subdir in $(CLIENTDIRS); do \ (cd $$subdir && $(MAKE) all) || exit 1; \ done bootstrap-autogen: version-update client-autogen @echo "Building IPA $(IPA_VERSION)" cd daemons; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR) --with-openldap; fi cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi client-autogen: version-update cd ipa-client; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi tests-man-autogen: version-update cd ipatests/man; if [ ! -e Makefile ]; then ../../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi install: all server-install tests-install @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ done client-install: client client-dirs @for subdir in $(CLIENTDIRS); do \ (cd $$subdir && $(MAKE) install) || exit 1; \ done cd install/po && $(MAKE) install || exit 1; if [ "$(DESTDIR)" = "" ]; then \ $(PYTHON) setup-client.py install; \ else \ $(PYTHON) setup-client.py install --root $(DESTDIR); \ fi client-dirs: @if [ "$(DESTDIR)" != "" ] ; then \ mkdir -p $(DESTDIR)/etc/ipa ; \ mkdir -p $(DESTDIR)/var/lib/ipa-client/sysrestore ; \ else \ echo "DESTDIR was not set, please create /etc/ipa and /var/lib/ipa-client/sysrestore" ; \ echo "Without those directories ipa-client-install will fail" ; \ fi lint: bootstrap-autogen ./make-lint $(LINT_OPTIONS) $(MAKE) -C install/po validate-src-strings test: ./make-testcert ./make-test release-update: if [ ! -e RELEASE ]; then echo 0 > RELEASE; fi version-update: release-update sed -e s/__VERSION__/$(IPA_VERSION)/ -e s/__RELEASE__/$(IPA_RPM_RELEASE)/ \ freeipa.spec.in > freeipa.spec sed -e s/__VERSION__/$(IPA_VERSION)/ version.m4.in \ > version.m4 sed -e s/__VERSION__/$(IPA_VERSION)/ ipapython/setup.py.in \ > ipapython/setup.py sed -e s/__VERSION__/$(IPA_VERSION)/ ipapython/version.py.in \ > ipapython/version.py sed -e s/__VERSION__/$(IPA_VERSION)/ ipatests/setup.py.in \ > ipatests/setup.py perl -pi -e "s:__NUM_VERSION__:$(IPA_NUM_VERSION):" ipapython/version.py perl -pi -e "s:__API_VERSION__:$(IPA_API_VERSION_MAJOR).$(IPA_API_VERSION_MINOR):" ipapython/version.py touch -r ipapython/version.py.in ipapython/version.py sed -e s/__VERSION__/$(IPA_VERSION)/ daemons/ipa-version.h.in \ > daemons/ipa-version.h perl -pi -e "s:__NUM_VERSION__:$(IPA_NUM_VERSION):" daemons/ipa-version.h perl -pi -e "s:__DATA_VERSION__:$(IPA_DATA_VERSION):" daemons/ipa-version.h sed -e s/__VERSION__/$(IPA_VERSION)/ -e s/__RELEASE__/$(IPA_RPM_RELEASE)/ \ ipa-client/ipa-client.spec.in > ipa-client/ipa-client.spec sed -e s/__VERSION__/$(IPA_VERSION)/ ipa-client/version.m4.in \ > ipa-client/version.m4 if [ "$(SUPPORTED_PLATFORM)" != "" ]; then \ sed -e s/SUPPORTED_PLATFORM/$(SUPPORTED_PLATFORM)/ ipapython/services.py.in \ > ipapython/services.py; \ touch -r ipapython/services.py.in ipapython/services.py; \ fi if [ "$(SKIP_API_VERSION_CHECK)" != "yes" ]; then \ ./makeapi --validate; \ fi server: version-update $(PYTHON) setup.py build server-install: server if [ "$(DESTDIR)" = "" ]; then \ $(PYTHON) setup.py install; \ else \ $(PYTHON) setup.py install --root $(DESTDIR); \ fi tests: version-update tests-man-autogen cd ipatests; $(PYTHON) setup.py build cd ipatests/man && $(MAKE) all tests-install: tests if [ "$(DESTDIR)" = "" ]; then \ cd ipatests; $(PYTHON) setup.py install; \ else \ cd ipatests; $(PYTHON) setup.py install --root $(DESTDIR); \ fi cd ipatests/man && $(MAKE) install archive: -mkdir -p dist git archive --format=tar --prefix=ipa/ $(TARGET) | (cd dist && tar xf -) local-archive: -mkdir -p dist/$(TARBALL_PREFIX) rsync -a --exclude=dist --exclude=.git --exclude=/build --exclude=rpmbuild . dist/$(TARBALL_PREFIX) archive-cleanup: rm -fr dist/freeipa tarballs: local-archive -mkdir -p dist/sources # tar up clean sources cd dist/$(TARBALL_PREFIX)/ipa-client; ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); make distclean cd dist/$(TARBALL_PREFIX)/daemons; ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); make distclean cd dist/$(TARBALL_PREFIX)/install; ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); make distclean cd dist; tar cfz sources/$(TARBALL) $(TARBALL_PREFIX) rm -rf dist/$(TARBALL_PREFIX) rpmroot: rm -rf $(RPMBUILD) mkdir -p $(RPMBUILD)/BUILD mkdir -p $(RPMBUILD)/RPMS mkdir -p $(RPMBUILD)/SOURCES mkdir -p $(RPMBUILD)/SPECS mkdir -p $(RPMBUILD)/SRPMS rpmdistdir: mkdir -p dist/rpms mkdir -p dist/srpms rpms: rpmroot rpmdistdir version-update lint tarballs cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/. rpmbuild --define "_topdir $(RPMBUILD)" -ba freeipa.spec cp $(RPMBUILD)/RPMS/*/$(PRJ_PREFIX)-*-$(IPA_VERSION)-*.rpm dist/rpms/ cp $(RPMBUILD)/SRPMS/$(PRJ_PREFIX)-$(IPA_VERSION)-*.src.rpm dist/srpms/ rm -rf $(RPMBUILD) client-rpms: rpmroot rpmdistdir version-update lint tarballs cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/. rpmbuild --define "_topdir $(RPMBUILD)" --define "ONLY_CLIENT 1" -ba freeipa.spec cp $(RPMBUILD)/RPMS/*/$(PRJ_PREFIX)-*-$(IPA_VERSION)-*.rpm dist/rpms/ cp $(RPMBUILD)/SRPMS/$(PRJ_PREFIX)-$(IPA_VERSION)-*.src.rpm dist/srpms/ rm -rf $(RPMBUILD) srpms: rpmroot rpmdistdir version-update lint tarballs cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/. rpmbuild --define "_topdir $(RPMBUILD)" -bs freeipa.spec cp $(RPMBUILD)/SRPMS/$(PRJ_PREFIX)-$(IPA_VERSION)-*.src.rpm dist/srpms/ rm -rf $(RPMBUILD) repodata: -createrepo -p dist dist: version-update archive tarballs archive-cleanup rpms repodata local-dist: bootstrap-autogen clean local-archive tarballs archive-cleanup rpms clean: version-update @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ done rm -f *~ distclean: version-update touch daemons/NEWS daemons/README daemons/AUTHORS daemons/ChangeLog touch install/NEWS install/README install/AUTHORS install/ChangeLog @for subdir in $(SUBDIRS); do \ (cd $$subdir && $(MAKE) $@) || exit 1; \ done rm -fr $(RPMBUILD) dist build rm -f daemons/NEWS daemons/README daemons/AUTHORS daemons/ChangeLog rm -f install/NEWS install/README install/AUTHORS install/ChangeLog maintainer-clean: clean rm -fr $(RPMBUILD) dist build cd daemons && $(MAKE) maintainer-clean cd install && $(MAKE) maintainer-clean cd ipa-client && $(MAKE) maintainer-clean cd ipapython && $(MAKE) maintainer-clean rm -f version.m4 rm -f freeipa.spec freeipa-3.3.4/version.m4.in0000664000175000017500000000004512202434255015034 0ustar mkosekmkosekdefine([IPA_VERSION], [__VERSION__]) freeipa-3.3.4/make-testcert0000775000175000017500000000752412271663206015215 0ustar mkosekmkosek#!/usr/bin/python # # Authors: # Rob Crittenden # # Copyright (C) 2011 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 . """ Generate a custom certificate used in the service unit tests. The certificate will be created in ipatests/test_xmlrpc/service.crt """ import sys import os import tempfile import shutil import nss.nss as nss from ipalib import api, x509, backend, errors from ipaserver.plugins import rabase from ipapython import ipautil from ipapython.dn import DN CERTPATH = 'ipatests/test_xmlrpc/service.crt' def run_certutil(reqdir, args, stdin=None): """ Run an NSS certutil command """ new_args = ["/usr/bin/certutil", "-d", reqdir] new_args = new_args + args return ipautil.run(new_args, stdin) def generateCSR(reqdir, pwname, subject): """ Create a CSR for the given subject. """ run_certutil(reqdir, ["-R", "-s", subject, "-o", '%s/req' % reqdir, "-z", "/etc/group", "-f", pwname, "-a", ]) fp = open('%s/req' % reqdir, "r") data = fp.read() fp.close() return data class client(backend.Executioner): """ A simple-minded IPA client that can execute remote commands. """ def run(self, method, *args, **options): self.create_context() result = self.execute(method, *args, **options) return result def makecert(reqdir): """ Generate a service certificate that can be used during unit testing. """ cfg = dict( context='cli', in_server=False, debug=False, verbose=0, ) api.bootstrap(**cfg) api.register(client) api.finalize() ra = rabase.rabase() if not os.path.exists(ra.sec_dir) and api.env.xmlrpc_uri == 'http://localhost:8888/ipa/xml': sys.exit('The in-tree self-signed CA is not configured, see ipatests/test_xmlrpc/test_cert.py') pwname = reqdir + "/pwd" # Create an empty password file fp = open(pwname, "w") fp.write("\n") fp.close() # Generate NSS cert database to store the private key for our CSR run_certutil(reqdir, ["-N", "-f", pwname]) res = api.Backend.client.run('config_show') subject_base = res['result']['ipacertificatesubjectbase'][0] cert = None subject = DN(('CN', api.env.host), subject_base) princ = 'unittest/%s@%s' % (api.env.host, api.env.realm) csr = unicode(generateCSR(reqdir, pwname, str(subject))) try: res = api.Backend.client.run('cert_request', csr, principal=princ, add=True) cert = x509.make_pem(res['result']['certificate']) fd = open(CERTPATH, 'w') fd.write(cert) fd.close() except errors.NotFound: return "certificate request failed" except errors.CommandError: return "You need to set enable_ra=True in ~/.ipa/default.conf" nss.nss_init_nodb() c = x509.load_certificate(cert, x509.PEM) print c return 0 reqdir = None if os.path.exists(CERTPATH): print "Test certificate %s exists, skipping." % CERTPATH sys.exit(0) try: reqdir = tempfile.mkdtemp(prefix = "tmp-") sys.exit(makecert(reqdir)) finally: shutil.rmtree(reqdir) freeipa-3.3.4/version.m40000664000175000017500000000003712271707517014442 0ustar mkosekmkosekdefine([IPA_VERSION], [3.3.4]) freeipa-3.3.4/freeipa.spec0000664000175000017500000016612312271707517015013 0ustar mkosekmkosek# Define ONLY_CLIENT to only make the ipa-client and ipa-python subpackages %{!?ONLY_CLIENT:%global ONLY_CLIENT 0} %global plugin_dir %{_libdir}/dirsrv/plugins %global POLICYCOREUTILSVER 2.1.12-5 %global gettext_domain ipa %if (0%{?fedora} > 15 || 0%{?rhel} >= 7) %define _hardened_build 1 %endif Name: freeipa Version: 3.3.4 Release: 0%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base License: GPLv3+ URL: http://www.freeipa.org/ Source0: freeipa-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if ! %{ONLY_CLIENT} BuildRequires: 389-ds-base-devel >= 1.3.1.3 BuildRequires: svrcore-devel BuildRequires: policycoreutils >= %{POLICYCOREUTILSVER} BuildRequires: systemd-units %if 0%{?fedora} >= 18 BuildRequires: samba-devel >= 2:4.0.5-1 BuildRequires: samba-python BuildRequires: libwbclient-devel %else BuildRequires: samba4-devel >= 4.0.0-139 BuildRequires: samba4-python %endif BuildRequires: libtalloc-devel BuildRequires: libtevent-devel %endif # ONLY_CLIENT BuildRequires: nspr-devel BuildRequires: nss-devel BuildRequires: openssl-devel BuildRequires: openldap-devel BuildRequires: krb5-devel >= 1.11 BuildRequires: krb5-workstation BuildRequires: libuuid-devel BuildRequires: libcurl-devel >= 7.21.7-2 BuildRequires: xmlrpc-c-devel >= 1.27.4 BuildRequires: popt-devel BuildRequires: autoconf BuildRequires: automake BuildRequires: m4 BuildRequires: libtool BuildRequires: gettext BuildRequires: python-devel BuildRequires: python-ldap BuildRequires: python-setuptools BuildRequires: python-krbV BuildRequires: python-nss BuildRequires: python-netaddr BuildRequires: python-kerberos BuildRequires: python-rhsm BuildRequires: pyOpenSSL BuildRequires: pylint BuildRequires: python-polib BuildRequires: libipa_hbac-python BuildRequires: python-memcached BuildRequires: sssd >= 1.9.2 BuildRequires: python-lxml BuildRequires: python-pyasn1 >= 0.0.9a BuildRequires: python-dns BuildRequires: m2crypto BuildRequires: check BuildRequires: libsss_idmap-devel BuildRequires: libsss_nss_idmap-devel BuildRequires: java-1.7.0-openjdk BuildRequires: libverto-devel BuildRequires: systemd BuildRequires: libunistring-devel # Find out Kerberos middle version to infer ABI changes in DAL driver # We cannot load DAL driver into KDC with wrong ABI. # This is also needed to support ipa-devel repository where krb5 1.11 is available for F18 %global krb5_dal_version %{expand:%(echo "#include "|cpp -dM|grep KRB5_KDB_DAL_MAJOR_VERSION|cut -d' ' -f3)} %description IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). %if ! %{ONLY_CLIENT} %package server Summary: The IPA authentication server Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: %{name}-client = %{version}-%{release} Requires: %{name}-admintools = %{version}-%{release} Requires: 389-ds-base >= 1.3.1.3 Requires: openldap-clients > 2.4.35-4 %if 0%{?fedora} == 18 Requires: nss >= 3.14.3-2 Requires: nss-tools >= 3.14.3-2 %else Requires: nss >= 3.14.3-12.0 Requires: nss-tools >= 3.14.3-12.0 %endif %if 0%{?krb5_dal_version} >= 4 Requires: krb5-server >= 1.11.2-1 %else %if 0%{krb5_dal_version} == 3 # krb5 1.11 bumped DAL interface major version, a rebuild is needed Requires: krb5-server < 1.11 Requires: krb5-server >= 1.10 %else Requires: krb5-server >= 1.10 %endif %endif Requires: krb5-pkinit-openssl Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: httpd Requires: mod_wsgi %if 0%{?fedora} >= 18 Requires: mod_auth_kerb >= 5.4-16 %else Requires: mod_auth_kerb >= 5.4-8 %endif Requires: mod_nss >= 1.0.8-24 Requires: python-ldap Requires: python-krbV Requires: acl Requires: python-pyasn1 Requires: memcached Requires: python-memcached Requires: systemd-units >= 38 Requires(pre): systemd-units Requires(post): systemd-units Requires: selinux-policy >= 3.12.1-65 Requires(post): selinux-policy-base Requires: slapi-nis >= 0.47.7 Requires: pki-ca >= 10.0.4 Requires: dogtag-pki-server-theme %if 0%{?rhel} Requires: subscription-manager %endif Requires(preun): python systemd-units Requires(postun): python systemd-units Requires: python-dns Requires: zip Requires: policycoreutils >= %{POLICYCOREUTILSVER} Requires: tar Requires(pre): certmonger >= 0.65 Requires(pre): 389-ds-base >= 1.3.1.3 # With FreeIPA 3.3, package freeipa-server-selinux was obsoleted as the # entire SELinux policy is stored in the system policy Obsoletes: freeipa-server-selinux < 3.3.0 # 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 < 3.5 %else Conflicts: bind-dyndb-ldap < 1.1.0-0.12.rc1 %endif Conflicts: bind < 9.8.2-0.4.rc2 # Versions of nss-pam-ldapd < 0.8.4 require a mapping from uniqueMember to # member. Conflicts: nss-pam-ldapd < 0.8.4 Obsoletes: ipa-server >= 1.0 %description server IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If you are installing an IPA server you need to install this package (in other words, most people should NOT install this package). %package server-trust-ad Summary: Virtual package to install packages required for Active Directory trusts Group: System Environment/Base Requires: %{name}-server = %version-%release Requires: m2crypto %if 0%{?fedora} >= 18 Requires: samba-python Requires: samba >= 2:4.0.5-1 Requires: samba-winbind %else Requires: samba4-python Requires: samba4 Requires: samba4-winbind %endif Requires: libsss_idmap %if 0%{?fedora} >= 19 Requires: libsss_nss_idmap-python %endif # We use alternatives to divert winbind_krb5_locator.so plugin to libkrb5 # on the installes where server-trust-ad subpackage is installed because # IPA AD trusts cannot be used at the same time with the locator plugin # since Winbindd will be configured in a different mode Requires(post): %{_sbindir}/update-alternatives Requires(post): python Requires(postun): %{_sbindir}/update-alternatives Requires(preun): %{_sbindir}/update-alternatives %description server-trust-ad Cross-realm trusts with Active Directory in IPA require working Samba 4 installation. This package is provided for convenience to install all required dependencies at once. %endif # ONLY_CLIENT %package client Summary: IPA authentication for use on clients Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: python-ldap Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: krb5-workstation Requires: authconfig Requires: pam_krb5 Requires: wget Requires: libcurl >= 7.21.7-2 Requires: xmlrpc-c >= 1.27.4 Requires: sssd >= 1.11.1 Requires: certmonger >= 0.65 Requires: nss-tools Requires: bind-utils Requires: oddjob-mkhomedir Requires: python-krbV Requires: python-dns Requires: libsss_autofs Requires: autofs Requires: libnfsidmap Requires: nfs-utils Requires(post): policycoreutils Obsoletes: ipa-client >= 1.0 %description client IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If your network uses IPA for authentication, this package should be installed on every client machine. %if ! %{ONLY_CLIENT} %package admintools Summary: IPA administrative tools Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: %{name}-client = %{version}-%{release} Requires: python-krbV Requires: python-ldap Obsoletes: ipa-admintools >= 1.0 %description admintools IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). This package provides command-line tools for IPA administrators. %endif # ONLY_CLIENT %package python Summary: Python libraries used by IPA Group: System Environment/Libraries Requires: python-kerberos Requires: gnupg Requires: iproute Requires: keyutils Requires: pyOpenSSL Requires: python-nss Requires: python-lxml Requires: python-netaddr Requires: libipa_hbac-python Obsoletes: ipa-python >= 1.0 %description python IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If you are using IPA you need to install this package. %if ! %{ONLY_CLIENT} %package tests Summary: IPA tests and test tools Requires: %{name}-client = %{version}-%{release} Requires: %{name}-python = %{version}-%{release} Requires: tar Requires: xz Requires: python-nose Requires: python-paste Requires: python-coverage Requires: python-polib Requires: python-paramiko >= 1.7.7 %description tests IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). This package contains tests that verify IPA functionality. %endif # ONLY_CLIENT %prep %setup -n freeipa-%{version} -q %build %ifarch ppc %{power64} s390 s390x # UI compilation segfaulted on some arches when the stack was lower (#1040576) export JAVA_STACK_SIZE="8m" %endif export CFLAGS="$CFLAGS %{optflags}" export CPPFLAGS="$CPPFLAGS %{optflags}" %if 0%{?fedora} >= 18 # use fedora18 platform which is based on fedora16 platform with systemd # support + fedora18 changes export SUPPORTED_PLATFORM=fedora18 %else export SUPPORTED_PLATFORM=fedora16 %endif # Force re-generate of platform support rm -f ipapython/services.py make version-update cd ipa-client; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd .. %if ! %{ONLY_CLIENT} cd daemons; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir} --with-openldap; cd .. cd install; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd .. %endif # ONLY_CLIENT %if ! %{ONLY_CLIENT} make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} all %else make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} client %endif # ONLY_CLIENT %install rm -rf %{buildroot} %if 0%{?fedora} >= 18 # use fedora18 platform which is based on fedora16 platform with systemd # support + fedora18 changes export SUPPORTED_PLATFORM=fedora18 %else export SUPPORTED_PLATFORM=fedora16 %endif # Force re-generate of platform support rm -f ipapython/services.py %if ! %{ONLY_CLIENT} make install DESTDIR=%{buildroot} %else make client-install DESTDIR=%{buildroot} %endif # ONLY_CLIENT %find_lang %{gettext_domain} %if ! %{ONLY_CLIENT} # Remove .la files from libtool - we don't want to package # these files rm %{buildroot}/%{plugin_dir}/libipa_pwd_extop.la rm %{buildroot}/%{plugin_dir}/libipa_enrollment_extop.la rm %{buildroot}/%{plugin_dir}/libipa_winsync.la rm %{buildroot}/%{plugin_dir}/libipa_repl_version.la rm %{buildroot}/%{plugin_dir}/libipa_uuid.la rm %{buildroot}/%{plugin_dir}/libipa_modrdn.la rm %{buildroot}/%{plugin_dir}/libipa_lockout.la rm %{buildroot}/%{plugin_dir}/libipa_cldap.la rm %{buildroot}/%{plugin_dir}/libipa_dns.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen_task.la rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la rm %{buildroot}/%{plugin_dir}/libipa_range_check.la rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la # Some user-modifiable HTML files are provided. Move these to /etc # and link back. mkdir -p %{buildroot}/%{_sysconfdir}/ipa/html mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysrestore mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysupgrade mkdir %{buildroot}%{_usr}/share/ipa/html/ ln -s ../../../..%{_sysconfdir}/ipa/html/ffconfig.js \ %{buildroot}%{_usr}/share/ipa/html/ffconfig.js ln -s ../../../..%{_sysconfdir}/ipa/html/ffconfig_page.js \ %{buildroot}%{_usr}/share/ipa/html/ffconfig_page.js ln -s ../../../..%{_sysconfdir}/ipa/html/ssbrowser.html \ %{buildroot}%{_usr}/share/ipa/html/ssbrowser.html ln -s ../../../..%{_sysconfdir}/ipa/html/unauthorized.html \ %{buildroot}%{_usr}/share/ipa/html/unauthorized.html ln -s ../../../..%{_sysconfdir}/ipa/html/browserconfig.html \ %{buildroot}%{_usr}/share/ipa/html/browserconfig.html ln -s ../../../..%{_sysconfdir}/ipa/html/ipa_error.css \ %{buildroot}%{_usr}/share/ipa/html/ipa_error.css # So we can own our Apache configuration mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d/ /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa.conf /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf mkdir -p %{buildroot}%{_usr}/share/ipa/html/ /bin/touch %{buildroot}%{_usr}/share/ipa/html/ca.crt /bin/touch %{buildroot}%{_usr}/share/ipa/html/configure.jar /bin/touch %{buildroot}%{_usr}/share/ipa/html/kerberosauth.xpi /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.con /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.js /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb5.ini /bin/touch %{buildroot}%{_usr}/share/ipa/html/krbrealm.con /bin/touch %{buildroot}%{_usr}/share/ipa/html/preferences.html mkdir -p %{buildroot}%{_initrddir} mkdir %{buildroot}%{_sysconfdir}/sysconfig/ install -m 644 init/ipa_memcached.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa_memcached # Web UI plugin dir mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins # NOTE: systemd specific section mkdir -p %{buildroot}%{_prefix}/lib/tmpfiles.d install -m 0644 init/systemd/ipa.conf.tmpfiles %{buildroot}%{_prefix}/lib/tmpfiles.d/%{name}.conf # END mkdir -p %{buildroot}%{_localstatedir}/run/ install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa_memcached/ install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa/ mkdir -p %{buildroot}%{_libdir}/krb5/plugins/libkrb5 touch %{buildroot}%{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so # NOTE: systemd specific section mkdir -p %{buildroot}%{_unitdir} install -m 644 init/systemd/ipa.service %{buildroot}%{_unitdir}/ipa.service install -m 644 init/systemd/ipa_memcached.service %{buildroot}%{_unitdir}/ipa_memcached.service # END mkdir -p %{buildroot}/%{_localstatedir}/lib/ipa/backup %endif # ONLY_CLIENT mkdir -p %{buildroot}%{_sysconfdir}/ipa/ /bin/touch %{buildroot}%{_sysconfdir}/ipa/default.conf /bin/touch %{buildroot}%{_sysconfdir}/ipa/ca.crt mkdir -p %{buildroot}/%{_localstatedir}/lib/ipa-client/sysrestore %if ! %{ONLY_CLIENT} mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d install -pm 644 contrib/completion/ipa.bash_completion %{buildroot}%{_sysconfdir}/bash_completion.d/ipa mkdir -p %{buildroot}%{_sysconfdir}/cron.d (cd %{buildroot}/%{python_sitelib}/ipaserver && find . -type f | \ grep -v dcerpc | grep -v adtrustinstance | \ sed -e 's,\.py.*$,.*,g' | sort -u | \ sed -e 's,\./,%%{python_sitelib}/ipaserver/,g' ) >server-python.list (cd %{buildroot}/%{python_sitelib}/ipatests && find . -type f | \ sed -e 's,\.py.*$,.*,g' | sort -u | \ sed -e 's,\./,%%{python_sitelib}/ipatests/,g' ) >tests-python.list %endif # ONLY_CLIENT %clean rm -rf %{buildroot} %if ! %{ONLY_CLIENT} %post server # NOTE: systemd specific section /bin/systemctl --system daemon-reload 2>&1 || : # END if [ $1 -gt 1 ] ; then /bin/systemctl condrestart certmonger.service 2>&1 || : 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 --quiet >/dev/null || : /usr/sbin/ipa-upgradeconfig --quiet >/dev/null || : # Restart IPA processes. This must be also run in postrans so that plugins # and software is in consistent state python -c "import sys; from ipaserver.install import installutils; sys.exit(0 if installutils.is_ipa_configured() else 1);" > /dev/null 2>&1 # NOTE: systemd specific section if [ $? -eq 0 ]; then /bin/systemctl try-restart ipa.service >/dev/null 2>&1 || : fi # END %preun server if [ $1 = 0 ]; then # NOTE: systemd specific section /bin/systemctl --quiet stop ipa.service || : /bin/systemctl --quiet disable ipa.service || : # END fi %pre server # Stop ipa_kpasswd if it exists before upgrading so we don't have a # zombie process when we're done. if [ -e /usr/sbin/ipa_kpasswd ]; then # NOTE: systemd specific section /bin/systemctl stop ipa_kpasswd.service >/dev/null 2>&1 || : # END fi %postun server-trust-ad if [ "$1" -ge "1" ]; then if [ "`readlink %{_sysconfdir}/alternatives/winbind_krb5_locator.so`" == "/dev/null" ]; then %{_sbindir}/alternatives --set winbind_krb5_locator.so /dev/null fi fi %post server-trust-ad %{_sbindir}/update-alternatives --install %{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so \ winbind_krb5_locator.so /dev/null 90 %posttrans server-trust-ad python -c "import sys; from ipaserver.install import installutils; sys.exit(0 if installutils.is_ipa_configured() else 1);" > /dev/null 2>&1 if [ $? -eq 0 ]; then # NOTE: systemd specific section /bin/systemctl try-restart httpd.service >/dev/null 2>&1 || : # END fi %preun server-trust-ad if [ $1 -eq 0 ]; then %{_sbindir}/update-alternatives --remove winbind_krb5_locator.so /dev/null fi %endif # ONLY_CLIENT %post client if [ $1 -gt 1 ] ; then # Has the client been configured? restore=0 test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}') if [ -f '/etc/sssd/sssd.conf' -a $restore -ge 2 ]; then if ! grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then echo "includedir /var/lib/sss/pubconf/krb5.include.d/" > /etc/krb5.conf.ipanew cat /etc/krb5.conf >> /etc/krb5.conf.ipanew mv /etc/krb5.conf.ipanew /etc/krb5.conf /sbin/restorecon /etc/krb5.conf fi fi if [ -f '/etc/sysconfig/ntpd' -a $restore -ge 2 ]; then if grep -E -q 'OPTIONS=.*-u ntp:ntp' /etc/sysconfig/ntpd 2>/dev/null; then sed -r '/OPTIONS=/ { s/\s+-u ntp:ntp\s+/ /; s/\s*-u ntp:ntp\s*// }' /etc/sysconfig/ntpd >/etc/sysconfig/ntpd.ipanew mv /etc/sysconfig/ntpd.ipanew /etc/sysconfig/ntpd /sbin/restorecon /etc/sysconfig/ntpd /bin/systemctl condrestart ntpd.service 2>&1 || : fi fi fi %triggerin -n freeipa-client -- openssh-server # Has the client been configured? restore=0 test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}') if [ -f '/etc/ssh/sshd_config' -a $restore -ge 2 ]; then if grep -E -q '^(AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys|PubKeyAgent /usr/bin/sss_ssh_authorizedkeys %u)$' /etc/ssh/sshd_config 2>/dev/null; then sed -r ' /^(AuthorizedKeysCommand(User|RunAs)|PubKeyAgentRunAs)[ \t]/ d ' /etc/ssh/sshd_config >/etc/ssh/sshd_config.ipanew if /usr/sbin/sshd -t -f /dev/null -o 'AuthorizedKeysCommand=/usr/bin/sss_ssh_authorizedkeys' -o 'AuthorizedKeysCommandUser=nobody'; then sed -ri ' s/^PubKeyAgent (.+) %u$/AuthorizedKeysCommand \1/ s/^AuthorizedKeysCommand .*$/\0\nAuthorizedKeysCommandUser nobody/ ' /etc/ssh/sshd_config.ipanew elif /usr/sbin/sshd -t -f /dev/null -o 'AuthorizedKeysCommand=/usr/bin/sss_ssh_authorizedkeys' -o 'AuthorizedKeysCommandRunAs=nobody'; then sed -ri ' s/^PubKeyAgent (.+) %u$/AuthorizedKeysCommand \1/ s/^AuthorizedKeysCommand .*$/\0\nAuthorizedKeysCommandRunAs nobody/ ' /etc/ssh/sshd_config.ipanew elif /usr/sbin/sshd -t -f /dev/null -o 'PubKeyAgent=/usr/bin/sss_ssh_authorizedkeys %u' -o 'PubKeyAgentRunAs=nobody'; then sed -ri ' s/^AuthorizedKeysCommand (.+)$/PubKeyAgent \1 %u/ s/^PubKeyAgent .*$/\0\nPubKeyAgentRunAs nobody/ ' /etc/ssh/sshd_config.ipanew fi mv /etc/ssh/sshd_config.ipanew /etc/ssh/sshd_config /sbin/restorecon /etc/ssh/sshd_config chmod 600 /etc/ssh/sshd_config /bin/systemctl condrestart sshd.service 2>&1 || : fi fi %if ! %{ONLY_CLIENT} %files server -f server-python.list %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_sbindir}/ipa-backup %{_sbindir}/ipa-restore %{_sbindir}/ipa-ca-install %{_sbindir}/ipa-dns-install %{_sbindir}/ipa-server-install %{_sbindir}/ipa-replica-conncheck %{_sbindir}/ipa-replica-install %{_sbindir}/ipa-replica-prepare %{_sbindir}/ipa-replica-manage %{_sbindir}/ipa-csreplica-manage %{_sbindir}/ipa-server-certinstall %{_sbindir}/ipa-ldap-updater %{_sbindir}/ipa-compat-manage %{_sbindir}/ipa-nis-manage %{_sbindir}/ipa-managed-entries %{_sbindir}/ipactl %{_sbindir}/ipa-upgradeconfig %{_sbindir}/ipa-advise %{_libexecdir}/certmonger/dogtag-ipa-retrieve-agent-submit %{_libexecdir}/ipa-otpd %config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/ %dir %attr(0700,root,root) %{_localstatedir}/run/ipa/ # NOTE: systemd specific section %{_prefix}/lib/tmpfiles.d/%{name}.conf %attr(644,root,root) %{_unitdir}/ipa.service %attr(644,root,root) %{_unitdir}/ipa_memcached.service %attr(644,root,root) %{_unitdir}/ipa-otpd.socket %attr(644,root,root) %{_unitdir}/ipa-otpd@.service # END %dir %{python_sitelib}/ipaserver %dir %{python_sitelib}/ipaserver/install %dir %{python_sitelib}/ipaserver/install/plugins %dir %{python_sitelib}/ipaserver/advise %dir %{python_sitelib}/ipaserver/advise/plugins %dir %{python_sitelib}/ipaserver/plugins %dir %{_libdir}/ipa/certmonger %attr(755,root,root) %{_libdir}/ipa/certmonger/* %dir %{_usr}/share/ipa %{_usr}/share/ipa/wsgi.py* %{_usr}/share/ipa/copy-schema-to-ca.py* %{_usr}/share/ipa/*.ldif %{_usr}/share/ipa/*.uldif %{_usr}/share/ipa/*.template %dir %{_usr}/share/ipa/advise %dir %{_usr}/share/ipa/advise/legacy %{_usr}/share/ipa/advise/legacy/*.template %dir %{_usr}/share/ipa/ffextension %{_usr}/share/ipa/ffextension/bootstrap.js %{_usr}/share/ipa/ffextension/install.rdf %{_usr}/share/ipa/ffextension/chrome.manifest %dir %{_usr}/share/ipa/ffextension/chrome %dir %{_usr}/share/ipa/ffextension/chrome/content %{_usr}/share/ipa/ffextension/chrome/content/kerberosauth.js %{_usr}/share/ipa/ffextension/chrome/content/kerberosauth_overlay.xul %dir %{_usr}/share/ipa/ffextension/locale %dir %{_usr}/share/ipa/ffextension/locale/en-US %{_usr}/share/ipa/ffextension/locale/en-US/kerberosauth.properties %dir %{_usr}/share/ipa/html %{_usr}/share/ipa/html/ffconfig.js %{_usr}/share/ipa/html/ffconfig_page.js %{_usr}/share/ipa/html/ssbrowser.html %{_usr}/share/ipa/html/browserconfig.html %{_usr}/share/ipa/html/unauthorized.html %{_usr}/share/ipa/html/ipa_error.css %dir %{_usr}/share/ipa/migration %{_usr}/share/ipa/migration/error.html %{_usr}/share/ipa/migration/index.html %{_usr}/share/ipa/migration/invalid.html %{_usr}/share/ipa/migration/migration.py* %dir %{_usr}/share/ipa/ui %{_usr}/share/ipa/ui/index.html %{_usr}/share/ipa/ui/login.html %{_usr}/share/ipa/ui/logout.html %{_usr}/share/ipa/ui/reset_password.html %{_usr}/share/ipa/ui/*.ico %{_usr}/share/ipa/ui/*.css %{_usr}/share/ipa/ui/*.js %{_usr}/share/ipa/ui/*.eot %{_usr}/share/ipa/ui/*.svg %{_usr}/share/ipa/ui/*.ttf %{_usr}/share/ipa/ui/*.woff %dir %{_usr}/share/ipa/ui/js %dir %{_usr}/share/ipa/ui/js/dojo %{_usr}/share/ipa/ui/js/dojo/dojo.js %dir %{_usr}/share/ipa/ui/js/libs %{_usr}/share/ipa/ui/js/libs/*.js %dir %{_usr}/share/ipa/ui/js/freeipa %{_usr}/share/ipa/ui/js/freeipa/app.js %dir %{_usr}/share/ipa/ui/js/plugins %dir %{_usr}/share/ipa/ui/images %{_usr}/share/ipa/ui/images/*.png %{_usr}/share/ipa/ui/images/*.gif %dir %{_usr}/share/ipa/wsgi %{_usr}/share/ipa/wsgi/plugins.py* %dir %{_sysconfdir}/ipa %dir %{_sysconfdir}/ipa/html %config(noreplace) %{_sysconfdir}/ipa/html/ffconfig.js %config(noreplace) %{_sysconfdir}/ipa/html/ffconfig_page.js %config(noreplace) %{_sysconfdir}/ipa/html/ssbrowser.html %config(noreplace) %{_sysconfdir}/ipa/html/ipa_error.css %config(noreplace) %{_sysconfdir}/ipa/html/unauthorized.html %config(noreplace) %{_sysconfdir}/ipa/html/browserconfig.html %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf %{_usr}/share/ipa/ca_renewal %{_usr}/share/ipa/ipa.conf %{_usr}/share/ipa/ipa-rewrite.conf %{_usr}/share/ipa/ipa-pki-proxy.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/configure.jar %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/kerberosauth.xpi %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.js %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb5.ini %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krbrealm.con %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/preferences.html %dir %{_usr}/share/ipa/updates/ %{_usr}/share/ipa/updates/* %attr(755,root,root) %{plugin_dir}/libipa_pwd_extop.so %attr(755,root,root) %{plugin_dir}/libipa_enrollment_extop.so %attr(755,root,root) %{plugin_dir}/libipa_winsync.so %attr(755,root,root) %{plugin_dir}/libipa_repl_version.so %attr(755,root,root) %{plugin_dir}/libipa_uuid.so %attr(755,root,root) %{plugin_dir}/libipa_modrdn.so %attr(755,root,root) %{plugin_dir}/libipa_lockout.so %attr(755,root,root) %{plugin_dir}/libipa_cldap.so %attr(755,root,root) %{plugin_dir}/libipa_dns.so %attr(755,root,root) %{plugin_dir}/libipa_range_check.so %dir %{_localstatedir}/lib/ipa %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/backup %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca %ghost %{_localstatedir}/lib/ipa/pki-ca/publish %attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so %{_mandir}/man1/ipa-replica-conncheck.1.gz %{_mandir}/man1/ipa-replica-install.1.gz %{_mandir}/man1/ipa-replica-manage.1.gz %{_mandir}/man1/ipa-csreplica-manage.1.gz %{_mandir}/man1/ipa-replica-prepare.1.gz %{_mandir}/man1/ipa-server-certinstall.1.gz %{_mandir}/man1/ipa-server-install.1.gz %{_mandir}/man1/ipa-dns-install.1.gz %{_mandir}/man1/ipa-ca-install.1.gz %{_mandir}/man1/ipa-compat-manage.1.gz %{_mandir}/man1/ipa-nis-manage.1.gz %{_mandir}/man1/ipa-managed-entries.1.gz %{_mandir}/man1/ipa-ldap-updater.1.gz %{_mandir}/man8/ipactl.8.gz %{_mandir}/man8/ipa-upgradeconfig.8.gz %{_mandir}/man1/ipa-backup.1.gz %{_mandir}/man1/ipa-restore.1.gz %{_mandir}/man1/ipa-advise.1.gz %files server-trust-ad %{_sbindir}/ipa-adtrust-install %attr(755,root,root) %{plugin_dir}/libipa_extdom_extop.so %{_usr}/share/ipa/smb.conf.empty %attr(755,root,root) %{_libdir}/samba/pdb/ipasam.so %attr(755,root,root) %{plugin_dir}/libipa_sidgen.so %attr(755,root,root) %{plugin_dir}/libipa_sidgen_task.so %{_mandir}/man1/ipa-adtrust-install.1.gz %{python_sitelib}/ipaserver/dcerpc* %{python_sitelib}/ipaserver/install/adtrustinstance* %ghost %{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so %endif # ONLY_CLIENT %files client %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_sbindir}/ipa-client-install %{_sbindir}/ipa-client-automount %{_sbindir}/ipa-getkeytab %{_sbindir}/ipa-rmkeytab %{_sbindir}/ipa-join %dir %{_usr}/share/ipa %dir %{_usr}/share/ipa/ipaclient %dir %{_localstatedir}/lib/ipa-client %dir %{_localstatedir}/lib/ipa-client/sysrestore %{_usr}/share/ipa/ipaclient/ipa.cfg %{_usr}/share/ipa/ipaclient/ipa.js %dir %{python_sitelib}/ipaclient %{python_sitelib}/ipaclient/*.py* %{_mandir}/man1/ipa-getkeytab.1.gz %{_mandir}/man1/ipa-rmkeytab.1.gz %{_mandir}/man1/ipa-client-install.1.gz %{_mandir}/man1/ipa-client-automount.1.gz %{_mandir}/man1/ipa-join.1.gz %{_mandir}/man5/default.conf.5.gz %if ! %{ONLY_CLIENT} %files admintools %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_bindir}/ipa %config %{_sysconfdir}/bash_completion.d %{_mandir}/man1/ipa.1.gz %endif # ONLY_CLIENT %files python -f %{gettext_domain}.lang %defattr(-,root,root,-) %doc COPYING README Contributors.txt %dir %{python_sitelib}/ipapython %dir %{python_sitelib}/ipapython/platform %dir %{python_sitelib}/ipapython/platform/base %dir %{python_sitelib}/ipapython/platform/fedora16 %dir %{python_sitelib}/ipapython/platform/fedora18 %dir %{python_sitelib}/ipapython/platform/redhat %{python_sitelib}/ipapython/*.py* %{python_sitelib}/ipapython/platform/*.py* %{python_sitelib}/ipapython/platform/base/*.py* %{python_sitelib}/ipapython/platform/fedora16/*.py* %{python_sitelib}/ipapython/platform/fedora18/*.py* %{python_sitelib}/ipapython/platform/redhat/*.py* %dir %{python_sitelib}/ipalib %{python_sitelib}/ipalib/* %attr(0644,root,root) %{python_sitearch}/default_encoding_utf8.so %{python_sitelib}/ipapython-*.egg-info %{python_sitelib}/freeipa-*.egg-info %{python_sitearch}/python_default_encoding-*.egg-info %dir %attr(0755,root,root) %{_sysconfdir}/ipa/ %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %if ! %{ONLY_CLIENT} %files tests -f tests-python.list %defattr(-,root,root,-) %doc COPYING README Contributors.txt %dir %{python_sitelib}/ipatests %dir %{python_sitelib}/ipatests/test_cmdline %dir %{python_sitelib}/ipatests/test_install %dir %{python_sitelib}/ipatests/test_ipalib %dir %{python_sitelib}/ipatests/test_ipapython %dir %{python_sitelib}/ipatests/test_ipaserver %dir %{python_sitelib}/ipatests/test_ipaserver/install %dir %{python_sitelib}/ipatests/test_pkcs10 %dir %{python_sitelib}/ipatests/test_webui %dir %{python_sitelib}/ipatests/test_xmlrpc %{_bindir}/ipa-run-tests %{_bindir}/ipa-test-config %{_bindir}/ipa-test-task %{python_sitelib}/ipatests-*.egg-info %{_mandir}/man1/ipa-run-tests.1.gz %{_mandir}/man1/ipa-test-config.1.gz %{_mandir}/man1/ipa-test-task.1.gz %endif # ONLY_CLIENT %changelog * Fri Oct 25 2013 Martin Kosek - 3.3.2-1 - Remove mod_ssl conflict, it can now live with mod_nss installed * Wed Sep 4 2013 Ana Krivokapic - 3.3.0-3 - Conform to tmpfiles.d packaging guidelines * Wed Aug 28 2013 Petr Viktorin - 3.3.0-2 - Add man pages to the tests subpackage * Mon Aug 12 2013 Petr Viktorin - 3.3.0-1 - Downgrade required version of python-paramiko for the tests subpackage * Thu Aug 8 2013 Martin Kosek - 3.2.99-13 - Require slapi-nis 0.47.7 and sssd 1.11.0-0.1.beta2 required for core features of 3.3.0 release * Fri Jul 26 2013 Martin Kosek - 3.2.99-12 - Require pki-ca 10.0.4 which fixes external CA installation (#986901) * Wed Jul 24 2013 Petr Viktorin - 3.2.99-11 - Add tar and xz dependencies to freeipa-tests * Wed Jul 24 2013 Tomas Babej - 3.2.99-10 - Move requirement for keyutils from freeipa-server to freeipa-python * Wed Jul 24 2013 Martin Kosek - 3.2.99-9 - Bump minimum version of sssd to 1.10.92 to pick up latest SSSD 1.11 Beta development * Thu Jul 18 2013 Ana Krivokapic - 3.2.99-8 - Bump minimum version of sssd to 1.10.90 for the 'ipa_server_mode' option. * Wed Jul 17 2013 Martin Kosek - 3.2.99-7 - Require selinux-policy 3.12.1-65 containing missing policy after removal of freeipa-server-selinux subpackage * Tue Jul 16 2013 Tomas Babej - 3.2.99-6 - Do not create /var/lib/ipa/pki-ca/publish, retain reference as ghost * Thu Jul 11 2013 Martin Kosek - 3.2.99-5 - Run ipa-upgradeconfig and server restart in posttrans to avoid inconsistency issues when there are still old parts of software (like entitlements plugin) * Wed Jul 10 2013 Ana Krivokapic - 3.2.99-4 - Bump minimum version of 389-ds-base to 1.3.1.3 for user password change fix. * Wed Jun 26 2013 Jan Cholasta - 3.2.99-3 - Bump minimum version of 389-ds-base to 1.3.1.1 for SASL mapping priority support. * Mon Jun 17 2013 Petr Viktorin - 3.2.99-2 - Add the freeipa-tests subpackage * Thu Jun 13 2013 Martin Kosek - 3.2.99-1 - Drop freeipa-server-selinux subpackage - Drop redundant directory /var/cache/ipa/sessions * Fri May 10 2013 Martin Kosek - 3.1.99-13 - Add requires for openldap-2.4.35-4 to pickup fixed SASL_NOCANON behavior for socket based connections (#960222) * Tue May 7 2013 Petr Viktorin - 3.1.99-12 - Require libsss_nss_idmap-python in Fedora 19+ * Mon May 6 2013 Petr Vobornik - 3.1.99-11 - Web UI plugins * Fri May 3 2013 Rob Crittenden - 3.1.99-10 - Require pki-ca 10.0.2 for 501 response code on find for d9 -> d10 upgrades * Tue Apr 30 2013 Rob Crittenden - 3.1.99-9 - Add Conflicts on nss-pam-ldapd < 0.8.4. The mapping from uniqueMember to member is now done automatically and having it in the config file raises an error. * Tue Apr 30 2013 Jan Cholasta - 3.1.99-8 - Add triggerin scriptlet to update sshd_config on openssh-server update * Thu Apr 25 2013 Rob Crittenden - 3.1.99-7 - Update nss and nss-tools dependency to fix certutil problem (#872761) * Mon Apr 15 2013 Martin Kosek - 3.1.99-6 - Require samba 4.0.5, includes new passdb API - Require krb5 1.11.2-1, fixes missing PAC issue - Change permissions on backup dir to 700 * Fri Apr 5 2013 Rob Crittenden - 3.1.99-5 - Add backup and restore - Own /var/lib/ipa/backup * Thu Apr 4 2013 Alexander Bokovoy - 3.1.99-4 - Make sure build against Krb5 1.11 in Fedora 18 environment creates proper dependencies * Tue Apr 2 2013 Martin Kosek - 3.1.99-3 - Require 389-base-base >= 1.3.0.5 to pull the following fixes: - upgrade deadlock caused by DNA plugin reconfiguration - CVE-2013-1897: unintended information exposure when nsslapd-allow-anonymous-access is set to rootdse * Wed Mar 27 2013 Martin Kosek - 3.1.99-2 - Remove conflict with krb5-server > 1.11 as ipa-kdb is compatible - ipa-ldap-updater show produce errors only - update policycoreutils version to 2.1.12-5 to match Requires in Fedora - require at least systemd 38 which provides the journal (we no longer need to require syslog.target) * Thu Mar 21 2013 Martin Kosek - 3.1.99-1 - Require selinux-policy 3.11.1-86 to fix Fedora 17 to 18 upgrade issue * Tue Jan 29 2013 Petr Viktorin - 3.0.99-14 - Use ipa-ldap-updater --quiet instead of redirecting to /dev/null * Tue Jan 29 2013 Rob Crittenden - 3.0.99-13 - Set certmonger minimum version to 0.65 for NSS locking during renewal - Set selinux-policy to 3.11.1-73 so certmonger can run in post scriptlet * Thu Jan 24 2013 Rob Crittenden - 3.0.99-12 - Add certmonger condrestart to server post scriptlet - Make certmonger a (pre) Requires on the server subpackage * Tue Jan 22 2013 Petr Vobornik - 3.0.99-11 - dependency fix - Add BuildRequires: java-1.7.0-openjdk. - Removed BuildRequires: rhino * Fri Jan 18 2013 Petr Vobornik - 3.0.99-10 - Add Web UI layer JS files in ui/js/{dojo,freeipa,libs} directories - Add BuildRequires: rhino * Fri Dec 7 2012 Endi S. Dewata - 3.0.99-9 - Bump minimum version of pki-ca to 10.0.0-0.54.b3 * Fri Dec 7 2012 Martin Kosek - 3.0.99-8 - Bump minimum version of 389-ds-base to 1.3.0 to get transaction support * Thu Dec 6 2012 Rob Crittenden - 3.0.99-7 - Set min for selinux-policy to 3.11.1-60 to fix errors including sssd domain mapping in krb5.conf (#873429) * Wed Nov 21 2012 Alexander Bokovoy - 3.0.99-6 - Replace python-crypto by m2crypto dependency * Fri Nov 16 2012 Rob Crittenden - 3.0.99-5 - Bump minimum version of slapi-nis to 0.44 * Wed Nov 14 2012 Martin Kosek - 3.0.99-4 - Remove compatibility definitions for unsupported Fedora versions (Fedora 16 and lower) - Do not require specific package version when the package was available in Fedora 17 - Remove old SysV initscript compatibility code - we run on systemd now - Add Requires for the new Dogtag 10 and dogtag-pki-server-theme - Remove Requires on tomcat6 for Fedora 18 and later, Dogtag 10 pulls tomcat7 itself - Add Requires for tar (used by ipa-replica-prepare) * Fri Nov 09 2012 Martin Kosek - 3.0.99-3 - Set min for bind-dyndb-ldap to 2.3-2 to pick up disabling global forwarder per-zone * Fri Oct 26 2012 Sumit Bose - 3.0.99-2 - Restart httpd in post install of server-trust-ad * Wed Oct 24 2012 Martin Kosek - 3.0.99-1 - Add strict Requires for 389-ds-base and policycoreutils to avoid user removing them during package lifetime * Wed Oct 17 2012 Martin Kosek - 2.99.0-51 - Print ipa-upgradeconfig errors during RPM update * Wed Oct 10 2012 Alexander Bokovoy - 2.99.0-50 - Make sure server-trust-ad subpackage alternates winbind_krb5_locator.so plugin to /dev/null since they cannot be used when trusts are configured * Wed Oct 10 2012 Petr Viktorin - 2.99.0-49 - Add zip dependency, needed for creating unsigned Firefox extensions * Mon Oct 8 2012 Martin Kosek - 2.99.0-48 - Add directory /var/lib/ipa/pki-ca/publish for CRL published by pki-ca * Mon Oct 1 2012 Martin Kosek - 2.99.0-47 - Require samba packages instead of samba4 packages obsoleted in Fedora 18 and later - Add libwbclient-devel BuildRequires to pick up libwbclient.h on Fedora 18 and later * Tue Sep 18 2012 Petr Viktorin - 2.99.0-46 - Set certmonger minimum version to 0.60 for Dogtag 10 support. * Mon Sep 17 2012 Rob Crittenden - 2.99.0-45 - Set min for 389-ds-base to 1.2.11.14-1 on F17+ to pull in updated RUV code and nsslapd-readonly schema. * Fri Sep 14 2012 Sumit Bose - 2.99.0-44 - Updated samba4-devel dependency due to API change * Mon Aug 20 2012 Rob Crittenden - 2.99.0-43 - Set min for 389-ds-base to 1.2.11.9-1 on F17+ to pull in warning about low nsslapd-cachememsize. * Mon Aug 20 2012 Tomas Babej - 2.99.0-42 - Add samba4-winbind to build dependencies for AD server-side code * Fri Aug 17 2012 Martin Kosek - 2.99.0-41 - Set min for bind-dyndb-ldap to 1.1.0-0.16.rc1 to pick up complete zone transfer support * Thu Aug 2 2012 Martin Kosek - 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 - 2.99.0-39 - Set minimum certmonger to 0.58 for dogtag cert renewal * Wed Jul 18 2012 Alexander Bokovoy - 2.99.0-38 - Require samba4-devel >= 4.0.0-128 due to passdb API change in beta4 * Fri Jun 29 2012 Rob Crittenden - 2.99.0-37 - Add Requires on openssl - Set minimum tomcat6 to 6.0.35-4 in F-18 - Set minimum mod_auth_kerb to 5.4-16 in F-18 * Thu Jun 21 2012 Sumit Bose - 2.99.0-36 - Add extdom extop plugin * Thu Jun 21 2012 Rob Crittenden - 2.99.0-35 - Add client requires on libsss-autofs, autofs, libnfsidmap and nfs-utils for configuring automount and NFS. * Thu Jun 21 2012 Petr Vobornik - 2.99.0-34 - Add Web UI reset password pages * Wed Jun 20 2012 Ondrej Hamada - 2.99.0-33 - Set min for 389-ds-base to 1.2.11.5-1 on F17 to fix installation issue - Set min for 389-ds-base to 1.2.10.10-1 on F16 (and lower) to fix CN case persistence * Fri Jun 8 2012 Martin Kosek - 2.99.0-32 - Add directory /var/lib/ipa/sysupgrade for package upgrade metadata - Set min for bind-dyndb-ldap to 1.1.0-0.12.rc1 to pick up persistent search related bug fixes * Mon Jun 4 2012 Alexander Bokovoy - 2.99.0-31 - Add python-crypto to build dependencies for AD server-side code * Tue May 29 2012 Alexander Bokovoy - 2.99.0-30 - Add freeipa-server-trust-ad virtual package to capture all required dependencies for Active Directory trust management * Fri May 11 2012 Martin Kosek - 2.99.0-29 - Replace used DNS client library (acutil) with python-dns * Tue Apr 10 2012 Rob Crittenden - 2.99.0-28 - Set min for selinux-policy to 3.10.0-110 on F-17 to pick up certmonger policy for restarting services. - Set min for certmonger to 0.53 so we have the -C option to set restart commands. * Thu Apr 5 2012 Rob Crittenden - 2.99.0-27 - Bump minimum version of slapi-nis to 0.40 * Tue Mar 27 2012 Rob Crittenden - 2.99.0-26 - Add python-krbV Requires on client package * Mon Mar 26 2012 Rob Crittenden - 2.99.0-25 - Set min for 389-ds-base to 1.2.10.4-2 to fix upgrade issue * Fri Mar 23 2012 Petr Viktorin - 2.99.0-24 - Add python-lxml and python-pyasn1 to BuildRequires * Mon Mar 19 2012 Martin Kosek - 2.99.0-23 - Set min for bind-dyndb-ldap and bind to pick up new features and bug fixes * Thu Mar 1 2012 Jan Cholasta - 2.99.0-22 - Set min nvr of sssd to 1.8.0 for SSH support - Add BuildRequires on sssd >= 1.8.0 * Wed Feb 29 2012 Petr Vobornik - 2.99.0-21 - Add Web UI form based login page - Removed ipa_migration.css * Wed Feb 29 2012 Petr Vobornik - 2.99.0-20 - Add Web UI logout page * Mon Feb 27 2012 Rob Crittenden - 2.99.0-19 - Add Requires to ipa-client on oddjob-mkhomedir * Fri Feb 24 2012 Martin Kosek - 2.99.0-18 - Set min for bind-dyndb-ldap to 1.1.0-0.8.a2 to pick up new features * Thu Feb 23 2012 Rob Crittenden - 2.99.0-17 - Add Conflicts on mod_ssl * Thu Feb 16 2012 Rob Crittenden - 2.99.0-16 - Set min for 389-ds-base to 1.2.10.1-1 to fix install segfault, schema replication. * Tue Jan 31 2012 Rob Crittenden - 2.99.0-15 - Set min for krb5-server to 1.9.2-6 to pick up needed s4u2proxy patches * Wed Jan 11 2012 Rob Crittenden - 2.99.0-14 - Set min for mod_auth_kerb to 5.4-8 to pick up s4u2proxy support * Fri Dec 9 2011 Alexander Bokovoy - 2.99.0-13 - Fix dependency for samba4-devel package * Thu Nov 17 2011 Simo Sorce - 2.99.0-12 - Add CLDAP plugin - Set min nvr of 389-ds-base to 1.2.10-0.5.a5 for SLAPI_PLUGIN_CONFIG_ENTRY support * Mon Nov 14 2011 Endi S. Dewata - 2.99.0-11 - Make sure changes to extension.js are not removed. * Wed Oct 26 2011 Endi S. Dewata - 2.99.0-10 - Moved UI images into install/ui/images * Mon Oct 24 2011 Endi S. Dewata - 2.99.0-9 - Removed hbac-deny-remove.html * Fri Oct 21 2011 Alexander Bokovoy - 2.99.0-8 - Default to systemd for Fedora 16 and onwards * Fri Oct 14 2011 Rob Crittenden - 2.99.0-7 - Set min nvr of 389-ds-base to 1.2.10-0.4.a4 for limits fixes (740942, 742324) * Fri Oct 7 2011 Adam Young - 2.99.0-6 - Add explicit dependency on pki-setup. * Tue Sep 13 2011 Alexander Bokovoy - 2.99.0-5 - Make sure platform adaptation is packaged in -python sub-package * Fri Sep 9 2011 Martin Kosek - 2.99.0-4 - Add soft dependency for bind and bind-dyndb-ldap required versions * Wed Aug 31 2011 Rob Crittenden - 2.99.0-3 - Set min nvr of 389-ds-base to 1.2.9.7-1 for BZ 728605 * Mon Aug 29 2011 Rob Crittenden - 2.99.0-2 - Set min nvr of pki-ca to 9.0.12 for fix in BZ 700505 * Thu Aug 25 2011 Simo Sorce - 2.99.0-1 - Remove ipa_kpasswd. * Tue Aug 23 2011 Jan Cholasta - 2.1.0-1 - Add subscription-manager dependency for RHEL. * Thu Aug 11 2011 Martin Kosek - 2.0.90-12 - Set min nvr of 389-ds-base to 1.2.9.6 for fix in BZ 725743, 723937, and 725542 - Set min nvr of pki-ca to 9.0.11 for fix in BZ 728332 * Thu Aug 11 2011 Martin Kosek - 2.0.90-11 - Set min nvr of xmlrpc-c and libcurl to make sure GSSAPI delegation support is in * Tue Aug 2 2011 Endi S. Dewata - 2.0.90-10 - Add *.ico files * Fri Jul 29 2011 Alexander Bokovoy - 2.0.90-9 - Add libipa_hbac-python dependency for hbactest plugin * Thu Jul 28 2011 Rob Crittenden - 2.0.90-8 - Set min nvr of pki-ca to 9.0.10 on F-15+ to pick up updated caIPAserviceCert.cfg profile * Wed Jul 20 2011 Rob Crittenden - 2.0.90-7 - Make cyrus-sasl-gssapi requires arch-specific * Thu Jul 14 2011 Rob Crittenden - 2.0.90-6 - Add ipa-csreplica-manage tool. * Wed Jul 6 2011 Adam Young - 2.0.90-5 - Add HTML file describing issues with HBAC deny rules * Fri Jun 17 2011 Rob Crittenden - 2.0.90-4 - Ship ipa-ca-install utility * Thu May 12 2011 Rob Crittenden - 2.0.90-3 - Set min nvr of selinux-policy to 3.9.16-18 on F-15+ - Set min nvr of pki-ca to 9.0.7 on F-15+ * Thu May 5 2011 Martin Kosek - 2.0.90-2 - Add BuildRequires on pylint, python-rhsm to enable a build with enforced pylint check * Tue May 3 2011 Rob Crittenden - 2.0.90-1 - Bump version to 2.0.90 * Tue Apr 5 2011 Rob Crittenden - 1.99-47 - Set min version of 389-ds-base to 1.2.8.0-1 for fix in BZ 693466. * Thu Mar 17 2011 Rob Crittenden - 1.99-46 - Automatically apply updates when the package is upgraded. * Thu Feb 17 2011 Jakub Hrozek - 1.99-45 - Set minimum version of python-nss to 0.11 to make sure IPv6 support is in * Wed Feb 9 2011 Rob Crittenden - 1.99-44 - Set minimum version of sssd to 1.5.1 * Wed Feb 2 2011 Rob Crittenden - 1.99-43 - Set min version of 389-ds-base to 1.2.8 - Set min version of mod_nss 1.0.8-10 - Set min version of selinux-policy to 3.9.7-27 * Thu Jan 27 2011 Rob Crittenden - 1.99-42 - Apply changes discovered in Fedora package review process (#672986) * Tue Jan 25 2011 Rob Crittenden - 1.99-41 - Re-arrange doc and defattr to clean up rpmlint warnings - Remove conditionals on older releases - Move some man pages into admintools subpackage - Remove some explicit Requires in client that aren't needed - Consistent use of buildroot vs RPM_BUILD_ROOT * Wed Jan 19 2011 Adam Young - 1.99-40 - Moved directory install/static to install/ui * Thu Jan 13 2011 Simo Sorce - 1.99-39 - Remove dependency on nss_ldap/nss-pam-ldapd - The official client is sssd and that's what we use by default. * Thu Jan 13 2011 Simo Sorce - 1.99-38 - Remove radius subpackages * Thu Jan 13 2011 Rob Crittenden - 1.99-37 - Set minimum pki-ca and pki-silent versions to 9.0.0 * Wed Jan 12 2011 Rob Crittenden - 1.99-36 - Drop BuildRequires on mozldap-devel * Mon Dec 13 2010 Rob Crittenden - 1.99-35 - Add Requires on krb5-pkinit-openssl * Fri Dec 10 2010 Jr Aquino - 1.99-34 - Add ipa-host-net-manage script * Tue Dec 7 2010 Simo Sorce - 1.99-33 - Add ipa init script * Fri Nov 19 2010 Rob Crittenden - 1.99-32 - Set minimum level of 389-ds-base to 1.2.7 for enhanced memberof plugin * Wed Nov 3 2010 Rob Crittenden - 1.99-31 - remove ipa-fix-CVE-2008-3274 * Wed Oct 6 2010 Rob Crittenden - 1.99-30 - Remove duplicate %%files entries on share/ipa/static - Add python default encoding shared library * Mon Sep 20 2010 Rob Crittenden - 1.99-29 - Drop requires on python-configobj (not used any more) - Drop ipa-ldap-updater message, upgrades are done differently now * Wed Sep 8 2010 Rob Crittenden - 1.99-28 - Drop conflicts on mod_nss - Require nss-pam-ldapd on F-14 or higher instead of nss_ldap (#606847) - Drop a slew of conditionals on older Fedora releases (< 12) - Add a few conditionals against RHEL 6 - Add Requires of nss-tools on ipa-client * Fri Aug 13 2010 Rob Crittenden - 1.99-27 - Set minimum version of certmonger to 0.26 (to pck up #621670) - Set minimum version of pki-silent to 1.3.4 (adds -key_algorithm) - Set minimum version of pki-ca to 1.3.6 - Set minimum version of sssd to 1.2.1 * Tue Aug 10 2010 Rob Crittenden - 1.99-26 - Add BuildRequires for authconfig * Mon Jul 19 2010 Rob Crittenden - 1.99-25 - Bump up minimum version of python-nss to pick up nss_is_initialize() API * Thu Jun 24 2010 Adam Young - 1.99-24 - Removed python-asset based webui * Thu Jun 24 2010 Rob Crittenden - 1.99-23 - Change Requires from fedora-ds-base to 389-ds-base - Set minimum level of 389-ds-base to 1.2.6 for the replication version plugin. * Tue Jun 1 2010 Rob Crittenden - 1.99-22 - Drop Requires of python-krbV on ipa-client * Mon May 17 2010 Rob Crittenden - 1.99-21 - Load ipa_dogtag.pp in post install * Mon Apr 26 2010 Rob Crittenden - 1.99-20 - Set minimum level of sssd to 1.1.1 to pull in required hbac fixes. * Thu Mar 4 2010 Rob Crittenden - 1.99-19 - No need to create /var/log/ipa_error.log since we aren't using TurboGears any more. * Mon Mar 1 2010 Jason Gerard DeRose - 1.99-18 - Fixed share/ipa/wsgi.py so .pyc, .pyo files are included * Wed Feb 24 2010 Jason Gerard DeRose - 1.99-17 - Added Require mod_wsgi, added share/ipa/wsgi.py * Thu Feb 11 2010 Jason Gerard DeRose - 1.99-16 - Require python-wehjit >= 0.2.2 * Wed Feb 3 2010 Rob Crittenden - 1.99-15 - Add sssd and certmonger as a Requires on ipa-client * Wed Jan 27 2010 Jason Gerard DeRose - 1.99-14 - Require python-wehjit >= 0.2.0 * Fri Dec 4 2009 Rob Crittenden - 1.99-13 - Add ipa-rmkeytab tool * Tue Dec 1 2009 Rob Crittenden - 1.99-12 - Set minimum of python-pyasn1 to 0.0.9a so we have support for the ASN.1 Any type * Wed Nov 25 2009 Rob Crittenden - 1.99-11 - Remove v1-style /etc/ipa/ipa.conf, replacing with /etc/ipa/default.conf * Fri Nov 13 2009 Rob Crittenden - 1.99-10 - Add bash completion script and own /etc/bash_completion.d in case it doesn't already exist * Tue Nov 3 2009 Rob Crittenden - 1.99-9 - Remove ipa_webgui, its functions rolled into ipa_httpd * Mon Oct 12 2009 Jason Gerard DeRose - 1.99-8 - Removed python-cherrypy from BuildRequires and Requires - Added Requires python-assets, python-wehjit * Mon Aug 24 2009 Rob Crittenden - 1.99-7 - Added httpd SELinux policy so CRLs can be read * Thu May 21 2009 Rob Crittenden - 1.99-6 - Move ipalib to ipa-python subpackage - Bump minimum version of slapi-nis to 0.15 * Wed May 6 2009 Rob Crittenden - 1.99-5 - Set 0.14 as minimum version for slapi-nis * Wed Apr 22 2009 Rob Crittenden - 1.99-4 - Add Requires: python-nss to ipa-python sub-package * Thu Mar 5 2009 Rob Crittenden - 1.99-3 - Remove the IPA DNA plugin, use the DS one * Wed Mar 4 2009 Rob Crittenden - 1.99-2 - Build radius separately - Fix a few minor issues * Tue Feb 3 2009 Rob Crittenden - 1.99-1 - Replace TurboGears requirement with python-cherrypy * Sat Jan 17 2009 Tomas Mraz - 1.2.1-3 - rebuild with new openssl * Fri Dec 19 2008 Dan Walsh - 1.2.1-2 - Fix SELinux code * Mon Dec 15 2008 Simo Sorce - 1.2.1-1 - Fix breakage caused by python-kerberos update to 1.1 * Fri Dec 5 2008 Simo Sorce - 1.2.1-0 - New upstream release 1.2.1 * Sat Nov 29 2008 Ignacio Vazquez-Abrams - 1.2.0-4 - Rebuild for Python 2.6 * Fri Nov 14 2008 Simo Sorce - 1.2.0-3 - Respin after the tarball has been re-released upstream New hash is 506c9c92dcaf9f227cba5030e999f177 * Thu Nov 13 2008 Simo Sorce - 1.2.0-2 - Conditionally restart also dirsrv and httpd when upgrading * Wed Oct 29 2008 Rob Crittenden - 1.2.0-1 - Update to upstream version 1.2.0 - Set fedora-ds-base minimum version to 1.1.3 for winsync header - Set the minimum version for SELinux policy - Remove references to Fedora 7 * Wed Jul 23 2008 Simo Sorce - 1.1.0-3 - Fix for CVE-2008-3274 - Fix segfault in ipa-kpasswd in case getifaddrs returns a NULL interface - Add fix for bug #453185 - Rebuild against openldap libraries, mozldap ones do not work properly - TurboGears is currently broken in rawhide. Added patch to not build the UI locales and removed them from the ipa-server files section. * Wed Jun 18 2008 Rob Crittenden - 1.1.0-2 - Add call to /usr/sbin/upgradeconfig to post install * Wed Jun 11 2008 Rob Crittenden - 1.1.0-1 - Update to upstream version 1.1.0 - Patch for indexing memberof attribute - Patch for indexing uidnumber and gidnumber - Patch to change DNA default values for replicas - Patch to fix uninitialized variable in ipa-getkeytab * Fri May 16 2008 Rob Crittenden - 1.0.0-5 - Set fedora-ds-base minimum version to 1.1.0.1-4 and mod_nss minimum version to 1.0.7-4 so we pick up the NSS fixes. - Add selinux-policy-base(post) to Requires (446496) * Tue Apr 29 2008 Rob Crittenden - 1.0.0-4 - Add missing entry for /var/cache/ipa/kpasswd (444624) - Added patch to fix permissions problems with the Apache NSS database. - Added patch to fix problem with DNS querying where the query could be returned as the answer. - Fix spec error where patch1 was in the wrong section * Fri Apr 25 2008 Rob Crittenden - 1.0.0-3 - Added patch to fix problem reported by ldapmodify * Fri Apr 25 2008 Rob Crittenden - 1.0.0-2 - Fix Requires for krb5-server that was missing for Fedora versions > 9 - Remove quotes around test for fedora version to package egg-info * Fri Apr 18 2008 Rob Crittenden - 1.0.0-1 - Update to upstream version 1.0.0 * Tue Mar 18 2008 Rob Crittenden 0.99-12 - Pull upstream changelog 722 - Add Conflicts mod_ssl (435360) * Fri Feb 29 2008 Rob Crittenden 0.99-11 - Pull upstream changelog 698 - Fix ownership of /var/log/ipa_error.log during install (435119) - Add pwpolicy command and man page * Thu Feb 21 2008 Rob Crittenden 0.99-10 - Pull upstream changelog 678 - Add new subpackage, ipa-server-selinux - Add Requires: authconfig to ipa-python (bz #433747) - Package i18n files * Mon Feb 18 2008 Rob Crittenden 0.99-9 - Pull upstream changelog 641 - Require minimum version of krb5-server on F-7 and F-8 - Package some new files * Thu Jan 31 2008 Rob Crittenden 0.99-8 - Marked with wrong license. IPA is GPLv2. * Tue Jan 29 2008 Rob Crittenden 0.99-7 - Ensure that /etc/ipa exists before moving user-modifiable html files there - Put html files into /etc/ipa/html instead of /etc/ipa * Tue Jan 29 2008 Rob Crittenden 0.99-6 - Pull upstream changelog 608 which renamed several files * Thu Jan 24 2008 Rob Crittenden 0.99-5 - package the sessions dir /var/cache/ipa/sessions - Pull upstream changelog 597 * Thu Jan 24 2008 Rob Crittenden 0.99-4 - Updated upstream pull (596) to fix bug in ipa_webgui that was causing the UI to not start. * Thu Jan 24 2008 Rob Crittenden 0.99-3 - Included LICENSE and README in all packages for documentation - Move user-modifiable content to /etc/ipa and linked back to /usr/share/ipa/html - Changed some references to /usr to the {_usr} macro and /etc to {_sysconfdir} - Added popt-devel to BuildRequires for Fedora 8 and higher and popt for Fedora 7 - Package the egg-info for Fedora 9 and higher for ipa-python * Tue Jan 22 2008 Rob Crittenden 0.99-2 - Added auto* BuildRequires * Mon Jan 21 2008 Rob Crittenden 0.99-1 - Unified spec file * Thu Jan 17 2008 Rob Crittenden - 0.6.0-2 - Fixed License in specfile - Include files from /usr/lib/python*/site-packages/ipaserver * Fri Dec 21 2007 Karl MacMillan - 0.6.0-1 - Version bump for release * Wed Nov 21 2007 Karl MacMillan - 0.5.0-1 - Preverse mode on ipa-keytab-util - Version bump for relase and rpm name change * Thu Nov 15 2007 Rob Crittenden - 0.4.1-2 - Broke invididual Requires and BuildRequires onto separate lines and reordered them - Added python-tgexpandingformwidget as a dependency - Require at least fedora-ds-base 1.1 * Thu Nov 1 2007 Karl MacMillan - 0.4.1-1 - Version bump for release * Wed Oct 31 2007 Karl MacMillan - 0.4.0-6 - Add dep for freeipa-admintools and acl * Wed Oct 24 2007 Rob Crittenden - 0.4.0-5 - Add dependency for python-krbV * Fri Oct 19 2007 Rob Crittenden - 0.4.0-4 - Require mod_nss-1.0.7-2 for mod_proxy fixes * Thu Oct 18 2007 Karl MacMillan - 0.4.0-3 - Convert to autotools-based build * Tue Sep 25 2007 Karl MacMillan - 0.4.0-2 * Fri Sep 7 2007 Karl MacMillan - 0.3.0-1 - Added support for libipa-dna-plugin * Fri Aug 10 2007 Karl MacMillan - 0.2.0-1 - Added support for ipa_kpasswd and ipa_pwd_extop * Sun Aug 5 2007 Rob Crittenden - 0.1.0-3 - Abstracted client class to work directly or over RPC * Wed Aug 1 2007 Rob Crittenden - 0.1.0-2 - Add mod_auth_kerb and cyrus-sasl-gssapi to Requires - Remove references to admin server in ipa-server-setupssl - Generate a client certificate for the XML-RPC server to connect to LDAP with - Create a keytab for Apache - Create an ldif with a test user - Provide a certmap.conf for doing SSL client authentication * Fri Jul 27 2007 Karl MacMillan - 0.1.0-1 - Initial rpm version freeipa-3.3.4/VERSION0000664000175000017500000001066612271707517013574 0ustar mkosekmkosek######################################################## # freeIPA Version # # # # freeIPA versions are as follows # # 1.0.x New production series # # 1.0.x{pre,beta,rc}y Preview/Testing, Beta & RC # # 1.0.0GITabcdefg Build from GIT # # # ######################################################## ######################################################## # This are the main version numbers # # # # .. # # # # e.g. IPA_VERSION_MAJOR=1 # # IPA_VERSION_MINOR=0 # # IPA_VERSION_RELEASE=0 # # -> "1.0.0" # ######################################################## IPA_VERSION_MAJOR=3 IPA_VERSION_MINOR=3 IPA_VERSION_RELEASE=4 ######################################################## # For 'pre' releases the version will be # # # # ..pre # # # # e.g. IPA_VERSION_PRE_RELEASE=1 # # -> "1.0.0pre1" # ######################################################## IPA_VERSION_PRE_RELEASE= ######################################################## # For 'beta' releases the version will be # # # # ..beta # # # # e.g. IPA_VERSION_BETA_RELEASE=1 # # -> "1.0.0beta1" # ######################################################## IPA_VERSION_BETA_RELEASE= ######################################################## # For 'rc' releases the version will be # # # # ..rc # # # # e.g. IPA_VERSION_RC_RELEASE=1 # # -> "1.0.0rc1" # ######################################################## IPA_VERSION_RC_RELEASE= ######################################################## # To mark GIT snapshots this should be set to 'yes' # # in the development BRANCH, and set to 'no' only in # # the IPA_X_X_RELEASE BRANCH # # # # ..GITxxx # # # # e.g. IPA_VERSION_IS_SVN_SNAPSHOT=yes # # -> "1.0.0GITabcdefg" # ######################################################## IPA_VERSION_IS_GIT_SNAPSHOT="yes" ######################################################## # The version of IPA data. This is used to identify # # incompatibilities in data that could cause issues # # with replication. If the built-in versions don't # # match exactly then replication will fail. # # # # The format is %Y%m%d%H%M%S # # # # e.g. IPA_DATA_VERSION=`date +%Y%m%d%H%M%S` # # -> "20100614120000" # ######################################################## IPA_DATA_VERSION=20100614120000 ######################################################## # The version of the IPA API. This controls which # # client versions can use the XML-RPC and json APIs # # # # A change to existing API requires a MAJOR version # # update. The addition of new API bumps the MINOR # # version. # # # # The format is a whole number # # # ######################################################## IPA_API_VERSION_MAJOR=2 IPA_API_VERSION_MINOR=65 freeipa-3.3.4/make-test0000775000175000017500000000205312271663206014327 0ustar mkosekmkosek#!/usr/bin/python """ Run IPA unit tests under multiple versions of Python (if present). """ import sys import optparse import os from os import path from subprocess import call versions = ('2.4', '2.5', '2.6', '2.7') python = '/usr/bin/python' nose = '/usr/bin/nosetests' ran = [] fail = [] cmd = [ nose, '-v', '--with-doctest', '--doctest-tests', '--exclude=plugins', ] cmd += sys.argv[1:] # This must be set so ipalib.api gets initialized property for tests: os.environ['IPA_UNIT_TEST_MODE'] = 'cli_test' if not path.isfile(nose): print 'ERROR: need %r' % nose sys.exit(100) for v in versions: pver = python + v if not path.isfile(pver): continue command = [pver] + cmd print ' '.join(cmd) if 0 != call(cmd): fail.append(pver) ran.append(pver) print '=' * 70 for pver in ran: if pver in fail: print 'FAILED under %r' % pver else: print 'passed under %r' % pver print '' if fail: print '** FAIL **' sys.exit(1) else: print '** pass **' sys.exit(0) freeipa-3.3.4/lite-server.py0000775000175000017500000001031312270466515015326 0ustar mkosekmkosek#!/usr/bin/python # Authors: # Jason Gerard DeRose # # 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 . """ In-tree paste-based test server. This uses the *Python Paste* WSGI server. For more info, see: http://pythonpaste.org/ Unfortunately, SSL support is broken under Python 2.6 with paste 1.7.2, see: http://trac.pythonpaste.org/pythonpaste/ticket/314 """ from os import path, getcwd import optparse from paste import httpserver import paste.gzipper from paste.urlmap import URLMap from ipalib import api class KRBCheater(object): def __init__(self, app): self.app = app self.url = app.url self.ccname = api.Backend.krb.default_ccname() def __call__(self, environ, start_response): environ['KRB5CCNAME'] = self.ccname return self.app(environ, start_response) class WebUIApp(object): INDEX_FILE = 'index.html' EXTENSION_TO_MIME_MAP = { 'xhtml': 'text/html', 'html': 'text/html', 'js': 'text/javascript', 'inc': 'text/html', 'css': 'text/css', 'png': 'image/png', 'json': 'text/javascript', } def __init__(self): self.url = '/ipa/ui' def __call__(self, environ, start_response): path_info = environ['PATH_INFO'].lstrip('/') if path_info == '': path_info = self.INDEX_FILE requested_file = path.join(getcwd(), 'install/ui/', path_info) extension = requested_file.rsplit('.', 1)[-1] if extension not in self.EXTENSION_TO_MIME_MAP: start_response('404 Not Found', [('Content-Type', 'text/plain')]) return ['NOT FOUND'] mime_type = self.EXTENSION_TO_MIME_MAP[extension] f = None try: f = open(requested_file, 'r') api.log.info('Request file %s' % requested_file) start_response('200 OK', [('Content-Type', mime_type)]) return [f.read()] except IOError: start_response('404 Not Found', [('Content-Type', 'text/plain')]) return ['NOT FOUND'] finally: if f is not None: f.close() api.log.info('Request done') if __name__ == '__main__': parser = optparse.OptionParser() parser.add_option('--dev', help='Run WebUI in development mode (requires FireBug)', default=True, action='store_false', dest='prod', ) parser.add_option('--host', help='Listen on address HOST (default 127.0.0.1)', default='127.0.0.1', ) parser.add_option('--port', help='Listen on PORT (default 8888)', default=8888, type='int', ) api.env.in_server = True api.env.startup_traceback = True (options, args) = api.bootstrap_with_global_options(parser, context='lite') api.env._merge( lite_port=options.port, lite_host=options.host, webui_prod=options.prod, lite_pem=api.env._join('dot_ipa', 'lite.pem'), ) api.finalize() urlmap = URLMap() apps = [ ('IPA', KRBCheater(api.Backend.wsgi_dispatch)), ('webUI', KRBCheater(WebUIApp())), ] for (name, app) in apps: urlmap[app.url] = app api.log.info('Mounting %s at %s', name, app.url) if path.isfile(api.env.lite_pem): pem = api.env.lite_pem else: api.log.info('To enable SSL, place PEM file at %r', api.env.lite_pem) pem = None httpserver.serve(paste.gzipper.middleware(urlmap), host=api.env.lite_host, port=api.env.lite_port, ssl_pem=pem, ) freeipa-3.3.4/ipalib/0000775000175000017500000000000012271707517013753 5ustar mkosekmkosekfreeipa-3.3.4/ipalib/config.pyc0000664000175000017500000004704412271707517015746 0ustar mkosekmkosekó MmâRc@sÐdZddlmZmZddlmZddlZddlmZddlZddl m Z ddl m Z ddl mZdd lmZdd lmZmZmZmZd efd „ƒYZdS( sp Process-wide static configuration and environment. The standard run-time instance of the `Env` class is initialized early in the `ipalib` process and is then locked into a read-only state, after which no further changes can be made to the environment throughout the remaining life of the process. For the per-request thread-local information, see `ipalib.request`. iÿÿÿÿ(tRawConfigParsert ParsingError(tNoneTypeN(tpath(tgetfqdn(tDN(t check_name(tCONFIG_SECTION(t TYPE_ERRORtOVERRIDE_ERRORt SET_ERRORt DEL_ERRORtEnvcBs¿eZdZeZd„Zd„Zd„Zd„Zd„Z d„Z d„Z d„Z d „Z d „Zd „Zd „Zd „Zd„Zd„Zd„Zd„Zd„Zd„ZRS(s• Store and retrieve environment variables. First an foremost, the `Env` class provides a handy container for environment variables. These variables can be both set *and* retrieved either as attributes *or* as dictionary items. For example, you can set a variable as an attribute: >>> env = Env() >>> env.attr = 'I was set as an attribute.' >>> env.attr u'I was set as an attribute.' >>> env['attr'] # Also retrieve as a dictionary item u'I was set as an attribute.' Or you can set a variable as a dictionary item: >>> env['item'] = 'I was set as a dictionary item.' >>> env['item'] u'I was set as a dictionary item.' >>> env.item # Also retrieve as an attribute u'I was set as a dictionary item.' The variable names must be valid lower-case Python identifiers that neither start nor end with an underscore. If your variable name doesn't meet these criteria, a ``ValueError`` will be raised when you try to set the variable (compliments of the `base.check_name()` function). For example: >>> env.BadName = 'Wont work as an attribute' Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'BadName' >>> env['BadName'] = 'Also wont work as a dictionary item' Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'BadName' The variable values can be ``str``, ``int``, or ``float`` instances, or the ``True``, ``False``, or ``None`` constants. When the value provided is an ``str`` instance, some limited automatic type conversion is performed, which allows values of specific types to be set easily from configuration files or command-line options. So in addition to their actual values, the ``True``, ``False``, and ``None`` constants can be specified with an ``str`` equal to what ``repr()`` would return. For example: >>> env.true = True >>> env.also_true = 'True' # Equal to repr(True) >>> env.true True >>> env.also_true True Note that the automatic type conversion is case sensitive. For example: >>> env.not_false = 'false' # Not equal to repr(False)! >>> env.not_false u'false' If an ``str`` value looks like an integer, it's automatically converted to the ``int`` type. Likewise, if an ``str`` value looks like a floating-point number, it's automatically converted to the ``float`` type. For example: >>> env.lucky = '7' >>> env.lucky 7 >>> env.three_halves = '1.5' >>> env.three_halves 1.5 Leading and trailing white-space is automatically stripped from ``str`` values. For example: >>> env.message = ' Hello! ' # Surrounded by double spaces >>> env.message u'Hello!' >>> env.number = ' 42 ' # Still converted to an int >>> env.number 42 >>> env.false = ' False ' # Still equal to repr(False) >>> env.false False Also, empty ``str`` instances are converted to ``None``. For example: >>> env.empty = '' >>> env.empty is None True `Env` variables are all set-once (first-one-wins). Once a variable has been set, trying to override it will raise an ``AttributeError``. For example: >>> env.date = 'First' >>> env.date = 'Second' Traceback (most recent call last): ... AttributeError: cannot override Env.date value u'First' with 'Second' An `Env` instance can be *locked*, after which no further variables can be set. Trying to set variables on a locked `Env` instance will also raise an ``AttributeError``. For example: >>> env = Env() >>> env.okay = 'This will work.' >>> env.__lock__() >>> env.nope = 'This wont work!' Traceback (most recent call last): ... AttributeError: locked: cannot set Env.nope to 'This wont work!' `Env` instances also provide standard container emulation for membership testing, counting, and iteration. For example: >>> env = Env() >>> 'key1' in env # Has key1 been set? False >>> env.key1 = 'value 1' >>> 'key1' in env True >>> env.key2 = 'value 2' >>> len(env) # How many variables have been set? 2 >>> list(env) # What variables have been set? ['key1', 'key2'] Lastly, in addition to all the handy container functionality, the `Env` class provides high-level methods for bootstraping a fresh `Env` instance into one containing all the run-time and configuration information needed by the built-in freeIPA plugins. These are the `Env` bootstraping methods, in the order they must be called: 1. `Env._bootstrap()` - initialize the run-time variables and then merge-in variables specified on the command-line. 2. `Env._finalize_core()` - merge-in variables from the configuration files and then merge-in variables from the internal defaults, after which at least all the standard variables will be set. After this method is called, the plugins will be loaded, during which third-party plugins can merge-in defaults for additional variables they use (likely using the `Env._merge()` method). 3. `Env._finalize()` - one last chance to merge-in variables and then the instance is locked. After this method is called, no more environment variables can be set during the remaining life of the process. However, normally none of these three bootstraping methods are called directly and instead only `plugable.API.bootstrap()` is called, which itself takes care of correctly calling the `Env` bootstrapping methods. cKsCtj|diƒtj|dtƒƒ|r?|j|ndS(Nt_Env__dt _Env__done(tobjectt __setattr__tsett_merge(tselft initialize((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__init__ÊscCs?|jtkr(td|jjƒ‚ntj|dtƒdS(s9 Prevent further changes to environment. s%s.__lock__() already calledt _Env__lockedN(RtTruet StandardErrort __class__t__name__RR(R((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__lock__ÐscCs|jS(s, Return ``True`` if locked. (R(R((s+/home/mkosek/freeipa-clean/ipalib/config.pyt __islocked__ÚscCs|||>> env = Env() >>> env.name = 'A value' >>> del env.name Traceback (most recent call last): ... AttributeError: locked: cannot delete Env.name N(R#R RR(RR((s+/home/mkosek/freeipa-clean/ipalib/config.pyt __delattr__s cCs ||jkS(sS Return True if instance contains ``key``; otherwise return False. (R (RR3((s+/home/mkosek/freeipa-clean/ipalib/config.pyt __contains__&scCs t|jƒS(s; Return number of variables currently set. (tlenR (R((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__len__,sccs#xt|jƒD] }|VqWdS(s: Iterate through keys in ascending order. N(tsortedR (RR3((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__iter__2scKsVd}x=|jƒD]/\}}||kr|||<|d7}qqW|t|ƒfS(s Merge variables from ``kw`` into the environment. Any variables in ``kw`` that have already been set will be ignored (meaning this method will *not* try to override them, which would raise an exception). This method returns a ``(num_set, num_total)`` tuple containing first the number of variables that were actually set, and second the total number of variables that were provided. For example: >>> env = Env() >>> env._merge(one=1, two=2) (2, 2) >>> env._merge(one=1, three=3) (1, 2) >>> env._merge(one=1, two=2, three=3) (0, 3) Also see `Env._merge_from_file()`. :param kw: Variables provides as keyword arguments. ii(t iteritemsR9(RtkwtiR3R((s+/home/mkosek/freeipa-clean/ipalib/config.pyR9s   cCstj|ƒ|kr(td|ƒ‚ntj|ƒs;dStƒ}y|j|ƒWntk ridSX|jtƒs‰|j tƒn|j tƒ}t |ƒdkr®dSd}x7|D]/\}}||kr»|||<|d7}q»q»Wd|krt |d>> env = Env() >>> env._merge_from_file('my/config.conf') Traceback (most recent call last): ... ValueError: config_file must be an absolute path; got 'my/config.conf' Also see `Env._merge()`. :param config_file: Absolute path of the configuration file to load. s,config_file must be an absolute path; got %rNiit config_loaded(ii( RtabspathR/tisfileRtreadRt has_sectionRt add_sectiontitemsR9R(Rt config_filetparserRFR?R3R((s+/home/mkosek/freeipa-clean/ipalib/config.pyt_merge_from_fileZs.      cGs4||kr0||dk r0tj|||ŒSdS(s Append path components in ``parts`` to base path ``self[key]``. For example: >>> env = Env() >>> env.home = '/people/joe' >>> env._join('home', 'Music', 'favourites') u'/people/joe/Music/favourites' N(R Rtjoin(RR3tparts((s+/home/mkosek/freeipa-clean/ipalib/config.pyt_joins cCsB||jkr.td|jj|fƒ‚n|jj|ƒdS(Ns%s.%s() already called(RRRRtadd(RR((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__doingscCs&||jkr"t||ƒƒndS(N(Rtgetattr(RR((s+/home/mkosek/freeipa-clean/ipalib/config.pyt__do_if_not_done¤scCs ||jkS(N(R(RR((s+/home/mkosek/freeipa-clean/ipalib/config.pyt_isdone¨scKsô|jdƒtjtjtƒƒ|_tj|jƒ|_tjtjdƒ|_ tj|j ƒ|_ t j j ddƒ|_|j|d|krä|j |jkrØtjtj|j dƒƒrØt|_qät|_n|jrd|krd|_nd|kr)|jd d ƒ|_nd |krAd |_nd |kr€|jre|j|_q€tjdddƒ|_nd|kr«|jd d|jƒ|_nd|krÏ|jd dƒ|_nd|krð|jdk|_ndS(sˆ Initialize basic environment. This method will perform the following steps: 1. Initialize certain run-time variables. These run-time variables are strictly determined by the external environment the process is running in; they cannot be specified on the command-line nor in the configuration files. 2. Merge-in the variables in ``overrides`` by calling `Env._merge()`. The intended use of ``overrides`` is to merge-in variables specified on the command-line. 3. Intelligently fill-in the *in_tree*, *context*, *conf*, and *conf_default* variables if they haven't been set already. Also see `Env._finalize_core()`, the next method in the bootstrap sequence. :param overrides: Variables specified via command-line options. t _bootstrapitHOMEtin_treessetup.pytmodet developertdot_ipathomes.ipatcontexttdefaulttconfdirt/tetctipatconfs%s.conft conf_defaults default.conftplugins_on_demandtcliN(t _Env__doingRtdirnameRAt__file__tipalibt site_packagestsystargvtscripttbintostenvirontgetR RXRRBRJRRTRRURLRWRYR[R_R`Ra(Rt overrides((s+/home/mkosek/freeipa-clean/ipalib/config.pyRR«s8              cKs |jdƒ|jdƒ|jjddƒdkrX|j|jƒ|j|jƒnd|kry|jdk|_ nd|krÎ|j s˜|j r°|j dd ƒ|_ qÎt jd d d d ƒ|_ nd |krù|j dd |jƒ|_n|j|dS(s„ Complete initialization of standard IPA environment. This method will perform the following steps: 1. Call `Env._bootstrap()` if it hasn't already been called. 2. Merge-in variables from the configuration file ``self.conf`` (if it exists) by calling `Env._merge_from_file()`. 3. Merge-in variables from the defaults configuration file ``self.conf_default`` (if it exists) by calling `Env._merge_from_file()`. 4. Intelligently fill-in the *in_server* , *logdir*, and *log* variables if they haven't already been set. 5. Merge-in the variables in ``defaults`` by calling `Env._merge()`. In normal circumstances ``defaults`` will simply be those specified in `constants.DEFAULT_CONFIG`. After this method is called, all the environment variables used by all the built-in plugins will be available. As such, this method should be called *before* any plugins are loaded. After this method has finished, the `Env` instance is still writable so that 3rd-party plugins can set variables they may require as the plugins are registered. Also see `Env._finalize()`, the final method in the bootstrap sequence. :param defaults: Internal defaults for all built-in variables. t_finalize_coreRRRUtdummyt in_servertservertlogdirRWtlogR\tvarR^s%s.logN(Rct_Env__do_if_not_doneR RnR RIR_R`RYRrRTRLRtRRJRuR(Rtdefaults((s+/home/mkosek/freeipa-clean/ipalib/config.pyRpös"     cKs5|jdƒ|jdƒ|j||jƒdS(sV Finalize and lock environment. This method will perform the following steps: 1. Call `Env._finalize_core()` if it hasn't already been called. 2. Merge-in the variables in ``lastchance`` by calling `Env._merge()`. 3. Lock this `Env` instance, after which no more environment variables can be set on this instance. Aside from unit-tests and example code, normally only one `Env` instance is created, which means that after this step, no more variables can be set during the remaining life of the process. This method should be called after all plugins have been loaded and after `plugable.API.finalize()` has been called. :param lastchance: Any final variables to merge-in before locking. t _finalizeRpN(RcRwRR(Rt lastchance((s+/home/mkosek/freeipa-clean/ipalib/config.pyRy1s   (Rt __module__t__doc__RRRRRRR5R6R7R8R:R<RRIRLRcRwRQRRRpRy(((s+/home/mkosek/freeipa-clean/ipalib/config.pyR -s*™    '      ! 5     K ;(R|t ConfigParserRRttypesRRlRRhtsocketRt ipapython.dnRtbaseRt constantsRRR R R RR (((s+/home/mkosek/freeipa-clean/ipalib/config.pyts  "freeipa-3.3.4/ipalib/plugable.py0000664000175000017500000006336312271663206016127 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Plugin framework. The classes in this module make heavy use of Python container emulation. If you are unfamiliar with this Python feature, see http://docs.python.org/ref/sequence-types.html """ import re import sys import inspect import threading import os from os import path import subprocess import optparse import errors import textwrap from config import Env import util import text from text import _ from base import ReadOnly, NameSpace, lock, islocked, check_name from constants import DEFAULT_CONFIG from ipapython.ipa_log_manager import * # FIXME: Updated constants.TYPE_ERROR to use this clearer format from wehjit: TYPE_ERROR = '%s: need a %r; got a %r: %r' def is_production_mode(obj): """ If the object has self.env.mode defined and that mode is production return True, otherwise return False. """ if getattr(obj, 'env', None) is None: return False if getattr(obj.env, 'mode', None) is None: return False return obj.env.mode == 'production' class SetProxy(ReadOnly): """ A read-only container with set/sequence behaviour. This container acts as a proxy to an actual set-like object (a set, frozenset, or dict) that is passed to the constructor. To the extent possible in Python, this underlying set-like object cannot be modified through the SetProxy... which just means you wont do it accidentally. """ def __init__(self, s): """ :param s: The target set-like object (a set, frozenset, or dict) """ allowed = (set, frozenset, dict) if type(s) not in allowed: raise TypeError('%r not in %r' % (type(s), allowed)) self.__s = s if not is_production_mode(self): lock(self) def __len__(self): """ Return the number of items in this container. """ return len(self.__s) def __iter__(self): """ Iterate (in ascending order) through keys. """ for key in sorted(self.__s): yield key def __contains__(self, key): """ Return True if this container contains ``key``. :param key: The key to test for membership. """ return key in self.__s class DictProxy(SetProxy): """ A read-only container with mapping behaviour. This container acts as a proxy to an actual mapping object (a dict) that is passed to the constructor. To the extent possible in Python, this underlying mapping object cannot be modified through the DictProxy... which just means you wont do it accidentally. Also see `SetProxy`. """ def __init__(self, d): """ :param d: The target mapping object (a dict) """ if type(d) is not dict: raise TypeError('%r is not %r' % (type(d), dict)) self.__d = d super(DictProxy, self).__init__(d) def __getitem__(self, key): """ Return the value corresponding to ``key``. :param key: The key of the value you wish to retrieve. """ return self.__d[key] def __call__(self): """ Iterate (in ascending order by key) through values. """ for key in self: yield self.__d[key] class MagicDict(DictProxy): """ A mapping container whose values can be accessed as attributes. For example: >>> magic = MagicDict({'the_key': 'the value'}) >>> magic['the_key'] 'the value' >>> magic.the_key 'the value' This container acts as a proxy to an actual mapping object (a dict) that is passed to the constructor. To the extent possible in Python, this underlying mapping object cannot be modified through the MagicDict... which just means you wont do it accidentally. Also see `DictProxy` and `SetProxy`. """ def __getattr__(self, name): """ Return the value corresponding to ``name``. :param name: The name of the attribute you wish to retrieve. """ try: return self[name] except KeyError: raise AttributeError('no magic attribute %r' % name) class Plugin(ReadOnly): """ Base class for all plugins. """ finalize_early = True label = None def __init__(self): self.__api = None self.__finalize_called = False self.__finalized = False self.__finalize_lock = threading.RLock() cls = self.__class__ self.name = cls.__name__ self.module = cls.__module__ self.fullname = '%s.%s' % (self.module, self.name) self.bases = tuple( '%s.%s' % (b.__module__, b.__name__) for b in cls.__bases__ ) self.doc = _(cls.__doc__) if not self.doc.msg: self.summary = '<%s>' % self.fullname else: self.summary = unicode(self.doc).split('\n\n', 1)[0].strip() log_mgr.get_logger(self, True) if self.label is None: self.label = text.FixMe(self.name + '.label') if not isinstance(self.label, text.LazyText): raise TypeError( TYPE_ERROR % ( self.fullname + '.label', text.LazyText, type(self.label), self.label ) ) def __get_api(self): """ Return `API` instance passed to `set_api()`. If `set_api()` has not yet been called, None is returned. """ return self.__api api = property(__get_api) def finalize(self): """ Finalize plugin initialization. This method calls `_on_finalize()` and locks the plugin object. Subclasses should not override this method. Custom finalization is done in `_on_finalize()`. """ with self.__finalize_lock: assert self.__finalized is False if self.__finalize_called: # No recursive calls! return self.__finalize_called = True self._on_finalize() self.__finalized = True if not is_production_mode(self): lock(self) def _on_finalize(self): """ Do custom finalization. This method is called from `finalize()`. Subclasses can override this method in order to add custom finalization. """ pass def ensure_finalized(self): """ Finalize plugin initialization if it has not yet been finalized. """ with self.__finalize_lock: if not self.__finalized: self.finalize() class finalize_attr(object): """ Create a stub object for plugin attribute that isn't set until the finalization of the plugin initialization. When the stub object is accessed, it calls `ensure_finalized()` to make sure the plugin initialization is finalized. The stub object is expected to be replaced with the actual attribute value during the finalization (preferably in `_on_finalize()`), otherwise an `AttributeError` is raised. This is used to implement on-demand finalization of plugin initialization. """ __slots__ = ('name', 'value') def __init__(self, name, value=None): self.name = name self.value = value def __get__(self, obj, cls): if obj is None or obj.api is None: return self.value obj.ensure_finalized() try: return getattr(obj, self.name) except RuntimeError: # If the actual attribute value is not set in _on_finalize(), # getattr() calls __get__() again, which leads to infinite # recursion. This can happen only if the plugin is written # badly, so advise the developer about that instead of giving # them a generic "maximum recursion depth exceeded" error. raise AttributeError( "attribute '%s' of plugin '%s' was not set in finalize()" % (self.name, obj.name) ) def set_api(self, api): """ Set reference to `API` instance. """ assert self.__api is None, 'set_api() can only be called once' assert api is not None, 'set_api() argument cannot be None' self.__api = api if not isinstance(api, API): return for name in api: assert not hasattr(self, name) setattr(self, name, api[name]) for name in ('env', 'context'): if hasattr(api, name): assert not hasattr(self, name) setattr(self, name, getattr(api, name)) def call(self, executable, *args): """ Call ``executable`` with ``args`` using subprocess.call(). If the call exits with a non-zero exit status, `ipalib.errors.SubprocessError` is raised, from which you can retrieve the exit code by checking the SubprocessError.returncode attribute. This method does *not* return what ``executable`` sent to stdout... for that, use `Plugin.callread()`. """ argv = (executable,) + args self.debug('Calling %r', argv) code = subprocess.call(argv) if code != 0: raise errors.SubprocessError(returncode=code, argv=argv) def __repr__(self): """ Return 'module_name.class_name()' representation. This representation could be used to instantiate this Plugin instance given the appropriate environment. """ return '%s.%s()' % ( self.__class__.__module__, self.__class__.__name__ ) class Registrar(DictProxy): """ Collects plugin classes as they are registered. The Registrar does not instantiate plugins... it only implements the override logic and stores the plugins in a namespace per allowed base class. The plugins are instantiated when `API.finalize()` is called. """ def __init__(self, *allowed): """ :param allowed: Base classes from which plugins accepted by this Registrar must subclass. """ self.__allowed = dict((base, {}) for base in allowed) self.__registered = set() super(Registrar, self).__init__( dict(self.__base_iter()) ) def __base_iter(self): for (base, sub_d) in self.__allowed.iteritems(): if not is_production_mode(self): assert inspect.isclass(base) name = base.__name__ if not is_production_mode(self): assert not hasattr(self, name) setattr(self, name, MagicDict(sub_d)) yield (name, base) def __findbases(self, klass): """ Iterates through allowed bases that ``klass`` is a subclass of. Raises `errors.PluginSubclassError` if ``klass`` is not a subclass of any allowed base. :param klass: The plugin class to find bases for. """ if not is_production_mode(self): assert inspect.isclass(klass) found = False for (base, sub_d) in self.__allowed.iteritems(): if issubclass(klass, base): found = True yield (base, sub_d) if not found: raise errors.PluginSubclassError( plugin=klass, bases=self.__allowed.keys() ) def __call__(self, klass, override=False): """ Register the plugin ``klass``. :param klass: A subclass of `Plugin` to attempt to register. :param override: If true, override an already registered plugin. """ if not inspect.isclass(klass): raise TypeError('plugin must be a class; got %r' % klass) # Raise DuplicateError if this exact class was already registered: if klass in self.__registered: raise errors.PluginDuplicateError(plugin=klass) # Find the base class or raise SubclassError: for (base, sub_d) in self.__findbases(klass): # Check override: if klass.__name__ in sub_d: if not override: # Must use override=True to override: raise errors.PluginOverrideError( base=base.__name__, name=klass.__name__, plugin=klass, ) else: if override: # There was nothing already registered to override: raise errors.PluginMissingOverrideError( base=base.__name__, name=klass.__name__, plugin=klass, ) # The plugin is okay, add to sub_d: sub_d[klass.__name__] = klass # The plugin is okay, add to __registered: self.__registered.add(klass) class API(DictProxy): """ Dynamic API object through which `Plugin` instances are accessed. """ def __init__(self, *allowed): self.__d = dict() self.__done = set() self.register = Registrar(*allowed) self.env = Env() super(API, self).__init__(self.__d) def __doing(self, name): if name in self.__done: raise StandardError( '%s.%s() already called' % (self.__class__.__name__, name) ) self.__done.add(name) def __do_if_not_done(self, name): if name not in self.__done: getattr(self, name)() def isdone(self, name): return name in self.__done def bootstrap(self, parser=None, **overrides): """ Initialize environment variables and logging. """ self.__doing('bootstrap') self.env._bootstrap(**overrides) self.env._finalize_core(**dict(DEFAULT_CONFIG)) object.__setattr__(self, 'log_mgr', log_mgr) log = log_mgr.root_logger object.__setattr__(self, 'log', log) # If logging has already been configured somewhere else (like in the # installer), don't add handlers or change levels: if log_mgr.configure_state != 'default' or self.env.validate_api: return log_mgr.default_level = 'info' log_mgr.configure_from_env(self.env, configure_state='api') # Add stderr handler: level = 'info' if self.env.debug: level = 'debug' else: if self.env.context == 'cli': if self.env.verbose > 0: level = 'info' else: level = 'warning' if log_mgr.handlers.has_key('console'): log_mgr.remove_handler('console') log_mgr.create_log_handlers([dict(name='console', stream=sys.stderr, level=level, format=LOGGING_FORMAT_STDERR)]) if not parser: parser = self.build_global_parser() object.__setattr__(self, 'parser', parser) # Add file handler: if self.env.mode in ('dummy', 'unit_test'): return # But not if in unit-test mode if self.env.log is None: return log_dir = path.dirname(self.env.log) if not path.isdir(log_dir): try: os.makedirs(log_dir) except OSError: log.error('Could not create log_dir %r', log_dir) return level = 'info' if self.env.debug: level = 'debug' try: log_mgr.create_log_handlers([dict(name='file', filename=self.env.log, level=level, format=LOGGING_FORMAT_FILE)]) except IOError, e: log.error('Cannot open log file %r: %s', self.env.log, e) return def build_global_parser(self, parser=None, context=None): """ Add global options to an optparse.OptionParser instance. """ if parser is None: parser = optparse.OptionParser( add_help_option=False, formatter=IPAHelpFormatter(), usage='%prog [global-options] COMMAND [command-options]', description='Manage an IPA domain', epilog='\n'.join([ 'See "ipa help topics" for available help topics.', 'See "ipa help " for more information on a ' 'specific topic.', 'See "ipa help commands" for the full list of commands.', 'See "ipa --help" for more information on a ' 'specific command.', ])) parser.disable_interspersed_args() parser.add_option("-h", "--help", action="help", help='Show this help message and exit') parser.add_option('-e', dest='env', metavar='KEY=VAL', action='append', help='Set environment variable KEY to VAL', ) parser.add_option('-c', dest='conf', metavar='FILE', help='Load configuration from FILE', ) parser.add_option('-d', '--debug', action='store_true', help='Produce full debuging output', ) parser.add_option('--delegate', action='store_true', help='Delegate the TGT to the IPA server', ) parser.add_option('-v', '--verbose', action='count', help='Produce more verbose output. A second -v displays the XML-RPC request', ) if context == 'cli': parser.add_option('-a', '--prompt-all', action='store_true', help='Prompt for ALL values (even if optional)' ) parser.add_option('-n', '--no-prompt', action='store_false', dest='interactive', help='Prompt for NO values (even if required)' ) parser.add_option('-f', '--no-fallback', action='store_false', dest='fallback', help='Only use the server configured in /etc/ipa/default.conf' ) return parser def bootstrap_with_global_options(self, parser=None, context=None): parser = self.build_global_parser(parser, context) (options, args) = parser.parse_args() overrides = {} if options.env is not None: assert type(options.env) is list for item in options.env: try: (key, value) = item.split('=', 1) except ValueError: # FIXME: this should raise an IPA exception with an # error code. # --Jason, 2008-10-31 pass overrides[str(key.strip())] = value.strip() for key in ('conf', 'debug', 'verbose', 'prompt_all', 'interactive', 'fallback', 'delegate'): value = getattr(options, key, None) if value is not None: overrides[key] = value if hasattr(options, 'prod'): overrides['webui_prod'] = options.prod if context is not None: overrides['context'] = context self.bootstrap(parser, **overrides) return (options, args) def load_plugins(self): """ Load plugins from all standard locations. `API.bootstrap` will automatically be called if it hasn't been already. """ self.__doing('load_plugins') self.__do_if_not_done('bootstrap') if self.env.mode in ('dummy', 'unit_test'): return self.import_plugins('ipalib') if self.env.context in ('server', 'lite'): self.import_plugins('ipaserver') if self.env.context in ('installer', 'updates'): self.import_plugins('ipaserver/install/plugins') if self.env.context in ('advise'): self.import_plugins('ipaserver/advise/plugins') # FIXME: This method has no unit test def import_plugins(self, package): """ Import modules in ``plugins`` sub-package of ``package``. """ package = package.replace(os.path.sep, '.') subpackage = '%s.plugins' % package try: parent = __import__(package) parts = package.split('.')[1:] if parts: for part in parts: if part == 'plugins': plugins = subpackage.plugins subpackage = plugins.__name__ break subpackage = parent.__getattribute__(part) parent = subpackage else: plugins = __import__(subpackage).plugins except ImportError, e: self.log.error( 'cannot import plugins sub-package %s: %s', subpackage, e ) raise e parent_dir = path.dirname(path.abspath(parent.__file__)) plugins_dir = path.dirname(path.abspath(plugins.__file__)) if parent_dir == plugins_dir: raise errors.PluginsPackageError( name=subpackage, file=plugins.__file__ ) self.log.debug('importing all plugin modules in %r...', plugins_dir) for (name, pyfile) in util.find_modules_in_dir(plugins_dir): fullname = '%s.%s' % (subpackage, name) self.log.debug('importing plugin module %r', pyfile) try: __import__(fullname) except errors.SkipPluginModule, e: self.log.debug( 'skipping plugin module %s: %s', fullname, e.reason ) except StandardError, e: if self.env.startup_traceback: import traceback self.log.error('could not load plugin module %r\n%s', pyfile, traceback.format_exc()) raise def finalize(self): """ Finalize the registration, instantiate the plugins. `API.bootstrap` will automatically be called if it hasn't been already. """ self.__doing('finalize') self.__do_if_not_done('load_plugins') class PluginInstance(object): """ Represents a plugin instance. """ i = 0 def __init__(self, klass): self.created = self.next() self.klass = klass self.instance = klass() self.bases = [] @classmethod def next(cls): cls.i += 1 return cls.i class PluginInfo(ReadOnly): def __init__(self, p): assert isinstance(p, PluginInstance) self.created = p.created self.name = p.klass.__name__ self.module = str(p.klass.__module__) self.plugin = '%s.%s' % (self.module, self.name) self.bases = tuple(b.__name__ for b in p.bases) if not is_production_mode(self): lock(self) plugins = {} tofinalize = set() def plugin_iter(base, subclasses): for klass in subclasses: assert issubclass(klass, base) if klass not in plugins: plugins[klass] = PluginInstance(klass) p = plugins[klass] if not is_production_mode(self): assert base not in p.bases p.bases.append(base) if klass.finalize_early or not self.env.plugins_on_demand: tofinalize.add(p) yield p.instance production_mode = is_production_mode(self) for name in self.register: base = self.register[name] magic = getattr(self.register, name) namespace = NameSpace( plugin_iter(base, (magic[k] for k in magic)) ) if not production_mode: assert not ( name in self.__d or hasattr(self, name) ) self.__d[name] = namespace object.__setattr__(self, name, namespace) for p in plugins.itervalues(): p.instance.set_api(self) if not production_mode: assert p.instance.api is self for p in tofinalize: p.instance.ensure_finalized() if not production_mode: assert islocked(p.instance) is True object.__setattr__(self, '_API__finalized', True) tuple(PluginInfo(p) for p in plugins.itervalues()) object.__setattr__(self, 'plugins', tuple(PluginInfo(p) for p in plugins.itervalues()) ) class IPAHelpFormatter(optparse.IndentedHelpFormatter): def format_epilog(self, text): text_width = self.width - self.current_indent indent = " " * self.current_indent lines = text.splitlines() result = '\n'.join( textwrap.fill(line, text_width, initial_indent=indent, subsequent_indent=indent) for line in lines) return '\n%s\n' % result freeipa-3.3.4/ipalib/capabilities.py0000664000175000017500000000400312271663206016747 0ustar mkosekmkosek# Authors: # Petr Viktorin # # 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 . """List of, and utilities for working with, client capabilities by API version The API version is given in ipapython.version.API_VERSION. This module defines a dict, ``capabilities``, that maps feature names to API versions they were introduced in. """ from distutils import version VERSION_WITHOUT_CAPABILITIES = u'2.51' capabilities = dict( # messages: Server output may include an extra key, "messages", that # contains a list of warnings and other messages. # http://freeipa.org/page/V3/Messages messages=u'2.52', # optional_uid_params: Before this version, UID & GID parameter defaults # were 999, which meant "assign dynamically", so was not possible to get # a user with UID=999. With the capability, these parameters are optional # and 999 really means 999. # https://fedorahosted.org/freeipa/ticket/2886 optional_uid_params=u'2.54' ) def client_has_capability(client_version, capability): """Determine whether the client has the given capability :param capability: Name of the capability to test :param client_version: The API version string reported by the client """ version_tuple = version.LooseVersion(client_version) return version_tuple >= version.LooseVersion(capabilities[capability]) freeipa-3.3.4/ipalib/request.py0000664000175000017500000000334212202434255016005 0ustar mkosekmkosek# Authors: # Rob Crittenden # Jason Gerard DeRose # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty contextrmation # # 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 . """ Per-request thread-local data. """ import threading from base import ReadOnly, lock from constants import OVERRIDE_ERROR, CALLABLE_ERROR # Thread-local storage of most per-request information context = threading.local() class Connection(ReadOnly): """ Base class for connection objects stored on `request.context`. """ def __init__(self, conn, disconnect): self.conn = conn if not callable(disconnect): raise TypeError( CALLABLE_ERROR % ('disconnect', disconnect, type(disconnect)) ) self.disconnect = disconnect lock(self) def destroy_context(): """ Delete all attributes on thread-local `request.context`. """ # need to use .values(), 'cos value.disconnect modifies the dict for value in context.__dict__.values(): if isinstance(value, Connection): value.disconnect() context.__dict__.clear() freeipa-3.3.4/ipalib/__init__.py0000664000175000017500000010042412271663206016061 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . ''' Package containing the core library. ============================= Tutorial for Plugin Authors ============================= This tutorial will introduce you to writing plugins for freeIPA v2. It does not cover every detail, but it provides enough to get you started and is heavily cross-referenced with further documentation that (hopefully) fills in the missing details. In addition to this tutorial, the many built-in plugins in `ipalib.plugins` and `ipaserver.plugins` provide real-life examples of how to write good plugins. ---------------------------- How this tutorial is written ---------------------------- The code examples in this tutorial are presented as if entered into a Python interactive interpreter session. As such, when you create a real plugin in a source file, a few details will be different (in addition to the fact that you will never include the ``>>>`` nor ``...`` that the interpreter places at the beginning of each line of code). The tutorial examples all have this pattern: :: >>> from ipalib import Command, create_api >>> api = create_api() >>> class my_command(Command): ... pass ... >>> api.register(my_command) >>> api.finalize() In the tutorial we call `create_api()` to create an *example* instance of `plugable.API` to work with. But a real plugin will simply use ``ipalib.api``, the standard run-time instance of `plugable.API`. A real plugin will have this pattern: :: from ipalib import Command, api class my_command(Command): pass api.register(my_command) As seen above, also note that in a real plugin you will *not* call `plugable.API.finalize()`. When in doubt, look at some of the built-in plugins for guidance, like those in `ipalib.plugins`. If you don't know what the Python *interactive interpreter* is, or are confused about what this *Python* is in the first place, then you probably should start with the Python tutorial: http://docs.python.org/tutorial/index.html ------------------------------------ First steps: A simple command plugin ------------------------------------ Our first example will create the most basic command plugin possible. This command will be seen in the list of command plugins, but it wont be capable of actually doing anything yet. A command plugin simultaneously adds a new command that can be called through the command-line ``ipa`` script *and* adds a new XML-RPC method... the two are one in the same, simply invoked in different ways. A freeIPA plugin is a Python class, and when you create a plugin, you register this class itself (instead of an instance of the class). To be a command plugin, your plugin must subclass from `frontend.Command` (or from a subclass thereof). Here is our first example: >>> from ipalib import Command, create_api >>> api = create_api() >>> class my_command(Command): # Step 1, define class ... """My example plugin.""" ... >>> api.register(my_command) # Step 2, register class Notice that we are registering the ``my_command`` class itself, not an instance of ``my_command``. Until `plugable.API.finalize()` is called, your plugin class has not been instantiated nor does the ``Command`` namespace yet exist. For example: >>> hasattr(api, 'Command') False >>> api.finalize() # plugable.API.finalize() >>> hasattr(api.Command, 'my_command') True >>> api.Command.my_command.doc Gettext('My example plugin.', domain='ipa', localedir=None) Notice that your plugin instance is accessed through an attribute named ``my_command``, the same name as your plugin class name. ------------------------------ Make your command do something ------------------------------ This simplest way to make your example command plugin do something is to implement a ``run()`` method, like this: >>> class my_command(Command): ... """My example plugin with run().""" ... ... def run(self, **options): ... return dict(result='My run() method was called!') ... >>> api = create_api() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command() # Call your command {'result': 'My run() method was called!'} When `frontend.Command.__call__()` is called, it first validates any arguments and options your command plugin takes (if any) and then calls its ``run()`` method. ------------------------ Forwarding vs. execution ------------------------ However, unlike the example above, a typical command plugin will implement an ``execute()`` method instead of a ``run()`` method. Your command plugin can be loaded in two distinct contexts: 1. In a *client* context - Your command plugin is only used to validate any arguments and options it takes, and then ``self.forward()`` is called, which forwards the call over XML-RPC to an IPA server where the actual work is done. 2. In a *server* context - Your same command plugin validates any arguments and options it takes, and then ``self.execute()`` is called, which you should implement to perform whatever work your plugin does. The base `frontend.Command.run()` method simply dispatches the call to ``self.execute()`` if ``self.env.in_server`` is True, or otherwise dispatches the call to ``self.forward()``. For example, say you have a command plugin like this: >>> class my_command(Command): ... """Forwarding vs. execution.""" ... ... def forward(self, **options): ... return dict( ... result='forward(): in_server=%r' % self.env.in_server ... ) ... ... def execute(self, **options): ... return dict( ... result='execute(): in_server=%r' % self.env.in_server ... ) ... The ``options`` will contain a dict of command options. One option is added automatically: ``version``. It contains the API version of the client. In order to maintain forward compatibility, you should always specify the API version current at the time you're writing your client. If ``my_command`` is loaded in a *client* context, ``forward()`` will be called: >>> api = create_api() >>> api.env.in_server = False # run() will dispatch to forward() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'forward(): in_server=False'} On the other hand, if ``my_command`` is loaded in a *server* context, ``execute()`` will be called: >>> api = create_api() >>> api.env.in_server = True # run() will dispatch to execute() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'execute(): in_server=True'} Normally there should be no reason to override `frontend.Command.forward()`, but, as above, it can be done for demonstration purposes. In contrast, there *is* a reason you might want to override `frontend.Command.run()`: if it only makes sense to execute your command locally, if it should never be forwarded to the server. In this case, you should implement your *do-stuff* in the ``run()`` method instead of in the ``execute()`` method. For example, the ``ipa`` command line script has a ``help`` command (`ipalib.cli.help`) that is specific to the command-line-interface and should never be forwarded to the server. --------------- Backend plugins --------------- There are two types of plugins: 1. *Frontend plugins* - These are loaded in both the *client* and *server* contexts. These need to be installed with any application built atop the `ipalib` library. The built-in frontend plugins can be found in `ipalib.plugins`. The ``my_command`` example above is a frontend plugin. 2. *Backend plugins* - These are only loaded in a *server* context and only need to be installed on the IPA server. The built-in backend plugins can be found in `ipaserver.plugins`. Backend plugins should provide a set of methods that standardize how IPA interacts with some external system or library. For example, all interaction with LDAP is done through the ``ldap`` backend plugin defined in `ipaserver.plugins.b_ldap`. As a good rule of thumb, anytime you need to import some package that is not part of the Python standard library, you should probably interact with that package via a corresponding backend plugin you implement. Backend plugins are much more free-form than command plugins. Aside from a few reserved attribute names, you can define arbitrary public methods on your backend plugin. Here is a simple example: >>> from ipalib import Backend >>> class my_backend(Backend): ... """My example backend plugin.""" ... ... def do_stuff(self): ... """Part of your API.""" ... return 'Stuff got done.' ... >>> api = create_api() >>> api.register(my_backend) >>> api.finalize() >>> api.Backend.my_backend.do_stuff() 'Stuff got done.' ------------------------------- How your command should do work ------------------------------- We now return to our ``my_command`` plugin example. Plugins are separated into frontend and backend plugins so that there are not unnecessary dependencies required by an application that only uses `ipalib` and its built-in frontend plugins (and then forwards over XML-RPC for execution). But how do we avoid introducing additional dependencies? For example, the ``user_add`` command needs to talk to LDAP to add the user, yet we want to somehow load the ``user_add`` plugin on client machines without requiring the ``python-ldap`` package (Python bindings to openldap) to be installed. To answer that, we consult our golden rule: **The golden rule:** A command plugin should implement its ``execute()`` method strictly via calls to methods on one or more backend plugins. So the module containing the ``user_add`` command does not itself import the Python LDAP bindings, only the module containing the ``ldap`` backend plugin does that, and the backend plugins are only installed on the server. The ``user_add.execute()`` method, which is only called when in a server context, is implemented as a series of calls to methods on the ``ldap`` backend plugin. When `plugable.Plugin.set_api()` is called, each plugin stores a reference to the `plugable.API` instance it has been loaded into. So your plugin can access the ``my_backend`` plugin as ``self.api.Backend.my_backend``. Additionally, convenience attributes are set for each namespace, so your plugin can also access the ``my_backend`` plugin as simply ``self.Backend.my_backend``. This next example will tie everything together. First we create our backend plugin: >>> api = create_api() >>> api.env.in_server = True # We want to execute, not forward >>> class my_backend(Backend): ... """My example backend plugin.""" ... ... def do_stuff(self): ... """my_command.execute() calls this.""" ... return 'my_backend.do_stuff() indeed did do stuff!' ... >>> api.register(my_backend) Second, we have our frontend plugin, the command: >>> class my_command(Command): ... """My example command plugin.""" ... ... def execute(self, **options): ... """Implemented against Backend.my_backend""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... >>> api.register(my_command) Lastly, we call ``api.finalize()`` and see what happens when we call ``my_command()``: >>> api.finalize() >>> api.Command.my_command(version=u'2.47') {'result': 'my_backend.do_stuff() indeed did do stuff!'} When not in a server context, ``my_command.execute()`` never gets called, so it never tries to access the non-existent backend plugin at ``self.Backend.my_backend.`` To emphasize this point, here is one last example: >>> api = create_api() >>> api.env.in_server = False # We want to forward, not execute >>> class my_command(Command): ... """My example command plugin.""" ... ... def execute(self, **options): ... """Same as above.""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... ... def forward(self, **options): ... return dict(result='Just my_command.forward() getting called here.') ... >>> api.register(my_command) >>> api.finalize() Notice that the ``my_backend`` plugin has certainly not be registered: >>> hasattr(api.Backend, 'my_backend') False And yet we can call ``my_command()``: >>> api.Command.my_command() {'result': 'Just my_command.forward() getting called here.'} ---------------------------------------- Calling other commands from your command ---------------------------------------- It can be useful to have your ``execute()`` method call other command plugins. Among other things, this allows for meta-commands that conveniently call several other commands in a single operation. For example: >>> api = create_api() >>> api.env.in_server = True # We want to execute, not forward >>> class meta_command(Command): ... """My meta-command plugin.""" ... ... def execute(self, **options): ... """Calls command_1(), command_2()""" ... msg = '%s; %s.' % ( ... self.Command.command_1()['result'], ... self.Command.command_2()['result'], ... ) ... return dict(result=msg) >>> class command_1(Command): ... def execute(self, **options): ... return dict(result='command_1.execute() called') ... >>> class command_2(Command): ... def execute(self, **options): ... return dict(result='command_2.execute() called') ... >>> api.register(meta_command) >>> api.register(command_1) >>> api.register(command_2) >>> api.finalize() >>> api.Command.meta_command(version=u'2.47') {'result': 'command_1.execute() called; command_2.execute() called.'} Because this is quite useful, we are going to revise our golden rule somewhat: **The revised golden rule:** A command plugin should implement its ``execute()`` method strictly via what it can access through ``self.api``, most likely via the backend plugins in ``self.api.Backend`` (which can also be conveniently accessed as ``self.Backend``). ----------------------------------------------- Defining arguments and options for your command ----------------------------------------------- You can define a command that will accept specific arguments and options. For example: >>> from ipalib import Str >>> class nudge(Command): ... """Takes one argument, one option""" ... ... takes_args = ('programmer',) ... ... takes_options = (Str('stuff', default=u'documentation')) ... ... def execute(self, programmer, **kw): ... return dict( ... result='%s, go write more %s!' % (programmer, kw['stuff']) ... ) ... >>> api = create_api() >>> api.env.in_server = True >>> api.register(nudge) >>> api.finalize() >>> api.Command.nudge(u'Jason', version=u'2.47') {'result': u'Jason, go write more documentation!'} >>> api.Command.nudge(u'Jason', stuff=u'unit tests', version=u'2.47') {'result': u'Jason, go write more unit tests!'} The ``args`` and ``options`` attributes are `plugable.NameSpace` instances containing a command's arguments and options, respectively, as you can see: >>> list(api.Command.nudge.args) # Iterates through argument names ['programmer'] >>> api.Command.nudge.args.programmer Str('programmer') >>> list(api.Command.nudge.options) # Iterates through option names ['stuff', 'version'] >>> api.Command.nudge.options.stuff Str('stuff', default=u'documentation') >>> api.Command.nudge.options.stuff.default u'documentation' The 'version' option is added to commands automatically. The arguments and options must not contain colliding names. They are both merged together into the ``params`` attribute, another `plugable.NameSpace` instance, as you can see: >>> api.Command.nudge.params NameSpace(<3 members>, sort=False) >>> list(api.Command.nudge.params) # Iterates through the param names ['programmer', 'stuff', 'version'] When calling a command, its positional arguments can also be provided as keyword arguments, and in any order. For example: >>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason', version=u'2.47') {'result': u'Jason, go write more lines of code!'} When a command plugin is called, the values supplied for its parameters are put through a sophisticated processing pipeline that includes steps for normalization, type conversion, validation, and dynamically constructing the defaults for missing values. The details wont be covered here; however, here is a quick teaser: >>> from ipalib import Int >>> class create_player(Command): ... takes_options = ( ... 'first', ... 'last', ... Str('nick', ... normalizer=lambda value: value.lower(), ... default_from=lambda first, last: first[0] + last, ... ), ... Int('points', default=0), ... ) ... >>> cp = create_player() >>> cp.finalize() >>> cp.convert(points=u' 1000 ') {'points': 1000} >>> cp.normalize(nick=u'NickName') {'nick': u'nickname'} >>> cp.get_default(first=u'Jason', last=u'DeRose') {'nick': u'jderose', 'points': 0} For the full details on the parameter system, see the `frontend.parse_param_spec()` function, and the `frontend.Param` and `frontend.Command` classes. --------------------------------------- Allowed return values from your command --------------------------------------- The return values from your command can be rendered by different user interfaces (CLI, web-UI); furthermore, a call to your command can be transparently forwarded over the network (XML-RPC, JSON). As such, the return values from your command must be usable by the least common denominator. Your command should return only simple data types and simple data structures, the kinds that can be represented in an XML-RPC request or in the JSON format. The return values from your command's ``execute()`` method can include only the following: Simple scalar values: These can be ``str``, ``unicode``, ``int``, and ``float`` instances, plus the ``True``, ``False``, and ``None`` constants. Simple compound values: These can be ``dict``, ``list``, and ``tuple`` instances. These compound values must contain only the simple scalar values above or other simple compound values. These compound values can also be empty. For our purposes here, the ``list`` and ``tuple`` types are equivalent and can be used interchangeably. Also note that your ``execute()`` method should not contain any ``print`` statements or otherwise cause any output on ``sys.stdout``. Your command can (and should) produce log messages by using ``self.log`` (see below). To learn more about XML-RPC (XML Remote Procedure Call), see: http://docs.python.org/library/xmlrpclib.html http://en.wikipedia.org/wiki/XML-RPC To learn more about JSON (Java Script Object Notation), see: http://docs.python.org/library/json.html http://www.json.org/ --------------------------------------- How your command should print to stdout --------------------------------------- As noted above, your command should not print anything while in its ``execute()`` method. So how does your command format its output when called from the ``ipa`` script? After the `cli.CLI.run_cmd()` method calls your command, it will call your command's ``output_for_cli()`` method (if you have implemented one). If you implement an ``output_for_cli()`` method, it must have the following signature: :: output_for_cli(textui, result, *args, **options) textui An object implementing methods for outputting to the console. Currently the `ipalib.cli.textui` plugin is passed, which your method can also access as ``self.Backend.textui``. However, in case this changes in the future, your method should use the instance passed to it in this first argument. result This is the return value from calling your command plugin. Depending upon how your command is implemented, this is probably the return value from your ``execute()`` method. args The arguments your command was called with. If your command takes no arguments, you can omit this. You can also explicitly list your arguments rather than using the generic ``*args`` form. options The options your command was called with. If your command takes no options, you can omit this. If your command takes any options, you must use the ``**options`` form as they will be provided strictly as keyword arguments. For example, say we setup a command like this: >>> class show_items(Command): ... ... takes_args = ('key?',) ... ... takes_options = (Flag('reverse'),) ... ... def execute(self, key, **options): ... items = dict( ... fruit=u'apple', ... pet=u'dog', ... city=u'Berlin', ... ) ... if key in items: ... return dict(result=items[key]) ... items = [ ... (k, items[k]) for k in sorted(items, reverse=options['reverse']) ... ] ... return dict(result=items) ... ... def output_for_cli(self, textui, result, key, **options): ... result = result['result'] ... if key is not None: ... textui.print_plain('%s = %r' % (key, result)) ... else: ... textui.print_name(self.name) ... textui.print_keyval(result) ... format = '%d items' ... if options['reverse']: ... format += ' (in reverse order)' ... textui.print_count(result, format) ... >>> api = create_api() >>> api.bootstrap(in_server=True) # We want to execute, not forward >>> api.register(show_items) >>> api.finalize() Normally when you invoke the ``ipa`` script, `cli.CLI.load_plugins()` will register the `cli.textui` backend plugin, but for the sake of our example, we will just create an instance here: >>> from ipalib import cli >>> textui = cli.textui() # We'll pass this to output_for_cli() Now for what we are concerned with in this example, calling your command through the ``ipa`` script basically will do the following: >>> result = api.Command.show_items() >>> api.Command.show_items.output_for_cli(textui, result, None, reverse=False) ----------- show-items: ----------- city = u'Berlin' fruit = u'apple' pet = u'dog' ------- 3 items ------- Similarly, calling it with ``reverse=True`` would result in the following: >>> result = api.Command.show_items(reverse=True) >>> api.Command.show_items.output_for_cli(textui, result, None, reverse=True) ----------- show-items: ----------- pet = u'dog' fruit = u'apple' city = u'Berlin' -------------------------- 3 items (in reverse order) -------------------------- Lastly, providing a ``key`` would result in the following: >>> result = api.Command.show_items(u'city') >>> api.Command.show_items.output_for_cli(textui, result, 'city', reverse=False) city = u'Berlin' See the `ipalib.cli.textui` plugin for a description of its methods. ------------------------ Logging from your plugin ------------------------ After `plugable.Plugin.set_api()` is called, your plugin will have a ``self.log`` attribute. Plugins should only log through this attribute. For example: >>> class paint_house(Command): ... ... takes_args = 'color' ... ... def execute(self, color, **options): ... """Uses self.log.error()""" ... if color not in ('red', 'blue', 'green'): ... self.log.error("I don't have %s paint!", color) # Log error ... return ... return 'I painted the house %s.' % color ... Some basic knowledge of the Python ``logging`` module might be helpful. See: http://docs.python.org/library/logging.html The important thing to remember is that your plugin should not configure logging itself, but should instead simply use the ``self.log`` logger. Also see the `plugable.API.bootstrap()` method for details on how the logging is configured. --------------------- Environment variables --------------------- Plugins access configuration variables and run-time information through ``self.api.env`` (or for convenience, ``self.env`` is equivalent). This attribute is a refences to the `ipalib.config.Env` instance created in `plugable.API.__init__()`. After `API.bootstrap()` has been called, the `Env` instance will be populated with all the environment information used by the built-in plugins. This will be called before any plugins are registered, so plugin authors can assume these variables will all exist by the time the module containing their plugin (or plugins) is imported. `Env._bootstrap()`, which is called by `API.bootstrap()`, will create several run-time variables that connot be overriden in configuration files or through command-line options. Here is an overview of this run-time information: ============= ============================= ======================= Key Example value Description ============= ============================= ======================= bin '/usr/bin' Dir. containing script dot_ipa '/home/jderose/.ipa' User config directory home os.environ['HOME'] User home dir. ipalib '.../site-packages/ipalib' Dir. of ipalib package mode 'unit_test' The mode ipalib is in script sys.argv[0] Path of script site_packages '.../python2.5/site-packages' Dir. containing ipalib/ ============= ============================= ======================= If your plugin requires new environment variables *and* will be included in the freeIPA built-in plugins, you should add the defaults for your variables in `ipalib.constants.DEFAULT_CONFIG`. Also, you should consider whether your new environment variables should have any auto-magic logic to determine their values if they haven't already been set by the time `config.Env._bootstrap()`, `config.Env._finalize_core()`, or `config.Env._finalize()` is called. On the other hand, if your plugin requires new environment variables and will be installed in a 3rd-party package, your plugin should set these variables in the module it is defined in. `config.Env` values work on a first-one-wins basis... after a value has been set, it can not be overridden with a new value. As any variables can be set using the command-line ``-e`` global option or set in a configuration file, your module must check whether a variable has already been set before setting its default value. For example: >>> if 'message_of_the_day' not in api.env: ... api.env.message_of_the_day = 'Hello, world!' ... Your plugin can access any environment variables via ``self.env``. For example: >>> class motd(Command): ... """Print message of the day.""" ... ... def execute(self, **options): ... return dict(result=self.env.message) ... >>> api = create_api() >>> api.bootstrap(in_server=True, message='Hello, world!') >>> api.register(motd) >>> api.finalize() >>> api.Command.motd(version=u'2.47') {'result': u'Hello, world!'} Also see the `plugable.API.bootstrap_with_global_options()` method. --------------------------------------------- Indispensable ipa script commands and options --------------------------------------------- The ``console`` command will launch a custom interactive Python interpreter session. The global environment will have an ``api`` variable, which is the standard `plugable.API` instance found at ``ipalib.api``. All plugins will have been loaded (well, except the backend plugins if ``in_server`` is False) and ``api`` will be fully initialized. To launch the console from within the top-level directory in the source tree, just run ``ipa console`` from a terminal, like this: :: $ ./ipa console By default, ``in_server`` is False. If you want to start the console in a server context (so that all the backend plugins are loaded), you can use the ``-e`` option to set the ``in_server`` environment variable, like this: :: $ ./ipa -e in_server=True console You can specify multiple environment variables by including the ``-e`` option multiple times, like this: :: $ ./ipa -e in_server=True -e mode=dummy console The space after the ``-e`` is optional. This is equivalent to the above command: :: $ ./ipa -ein_server=True -emode=dummy console The ``env`` command will print out the full environment in key=value pairs, like this: :: $ ./ipa env If you use the ``--server`` option, it will forward the call to the server over XML-RPC and print out what the environment is on the server, like this: :: $ ./ipa env --server The ``plugins`` command will show details of all the plugin that are loaded, like this: :: $ ./ipa plugins ----------------------------------- Learning more about freeIPA plugins ----------------------------------- To learn more about writing freeIPA plugins, you should: 1. Look at some of the built-in plugins, like the frontend plugins in `ipalib.plugins.f_user` and the backend plugins in `ipaserver.plugins.b_ldap`. 2. Learn about the base classes for frontend plugins in `ipalib.frontend`. 3. Learn about the core plugin framework in `ipalib.plugable`. Furthermore, the freeIPA plugin architecture was inspired by the Bazaar plugin architecture. Although the two are different enough that learning how to write plugins for Bazaar will not particularly help you write plugins for freeIPA, some might be interested in the documentation on writing plugins for Bazaar, available here: http://bazaar-vcs.org/WritingPlugins If nothing else, we just want to give credit where credit is deserved! However, freeIPA does not use any *code* from Bazaar... it merely borrows a little inspiration. -------------------------- A note on docstring markup -------------------------- Lastly, a quick note on markup: All the Python docstrings in freeIPA v2 (including this tutorial) use the *reStructuredText* markup language. For information on reStructuredText, see: http://docutils.sourceforge.net/rst.html For information on using reStructuredText markup with epydoc, see: http://epydoc.sourceforge.net/manual-othermarkup.html -------------------------------------------------- Next steps: get involved with freeIPA development! -------------------------------------------------- The freeIPA team is always interested in feedback and contribution from the community. To get involved with freeIPA, see the *Contribute* page on freeIPA.org: http://freeipa.org/page/Contribute ''' import os import plugable from backend import Backend from frontend import Command, LocalOrRemote, Updater, Advice from frontend import Object, Method, Property from crud import Create, Retrieve, Update, Delete, Search from parameters import DefaultFrom, Bool, Flag, Int, Decimal, Bytes, Str, IA5Str, Password, DNParam, DeprecatedParam from parameters import BytesEnum, StrEnum, AccessTime, File from errors import SkipPluginModule from text import _, ngettext, GettextFactory, NGettextFactory version_info = (2, 0, 0, 'alpha', 0) if version_info[3] == 'final': __version__ = '%d.%d.%d' % version_info[:3] else: __version__ = '%d.%d.%d.%s.%d' % version_info def create_api(mode='dummy'): """ Return standard `plugable.API` instance. This standard instance allows plugins that subclass from the following base classes: - `frontend.Command` - `frontend.Object` - `frontend.Method` - `frontend.Property` - `frontend.Advice` - `backend.Backend` """ api = plugable.API(Command, Object, Method, Property, Backend, Updater, Advice) if mode is not None: api.env.mode = mode assert mode != 'production' return api api = create_api(mode=None) if os.environ.get('IPA_UNIT_TEST_MODE', None) == 'cli_test': from cli import cli_plugins for klass in cli_plugins: api.register(klass) api.bootstrap(context='cli', in_server=False, in_tree=True) api.finalize() freeipa-3.3.4/ipalib/errors.py0000664000175000017500000012346112271663206015644 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty inmsgion # # 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 . """ Custom exception classes (some which are RPC transparent). `PrivateError` and its subclasses are custom IPA excetions that will *never* be forwarded in a Remote Procedure Call (RPC) response. On the other hand, `PublicError` and its subclasses can be forwarded in an RPC response. These public errors each carry a unique integer error code as well as a gettext translated error message (translated at the time the exception is raised). The purpose of the public errors is to relay information about *expected* user errors, service availability errors, and so on. They should *never* be used for *unexpected* programmatic or run-time errors. For security reasons it is *extremely* important that arbitrary exceptions *not* be forwarded in an RPC response. Unexpected exceptions can easily contain compromising information in their error messages. Any time the server catches any exception that isn't a `PublicError` subclass, it should raise an `InternalError`, which itself always has the same, static error message (and therefore cannot be populated with information about the true exception). The public errors are arranging into five main blocks of error code ranges: ============= ======================================== Error codes Exceptions ============= ======================================== 1000 - 1999 `AuthenticationError` and its subclasses 2000 - 2999 `AuthorizationError` and its subclasses 3000 - 3999 `InvocationError` and its subclasses 4000 - 4999 `ExecutionError` and its subclasses 5000 - 5999 `GenericError` and its subclasses ============= ======================================== Within these five blocks some sub-ranges are already allocated for certain types of error messages, while others are reserved for future use. Here are the current block assignments: - **900-5999** `PublicError` and its subclasses - **901 - 907** Assigned to special top-level public errors - **908 - 999** *Reserved for future use* - **1000 - 1999** `AuthenticationError` and its subclasses - **1001 - 1099** Open for general authentication errors - **1100 - 1199** `KerberosError` and its subclasses - **1200 - 1299** `SessionError` and its subclasses - **1300 - 1999** *Reserved for future use* - **2000 - 2999** `AuthorizationError` and its subclasses - **2001 - 2099** Open for general authorization errors - **2100 - 2199** `ACIError` and its subclasses - **2200 - 2999** *Reserved for future use* - **3000 - 3999** `InvocationError` and its subclasses - **3001 - 3099** Open for general invocation errors - **3100 - 3199** *Reserved for future use* - **4000 - 4999** `ExecutionError` and its subclasses - **4001 - 4099** Open for general execution errors - **4100 - 4199** `BuiltinError` and its subclasses - **4200 - 4299** `LDAPError` and its subclasses - **4300 - 4399** `CertificateError` and its subclasses - **4400 - 4999** *Reserved for future use* - **5000 - 5999** `GenericError` and its subclasses - **5001 - 5099** Open for generic errors - **5100 - 5999** *Reserved for future use* """ from ipalib.text import ngettext as ungettext import messages class PrivateError(StandardError): """ Base class for exceptions that are *never* forwarded in an RPC response. """ format = '' def __init__(self, **kw): self.msg = self.format % kw self.kw = kw for (key, value) in kw.iteritems(): assert not hasattr(self, key), 'conflicting kwarg %s.%s = %r' % ( self.__class__.__name__, key, value, ) setattr(self, key, value) StandardError.__init__(self, self.msg) class SubprocessError(PrivateError): """ Raised when ``subprocess.call()`` returns a non-zero exit status. This custom exception is needed because Python 2.4 doesn't have the ``subprocess.CalledProcessError`` exception (which was added in Python 2.5). For example: >>> raise SubprocessError(returncode=2, argv=('ls', '-lh', '/no-foo/')) Traceback (most recent call last): ... SubprocessError: return code 2 from ('ls', '-lh', '/no-foo/') The exit code of the sub-process is available via the ``returncode`` instance attribute. For example: >>> e = SubprocessError(returncode=1, argv=('/bin/false',)) >>> e.returncode 1 >>> e.argv # argv is also available ('/bin/false',) """ format = 'return code %(returncode)d from %(argv)r' class PluginSubclassError(PrivateError): """ Raised when a plugin doesn't subclass from an allowed base. For example: >>> raise PluginSubclassError(plugin='bad', bases=('base1', 'base2')) Traceback (most recent call last): ... PluginSubclassError: 'bad' not subclass of any base in ('base1', 'base2') """ format = '%(plugin)r not subclass of any base in %(bases)r' class PluginDuplicateError(PrivateError): """ Raised when the same plugin class is registered more than once. For example: >>> raise PluginDuplicateError(plugin='my_plugin') Traceback (most recent call last): ... PluginDuplicateError: 'my_plugin' was already registered """ format = '%(plugin)r was already registered' class PluginOverrideError(PrivateError): """ Raised when a plugin overrides another without using ``override=True``. For example: >>> raise PluginOverrideError(base='Command', name='env', plugin='my_env') Traceback (most recent call last): ... PluginOverrideError: unexpected override of Command.env with 'my_env' """ format = 'unexpected override of %(base)s.%(name)s with %(plugin)r' class PluginMissingOverrideError(PrivateError): """ Raised when a plugin overrides another that has not been registered. For example: >>> raise PluginMissingOverrideError(base='Command', name='env', plugin='my_env') Traceback (most recent call last): ... PluginMissingOverrideError: Command.env not registered, cannot override with 'my_env' """ format = '%(base)s.%(name)s not registered, cannot override with %(plugin)r' class SkipPluginModule(PrivateError): """ Raised to abort the loading of a plugin module. """ format = '%(reason)s' class PluginsPackageError(PrivateError): """ Raised when ``package.plugins`` is a module instead of a sub-package. """ format = '%(name)s must be sub-package, not module: %(file)r' ############################################################################## # Public errors: _texts = [] def _(message): _texts.append(message) return message class PublicError(StandardError): """ **900** Base class for exceptions that can be forwarded in an RPC response. """ def __init__(self, format=None, message=None, **kw): messages.process_message_arguments(self, format, message, **kw) super(PublicError, self).__init__(self.msg) errno = 900 rval = 1 format = None class VersionError(PublicError): """ **901** Raised when client and server versions are incompatible. For example: >>> raise VersionError(cver='2.0', sver='2.1', server='https://localhost') Traceback (most recent call last): ... VersionError: 2.0 client incompatible with 2.1 server at 'https://localhost' """ errno = 901 format = _("%(cver)s client incompatible with %(sver)s server at '%(server)s'") class UnknownError(PublicError): """ **902** Raised when client does not know error it caught from server. For example: >>> raise UnknownError(code=57, server='localhost', error=u'a new error') ... Traceback (most recent call last): ... UnknownError: unknown error 57 from localhost: a new error """ errno = 902 format = _('unknown error %(code)d from %(server)s: %(error)s') class InternalError(PublicError): """ **903** Raised to conceal a non-public exception. For example: >>> raise InternalError() Traceback (most recent call last): ... InternalError: an internal error has occurred """ errno = 903 format = _('an internal error has occurred') def __init__(self, message=None): """ Security issue: ignore any information given to constructor. """ PublicError.__init__(self) class ServerInternalError(PublicError): """ **904** Raised when client catches an `InternalError` from server. For example: >>> raise ServerInternalError(server='https://localhost') Traceback (most recent call last): ... ServerInternalError: an internal error has occurred on server at 'https://localhost' """ errno = 904 format = _("an internal error has occurred on server at '%(server)s'") class CommandError(PublicError): """ **905** Raised when an unknown command is called. For example: >>> raise CommandError(name='foobar') Traceback (most recent call last): ... CommandError: unknown command 'foobar' """ errno = 905 format = _("unknown command '%(name)s'") class ServerCommandError(PublicError): """ **906** Raised when client catches a `CommandError` from server. For example: >>> e = CommandError(name='foobar') >>> raise ServerCommandError(error=e.message, server='https://localhost') Traceback (most recent call last): ... ServerCommandError: error on server 'https://localhost': unknown command 'foobar' """ errno = 906 format = _("error on server '%(server)s': %(error)s") class NetworkError(PublicError): """ **907** Raised when a network connection cannot be created. For example: >>> raise NetworkError(uri='ldap://localhost:389', error=_(u'Connection refused')) Traceback (most recent call last): ... NetworkError: cannot connect to 'ldap://localhost:389': Connection refused """ errno = 907 format = _("cannot connect to '%(uri)s': %(error)s") class ServerNetworkError(PublicError): """ **908** Raised when client catches a `NetworkError` from server. """ errno = 908 format = _("error on server '%(server)s': %(error)s") class JSONError(PublicError): """ **909** Raised when server recieved a malformed JSON-RPC request. """ errno = 909 format = _('Invalid JSON-RPC request: %(error)s') class XMLRPCMarshallError(PublicError): """ **910** Raised when the XML-RPC lib cannot marshall the request For example: >>> raise XMLRPCMarshallError(error=_('int exceeds XML-RPC limits')) Traceback (most recent call last): ... XMLRPCMarshallError: error marshalling data for XML-RPC transport: int exceeds XML-RPC limits """ errno = 910 format = _('error marshalling data for XML-RPC transport: %(error)s') class RefererError(PublicError): """ **911** Raised when the request does not contain an HTTP referer For example: >>> raise RefererError(referer='referer') Traceback (most recent call last): ... RefererError: Missing or invalid HTTP Referer, referer """ errno = 911 format = _('Missing or invalid HTTP Referer, %(referer)s') ############################################################################## # 1000 - 1999: Authentication errors class AuthenticationError(PublicError): """ **1000** Base class for authentication errors (*1000 - 1999*). """ errno = 1000 class KerberosError(AuthenticationError): """ **1100** Base class for Kerberos authentication errors (*1100 - 1199*). For example: >>> raise KerberosError(major=_('Unspecified GSS failure. Minor code may provide more information'), minor=_('No credentials cache found')) Traceback (most recent call last): ... KerberosError: Kerberos error: Unspecified GSS failure. Minor code may provide more information/No credentials cache found """ errno = 1100 format= _('Kerberos error: %(major)s/%(minor)s') class CCacheError(KerberosError): """ **1101** Raised when sever does not recieve Kerberose credentials. For example: >>> raise CCacheError() Traceback (most recent call last): ... CCacheError: did not receive Kerberos credentials """ errno = 1101 format = _('did not receive Kerberos credentials') class ServiceError(KerberosError): """ **1102** Raised when service is not found in Kerberos DB. For example: >>> raise ServiceError(service='HTTP@localhost') Traceback (most recent call last): ... ServiceError: Service 'HTTP@localhost' not found in Kerberos database """ errno = 1102 format = _("Service '%(service)s' not found in Kerberos database") class NoCCacheError(KerberosError): """ **1103** Raised when a client attempts to use Kerberos without a ccache. For example: >>> raise NoCCacheError() Traceback (most recent call last): ... NoCCacheError: No credentials cache found """ errno = 1103 format = _('No credentials cache found') class TicketExpired(KerberosError): """ **1104** Raised when a client attempts to use an expired ticket For example: >>> raise TicketExpired() Traceback (most recent call last): ... TicketExpired: Ticket expired """ errno = 1104 format = _('Ticket expired') class BadCCachePerms(KerberosError): """ **1105** Raised when a client has bad permissions on their ccache For example: >>> raise BadCCachePerms() Traceback (most recent call last): ... BadCCachePerms: Credentials cache permissions incorrect """ errno = 1105 format = _('Credentials cache permissions incorrect') class BadCCacheFormat(KerberosError): """ **1106** Raised when a client has a misformated ccache For example: >>> raise BadCCacheFormat() Traceback (most recent call last): ... BadCCacheFormat: Bad format in credentials cache """ errno = 1106 format = _('Bad format in credentials cache') class CannotResolveKDC(KerberosError): """ **1107** Raised when the KDC can't be resolved For example: >>> raise CannotResolveKDC() Traceback (most recent call last): ... CannotResolveKDC: Cannot resolve KDC for requested realm """ errno = 1107 format = _('Cannot resolve KDC for requested realm') class SessionError(AuthenticationError): """ **1200** Base class for Session errors (*1200 - 1299*). For example: """ errno = 1200 format= _('Session error') class InvalidSessionPassword(SessionError): """ **1201** Raised when we cannot obtain a TGT for a principal. """ errno = 1201 format= _('Principal %(principal)s cannot be authenticated: %(message)s') ############################################################################## # 2000 - 2999: Authorization errors class AuthorizationError(PublicError): """ **2000** Base class for authorization errors (*2000 - 2999*). """ errno = 2000 class ACIError(AuthorizationError): """ **2100** Base class for ACI authorization errors (*2100 - 2199*). """ errno = 2100 format = _('Insufficient access: %(info)s') ############################################################################## # 3000 - 3999: Invocation errors class InvocationError(PublicError): """ **3000** Base class for command invocation errors (*3000 - 3999*). """ errno = 3000 class EncodingError(InvocationError): """ **3001** Raised when received text is incorrectly encoded. """ errno = 3001 class BinaryEncodingError(InvocationError): """ **3002** Raised when received binary data is incorrectly encoded. """ errno = 3002 class ZeroArgumentError(InvocationError): """ **3003** Raised when a command is called with arguments but takes none. For example: >>> raise ZeroArgumentError(name='ping') Traceback (most recent call last): ... ZeroArgumentError: command 'ping' takes no arguments """ errno = 3003 format = _("command '%(name)s' takes no arguments") class MaxArgumentError(InvocationError): """ **3004** Raised when a command is called with too many arguments. For example: >>> raise MaxArgumentError(name='user_add', count=2) Traceback (most recent call last): ... MaxArgumentError: command 'user_add' takes at most 2 arguments """ errno = 3004 def __init__(self, message=None, **kw): if message is None: format = ungettext( "command '%(name)s' takes at most %(count)d argument", "command '%(name)s' takes at most %(count)d arguments", kw['count'] ) else: format = None InvocationError.__init__(self, format, message, **kw) class OptionError(InvocationError): """ **3005** Raised when a command is called with unknown options. """ errno = 3005 class OverlapError(InvocationError): """ **3006** Raised when arguments and options overlap. For example: >>> raise OverlapError(names=['givenname', 'login']) Traceback (most recent call last): ... OverlapError: overlapping arguments and options: ['givenname', 'login'] """ errno = 3006 format = _("overlapping arguments and options: %(names)s") class RequirementError(InvocationError): """ **3007** Raised when a required parameter is not provided. For example: >>> raise RequirementError(name='givenname') Traceback (most recent call last): ... RequirementError: 'givenname' is required """ errno = 3007 format = _("'%(name)s' is required") class ConversionError(InvocationError): """ **3008** Raised when parameter value can't be converted to correct type. For example: >>> raise ConversionError(name='age', error=_(u'must be an integer')) Traceback (most recent call last): ... ConversionError: invalid 'age': must be an integer """ errno = 3008 format = _("invalid '%(name)s': %(error)s") class ValidationError(InvocationError): """ **3009** Raised when a parameter value fails a validation rule. For example: >>> raise ValidationError(name='sn', error=_(u'can be at most 128 characters')) Traceback (most recent call last): ... ValidationError: invalid 'sn': can be at most 128 characters """ errno = 3009 format = _("invalid '%(name)s': %(error)s") class NoSuchNamespaceError(InvocationError): """ **3010** Raised when an unknown namespace is requested. For example: >>> raise NoSuchNamespaceError(name='Plugins') Traceback (most recent call last): ... NoSuchNamespaceError: api has no such namespace: 'Plugins' """ errno = 3010 format = _("api has no such namespace: '%(name)s'") class PasswordMismatch(InvocationError): """ **3011** Raise when password and password confirmation don't match. """ errno = 3011 format = _('Passwords do not match') class NotImplementedError(InvocationError): """ **3012** Raise when a function hasn't been implemented. """ errno = 3012 format = _('Command not implemented') class NotConfiguredError(InvocationError): """ **3013** Raise when there is no configuration """ errno = 3013 format = _('Client is not configured. Run ipa-client-install.') class PromptFailed(InvocationError): """ **3014** Raise when an interactive prompt failed. """ errno = 3014 format = _('Could not get %(name)s interactively') class DeprecationError(InvocationError): """ **3015** Raise when a command has been deprecated For example: >>> raise DeprecationError(name='hbacrule_add_sourcehost') Traceback (most recent call last): ... DeprecationError: Command 'hbacrule_add_sourcehost' has been deprecated """ errno = 3015 format = _("Command '%(name)s' has been deprecated") ############################################################################## # 4000 - 4999: Execution errors class ExecutionError(PublicError): """ **4000** Base class for execution errors (*4000 - 4999*). """ errno = 4000 class NotFound(ExecutionError): """ **4001** Raised when an entry is not found. For example: >>> raise NotFound(reason='no such user') Traceback (most recent call last): ... NotFound: no such user """ errno = 4001 rval = 2 format = _('%(reason)s') class DuplicateEntry(ExecutionError): """ **4002** Raised when an entry already exists. For example: >>> raise DuplicateEntry Traceback (most recent call last): ... DuplicateEntry: This entry already exists """ errno = 4002 format = _('This entry already exists') class HostService(ExecutionError): """ **4003** Raised when a host service principal is requested For example: >>> raise HostService Traceback (most recent call last): ... HostService: You must enroll a host in order to create a host service """ errno = 4003 format = _('You must enroll a host in order to create a host service') class MalformedServicePrincipal(ExecutionError): """ **4004** Raised when a service principal is not of the form: service/fully-qualified host name For example: >>> raise MalformedServicePrincipal(reason=_('missing service')) Traceback (most recent call last): ... MalformedServicePrincipal: Service principal is not of the form: service/fully-qualified host name: missing service """ errno = 4004 format = _('Service principal is not of the form: service/fully-qualified host name: %(reason)s') class RealmMismatch(ExecutionError): """ **4005** Raised when the requested realm does not match the IPA realm For example: >>> raise RealmMismatch Traceback (most recent call last): ... RealmMismatch: The realm for the principal does not match the realm for this IPA server """ errno = 4005 format = _('The realm for the principal does not match the realm for this IPA server') class RequiresRoot(ExecutionError): """ **4006** Raised when a command requires the unix super-user to run For example: >>> raise RequiresRoot Traceback (most recent call last): ... RequiresRoot: This command requires root access """ errno = 4006 format = _('This command requires root access') class AlreadyPosixGroup(ExecutionError): """ **4007** Raised when a group is already a posix group For example: >>> raise AlreadyPosixGroup Traceback (most recent call last): ... AlreadyPosixGroup: This is already a posix group """ errno = 4007 format = _('This is already a posix group') class MalformedUserPrincipal(ExecutionError): """ **4008** Raised when a user principal is not of the form: user@REALM For example: >>> raise MalformedUserPrincipal(principal='jsmith@@EXAMPLE.COM') Traceback (most recent call last): ... MalformedUserPrincipal: Principal is not of the form user@REALM: 'jsmith@@EXAMPLE.COM' """ errno = 4008 format = _("Principal is not of the form user@REALM: '%(principal)s'") class AlreadyActive(ExecutionError): """ **4009** Raised when an entry is made active that is already active For example: >>> raise AlreadyActive() Traceback (most recent call last): ... AlreadyActive: This entry is already enabled """ errno = 4009 format = _('This entry is already enabled') class AlreadyInactive(ExecutionError): """ **4010** Raised when an entry is made inactive that is already inactive For example: >>> raise AlreadyInactive() Traceback (most recent call last): ... AlreadyInactive: This entry is already disabled """ errno = 4010 format = _('This entry is already disabled') class HasNSAccountLock(ExecutionError): """ **4011** Raised when an entry has the nsAccountLock attribute set For example: >>> raise HasNSAccountLock() Traceback (most recent call last): ... HasNSAccountLock: This entry cannot be enabled or disabled """ errno = 4011 format = _('This entry cannot be enabled or disabled') class NotGroupMember(ExecutionError): """ **4012** Raised when a non-member is attempted to be removed from a group For example: >>> raise NotGroupMember() Traceback (most recent call last): ... NotGroupMember: This entry is not a member """ errno = 4012 format = _('This entry is not a member') class RecursiveGroup(ExecutionError): """ **4013** Raised when a group is added as a member of itself For example: >>> raise RecursiveGroup() Traceback (most recent call last): ... RecursiveGroup: A group may not be a member of itself """ errno = 4013 format = _('A group may not be a member of itself') class AlreadyGroupMember(ExecutionError): """ **4014** Raised when a member is attempted to be re-added to a group For example: >>> raise AlreadyGroupMember() Traceback (most recent call last): ... AlreadyGroupMember: This entry is already a member """ errno = 4014 format = _('This entry is already a member') class Base64DecodeError(ExecutionError): """ **4015** Raised when a base64-encoded blob cannot decoded For example: >>> raise Base64DecodeError(reason=_('Incorrect padding')) Traceback (most recent call last): ... Base64DecodeError: Base64 decoding failed: Incorrect padding """ errno = 4015 format = _('Base64 decoding failed: %(reason)s') class RemoteRetrieveError(ExecutionError): """ **4016** Raised when retrieving data from a remote server fails For example: >>> raise RemoteRetrieveError(reason=_("Failed to get certificate chain.")) Traceback (most recent call last): ... RemoteRetrieveError: Failed to get certificate chain. """ errno = 4016 format = _('%(reason)s') class SameGroupError(ExecutionError): """ **4017** Raised when adding a group as a member of itself For example: >>> raise SameGroupError() Traceback (most recent call last): ... SameGroupError: A group may not be added as a member of itself """ errno = 4017 format = _('A group may not be added as a member of itself') class DefaultGroupError(ExecutionError): """ **4018** Raised when removing the default user group For example: >>> raise DefaultGroupError() Traceback (most recent call last): ... DefaultGroupError: The default users group cannot be removed """ errno = 4018 format = _('The default users group cannot be removed') class DNSNotARecordError(ExecutionError): """ **4019** Raised when a hostname is not a DNS A record For example: >>> raise DNSNotARecordError() Traceback (most recent call last): ... DNSNotARecordError: Host does not have corresponding DNS A record """ errno = 4019 format = _('Host does not have corresponding DNS A record') class ManagedGroupError(ExecutionError): """ **4020** Raised when a managed group is deleted For example: >>> raise ManagedGroupError() Traceback (most recent call last): ... ManagedGroupError: Deleting a managed group is not allowed. It must be detached first. """ errno = 4020 format = _('Deleting a managed group is not allowed. It must be detached first.') class ManagedPolicyError(ExecutionError): """ **4021** Raised when password policy is assigned to a managed group For example: >>> raise ManagedPolicyError() Traceback (most recent call last): ... ManagedPolicyError: A managed group cannot have a password policy. """ errno = 4021 format = _('A managed group cannot have a password policy.') class FileError(ExecutionError): """ **4022** Errors when dealing with files For example: >>> raise FileError(reason=_("cannot write file \'test\'")) Traceback (most recent call last): ... FileError: cannot write file 'test' """ errno = 4022 format = _('%(reason)s') class NoCertificateError(ExecutionError): """ **4023** Raised when trying to retrieve a certificate that doesn't exist. For example: >>> raise NoCertificateError(entry='ipa.example.com') Traceback (most recent call last): ... NoCertificateError: 'ipa.example.com' doesn't have a certificate. """ errno = 4023 format = _('\'%(entry)s\' doesn\'t have a certificate.') class ManagedGroupExistsError(ExecutionError): """ **4024** Raised when adding a user and its managed group exists For example: >>> raise ManagedGroupExistsError(group=u'engineering') Traceback (most recent call last): ... ManagedGroupExistsError: Unable to create private group. A group 'engineering' already exists. """ errno = 4024 format = _('Unable to create private group. A group \'%(group)s\' already exists.') class ReverseMemberError(ExecutionError): """ **4025** Raised when verifying that all reverse members have been added or removed. For example: >>> raise ReverseMemberError(verb=_('added'), exc=_("Group 'foo' not found.")) Traceback (most recent call last): ... ReverseMemberError: A problem was encountered when verifying that all members were added: Group 'foo' not found. """ errno = 4025 format = _('A problem was encountered when verifying that all members were %(verb)s: %(exc)s') class AttrValueNotFound(ExecutionError): """ **4026** Raised when an Attribute/Value pair is not found. For example: >>> raise AttrValueNotFound(attr='ipasudoopt', value='authenticate') Traceback (most recent call last): ... AttrValueNotFound: ipasudoopt does not contain 'authenticate' """ errno = 4026 rval = 1 format = _('%(attr)s does not contain \'%(value)s\'') class SingleMatchExpected(ExecutionError): """ **4027** Raised when a search should return a single match For example: >>> raise SingleMatchExpected(found=9) Traceback (most recent call last): ... SingleMatchExpected: The search criteria was not specific enough. Expected 1 and found 9. """ errno = 4027 rval = 1 format = _('The search criteria was not specific enough. Expected 1 and found %(found)d.') class AlreadyExternalGroup(ExecutionError): """ **4028** Raised when a group is already an external member group For example: >>> raise AlreadyExternalGroup Traceback (most recent call last): ... AlreadyExternalGroup: This group already allows external members """ errno = 4028 format = _('This group already allows external members') class ExternalGroupViolation(ExecutionError): """ **4029** Raised when a group is already an external member group and an attempt is made to use it as posix group For example: >>> raise ExternalGroupViolation Traceback (most recent call last): ... ExternalGroupViolation: This group cannot be posix because it is external """ errno = 4029 format = _('This group cannot be posix because it is external') class PosixGroupViolation(ExecutionError): """ **4030** Raised when a group is already a posix group and cannot be converted to external For example: >>> raise PosixGroupViolation Traceback (most recent call last): ... PosixGroupViolation: This is already a posix group and cannot be converted to external one """ errno = 4030 format = _('This is already a posix group and cannot be converted to external one') class BuiltinError(ExecutionError): """ **4100** Base class for builtin execution errors (*4100 - 4199*). """ errno = 4100 class HelpError(BuiltinError): """ **4101** Raised when requesting help for an unknown topic. For example: >>> raise HelpError(topic='newfeature') Traceback (most recent call last): ... HelpError: no command nor help topic 'newfeature' """ errno = 4101 format = _("no command nor help topic '%(topic)s'") class LDAPError(ExecutionError): """ **4200** Base class for LDAP execution errors (*4200 - 4299*). """ errno = 4200 class MidairCollision(ExecutionError): """ **4201** Raised when a change collides with another change For example: >>> raise MidairCollision() Traceback (most recent call last): ... MidairCollision: change collided with another change """ errno = 4201 format = _('change collided with another change') class EmptyModlist(ExecutionError): """ **4202** Raised when an LDAP update makes no changes For example: >>> raise EmptyModlist() Traceback (most recent call last): ... EmptyModlist: no modifications to be performed """ errno = 4202 format = _('no modifications to be performed') class DatabaseError(ExecutionError): """ **4203** Raised when an LDAP error is not otherwise handled For example: >>> raise DatabaseError(desc=_("Can't contact LDAP server"), info=_('Info goes here')) Traceback (most recent call last): ... DatabaseError: Can't contact LDAP server: Info goes here """ errno = 4203 format = _('%(desc)s: %(info)s') class LimitsExceeded(ExecutionError): """ **4204** Raised when search limits are exceeded. For example: >>> raise LimitsExceeded() Traceback (most recent call last): ... LimitsExceeded: limits exceeded for this query """ errno = 4204 format = _('limits exceeded for this query') class ObjectclassViolation(ExecutionError): """ **4205** Raised when an entry is missing a required attribute or objectclass For example: >>> raise ObjectclassViolation(info=_('attribute "krbPrincipalName" not allowed')) Traceback (most recent call last): ... ObjectclassViolation: attribute "krbPrincipalName" not allowed """ errno = 4205 format = _('%(info)s') class NotAllowedOnRDN(ExecutionError): """ **4206** Raised when an RDN value is modified. For example: >>> raise NotAllowedOnRDN() Traceback (most recent call last): ... NotAllowedOnRDN: modifying primary key is not allowed """ errno = 4206 format = _('modifying primary key is not allowed') class OnlyOneValueAllowed(ExecutionError): """ **4207** Raised when trying to set more than one value to single-value attributes For example: >> raise OnlyOneValueAllowed(attr='ipasearchtimelimit') Traceback (most recent call last): ... OnlyOneValueAllowed: ipasearchtimelimit: Only one value allowed. """ errno = 4207 format = _('%(attr)s: Only one value allowed.') class InvalidSyntax(ExecutionError): """ **4208** Raised when an value does not match the required syntax For example: >> raise InvalidSyntax(attr='ipahomesrootdir') Traceback (most recent call last): ... InvalidSyntax: ipahomesrootdir: Invalid syntax """ errno = 4208 format = _('%(attr)s: Invalid syntax.') class BadSearchFilter(ExecutionError): """ **4209** Raised when an invalid LDAP search filter is used For example: >>> raise BadSearchFilter(info=_('invalid syntax')) Traceback (most recent call last): ... BadSearchFilter: Bad search filter invalid syntax """ errno = 4209 format = _('Bad search filter %(info)s') class NotAllowedOnNonLeaf(ExecutionError): """ **4210** Raised when operation is not allowed on a non-leaf entry For example: >>> raise NotAllowedOnNonLeaf() Traceback (most recent call last): ... NotAllowedOnNonLeaf: Not allowed on non-leaf entry """ errno = 4210 format = _('Not allowed on non-leaf entry') class DatabaseTimeout(DatabaseError): """ **4211** Raised when an LDAP call times out For example: >>> raise DatabaseTimeout() Traceback (most recent call last): ... DatabaseTimeout: LDAP timeout """ errno = 4211 format = _('LDAP timeout') class CertificateError(ExecutionError): """ **4300** Base class for Certificate execution errors (*4300 - 4399*). """ errno = 4300 class CertificateOperationError(CertificateError): """ **4301** Raised when a certificate operation cannot be completed For example: >>> raise CertificateOperationError(error=_(u'bad serial number')) Traceback (most recent call last): ... CertificateOperationError: Certificate operation cannot be completed: bad serial number """ errno = 4301 format = _('Certificate operation cannot be completed: %(error)s') class CertificateFormatError(CertificateError): """ **4302** Raised when a certificate is badly formatted For example: >>> raise CertificateFormatError(error=_(u'improperly formated DER-encoded certificate')) Traceback (most recent call last): ... CertificateFormatError: Certificate format error: improperly formated DER-encoded certificate """ errno = 4302 format = _('Certificate format error: %(error)s') class MutuallyExclusiveError(ExecutionError): """ **4303** Raised when an operation would result in setting two attributes which are mutually exlusive. For example: >>> raise MutuallyExclusiveError(reason=_(u'hosts may not be added when hostcategory=all')) Traceback (most recent call last): ... MutuallyExclusiveError: hosts may not be added when hostcategory=all """ errno = 4303 format = _('%(reason)s') class NonFatalError(ExecutionError): """ **4304** Raised when part of an operation succeeds and the part that failed isn't critical. For example: >>> raise NonFatalError(reason=_(u'The host was added but the DNS update failed')) Traceback (most recent call last): ... NonFatalError: The host was added but the DNS update failed """ errno = 4304 format = _('%(reason)s') class AlreadyRegisteredError(ExecutionError): """ **4305** Raised when registering a user that is already registered. For example: >>> raise AlreadyRegisteredError() Traceback (most recent call last): ... AlreadyRegisteredError: Already registered """ errno = 4305 format = _('Already registered') class NotRegisteredError(ExecutionError): """ **4306** Raised when not registered and a registration is required For example: >>> raise NotRegisteredError() Traceback (most recent call last): ... NotRegisteredError: Not registered yet """ errno = 4306 format = _('Not registered yet') class DependentEntry(ExecutionError): """ **4307** Raised when an entry being deleted has dependencies For example: >>> raise DependentEntry(label=u'SELinux User Map', key=u'test', dependent=u'test1') Traceback (most recent call last): ... DependentEntry: test cannot be deleted because SELinux User Map test1 requires it """ errno = 4307 format = _('%(key)s cannot be deleted because %(label)s %(dependent)s requires it') class LastMemberError(ExecutionError): """ **4308** Raised when an entry being deleted or disabled is last member of a protected group For example: >>> raise LastMemberError(key=u'admin', label=u'group', container=u'admins') Traceback (most recent call last): ... LastMemberError: admin cannot be deleted or disabled because it is the last member of group admins """ errno = 4308 format = _('%(key)s cannot be deleted or disabled because it is the last member of %(label)s %(container)s') class ProtectedEntryError(ExecutionError): """ **4309** Raised when an entry being deleted or modified in a forbidden way is protected For example: >>> raise ProtectedEntryError(label=u'group', key=u'admins', reason=_(u'privileged group')) Traceback (most recent call last): ... ProtectedEntryError: group admins cannot be deleted/modified: privileged group """ errno = 4309 format = _('%(label)s %(key)s cannot be deleted/modified: %(reason)s') class CertificateInvalidError(CertificateError): """ **4310** Raised when a certificate is not valid For example: >>> raise CertificateInvalidError(name=_(u'CA')) Traceback (most recent call last): ... CertificateInvalidError: CA certificate is not valid """ errno = 4310 format = _('%(name)s certificate is not valid') ############################################################################## # 5000 - 5999: Generic errors class GenericError(PublicError): """ **5000** Base class for errors that don't fit elsewhere (*5000 - 5999*). """ errno = 5000 public_errors = tuple(sorted( messages.iter_messages(globals(), PublicError), key=lambda E: E.errno)) if __name__ == '__main__': messages.print_report('public errors', public_errors) freeipa-3.3.4/ipalib/errors.pyc0000664000175000017500000016143212271707517016013 0ustar mkosekmkosekó †fçRc@sš dZddlmZddlZdefd„ƒYZdefd„ƒYZdefd „ƒYZd efd „ƒYZ d efd „ƒYZ defd„ƒYZ defd„ƒYZ defd„ƒYZ gZd„Zdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd „ƒYZd!efd"„ƒYZd#efd$„ƒYZd%efd&„ƒYZd'efd(„ƒYZd)efd*„ƒYZd+efd,„ƒYZd-efd.„ƒYZd/efd0„ƒYZd1efd2„ƒYZd3efd4„ƒYZd5efd6„ƒYZ d7efd8„ƒYZ!d9efd:„ƒYZ"d;efd<„ƒYZ#d=efd>„ƒYZ$d?efd@„ƒYZ%dAe%fdB„ƒYZ&dCefdD„ƒYZ'dEe'fdF„ƒYZ(dGefdH„ƒYZ)dIe)fdJ„ƒYZ*dKe)fdL„ƒYZ+dMe)fdN„ƒYZ,dOe)fdP„ƒYZ-dQe)fdR„ƒYZ.dSe)fdT„ƒYZ/dUe)fdV„ƒYZ0dWe)fdX„ƒYZ1dYe)fdZ„ƒYZ2d[e)fd\„ƒYZ3d]e)fd^„ƒYZ4d_e)fd`„ƒYZ5dae)fdb„ƒYZ6dce)fdd„ƒYZ7dee)fdf„ƒYZ8dgefdh„ƒYZ9die9fdj„ƒYZ:dke9fdl„ƒYZ;dme9fdn„ƒYZ<doe9fdp„ƒYZ=dqe9fdr„ƒYZ>dse9fdt„ƒYZ?due9fdv„ƒYZ@dwe9fdx„ƒYZAdye9fdz„ƒYZBd{e9fd|„ƒYZCd}e9fd~„ƒYZDde9fd€„ƒYZEde9fd‚„ƒYZFdƒe9fd„„ƒYZGd…e9fd†„ƒYZHd‡e9fdˆ„ƒYZId‰e9fdŠ„ƒYZJd‹e9fdŒ„ƒYZKde9fdŽ„ƒYZLde9fd„ƒYZMd‘e9fd’„ƒYZNd“e9fd”„ƒYZOd•e9fd–„ƒYZPd—e9fd˜„ƒYZQd™e9fdš„ƒYZRd›e9fdœ„ƒYZSde9fdž„ƒYZTdŸe9fd „ƒYZUd¡e9fd¢„ƒYZVd£e9fd¤„ƒYZWd¥e9fd¦„ƒYZXd§eXfd¨„ƒYZYd©e9fdª„ƒYZZd«e9fd¬„ƒYZ[d­e9fd®„ƒYZ\d¯e9fd°„ƒYZ]d±e9fd²„ƒYZ^d³e9fd´„ƒYZ_dµe9fd¶„ƒYZ`d·e9fd¸„ƒYZad¹e9fdº„ƒYZbd»e9fd¼„ƒYZcd½e9fd¾„ƒYZdd¿e]fdÀ„ƒYZedÁe9fd„ƒYZfdÃeffdÄ„ƒYZgdÅeffdÆ„ƒYZhdÇe9fdÈ„ƒYZidÉe9fdÊ„ƒYZjdËe9fdÌ„ƒYZkdÍe9fd΄ƒYZldÏe9fdЄƒYZmdÑe9fdÒ„ƒYZndÓe9fdÔ„ƒYZodÕeffdÖ„ƒYZpd×efdØ„ƒYZqeresejteuƒeƒdÙdÚ„ƒƒZvewdÛkr– ejxdÜevƒndS(Ýs> Custom exception classes (some which are RPC transparent). `PrivateError` and its subclasses are custom IPA excetions that will *never* be forwarded in a Remote Procedure Call (RPC) response. On the other hand, `PublicError` and its subclasses can be forwarded in an RPC response. These public errors each carry a unique integer error code as well as a gettext translated error message (translated at the time the exception is raised). The purpose of the public errors is to relay information about *expected* user errors, service availability errors, and so on. They should *never* be used for *unexpected* programmatic or run-time errors. For security reasons it is *extremely* important that arbitrary exceptions *not* be forwarded in an RPC response. Unexpected exceptions can easily contain compromising information in their error messages. Any time the server catches any exception that isn't a `PublicError` subclass, it should raise an `InternalError`, which itself always has the same, static error message (and therefore cannot be populated with information about the true exception). The public errors are arranging into five main blocks of error code ranges: ============= ======================================== Error codes Exceptions ============= ======================================== 1000 - 1999 `AuthenticationError` and its subclasses 2000 - 2999 `AuthorizationError` and its subclasses 3000 - 3999 `InvocationError` and its subclasses 4000 - 4999 `ExecutionError` and its subclasses 5000 - 5999 `GenericError` and its subclasses ============= ======================================== Within these five blocks some sub-ranges are already allocated for certain types of error messages, while others are reserved for future use. Here are the current block assignments: - **900-5999** `PublicError` and its subclasses - **901 - 907** Assigned to special top-level public errors - **908 - 999** *Reserved for future use* - **1000 - 1999** `AuthenticationError` and its subclasses - **1001 - 1099** Open for general authentication errors - **1100 - 1199** `KerberosError` and its subclasses - **1200 - 1299** `SessionError` and its subclasses - **1300 - 1999** *Reserved for future use* - **2000 - 2999** `AuthorizationError` and its subclasses - **2001 - 2099** Open for general authorization errors - **2100 - 2199** `ACIError` and its subclasses - **2200 - 2999** *Reserved for future use* - **3000 - 3999** `InvocationError` and its subclasses - **3001 - 3099** Open for general invocation errors - **3100 - 3199** *Reserved for future use* - **4000 - 4999** `ExecutionError` and its subclasses - **4001 - 4099** Open for general execution errors - **4100 - 4199** `BuiltinError` and its subclasses - **4200 - 4299** `LDAPError` and its subclasses - **4300 - 4399** `CertificateError` and its subclasses - **4400 - 4999** *Reserved for future use* - **5000 - 5999** `GenericError` and its subclasses - **5001 - 5099** Open for generic errors - **5100 - 5999** *Reserved for future use* iÿÿÿÿ(tngettextNt PrivateErrorcBseZdZdZd„ZRS(sR Base class for exceptions that are *never* forwarded in an RPC response. tcKsŒ|j||_||_xY|jƒD]K\}}t||ƒ satd|jj||fƒ‚t|||ƒq&Wt j ||jƒdS(Nsconflicting kwarg %s.%s = %r( tformattmsgtkwt iteritemsthasattrtAssertionErrort __class__t__name__tsetattrt StandardErrort__init__(tselfRtkeytvalue((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR us (R t __module__t__doc__RR (((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRnstSubprocessErrorcBseZdZdZRS(sÀ Raised when ``subprocess.call()`` returns a non-zero exit status. This custom exception is needed because Python 2.4 doesn't have the ``subprocess.CalledProcessError`` exception (which was added in Python 2.5). For example: >>> raise SubprocessError(returncode=2, argv=('ls', '-lh', '/no-foo/')) Traceback (most recent call last): ... SubprocessError: return code 2 from ('ls', '-lh', '/no-foo/') The exit code of the sub-process is available via the ``returncode`` instance attribute. For example: >>> e = SubprocessError(returncode=1, argv=('/bin/false',)) >>> e.returncode 1 >>> e.argv # argv is also available ('/bin/false',) s(return code %(returncode)d from %(argv)r(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR€stPluginSubclassErrorcBseZdZdZRS(s" Raised when a plugin doesn't subclass from an allowed base. For example: >>> raise PluginSubclassError(plugin='bad', bases=('base1', 'base2')) Traceback (most recent call last): ... PluginSubclassError: 'bad' not subclass of any base in ('base1', 'base2') s0%(plugin)r not subclass of any base in %(bases)r(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR›s tPluginDuplicateErrorcBseZdZdZRS(s Raised when the same plugin class is registered more than once. For example: >>> raise PluginDuplicateError(plugin='my_plugin') Traceback (most recent call last): ... PluginDuplicateError: 'my_plugin' was already registered s!%(plugin)r was already registered(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR«s tPluginOverrideErrorcBseZdZdZRS(s. Raised when a plugin overrides another without using ``override=True``. For example: >>> raise PluginOverrideError(base='Command', name='env', plugin='my_env') Traceback (most recent call last): ... PluginOverrideError: unexpected override of Command.env with 'my_env' s8unexpected override of %(base)s.%(name)s with %(plugin)r(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRºs tPluginMissingOverrideErrorcBseZdZdZRS(sB Raised when a plugin overrides another that has not been registered. For example: >>> raise PluginMissingOverrideError(base='Command', name='env', plugin='my_env') Traceback (most recent call last): ... PluginMissingOverrideError: Command.env not registered, cannot override with 'my_env' sA%(base)s.%(name)s not registered, cannot override with %(plugin)r(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRÉs tSkipPluginModulecBseZdZdZRS(s9 Raised to abort the loading of a plugin module. s %(reason)s(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRØstPluginsPackageErrorcBseZdZdZRS(sO Raised when ``package.plugins`` is a module instead of a sub-package. s2%(name)s must be sub-package, not module: %(file)r(R RRR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRàscCstj|ƒ|S(N(t_textstappend(tmessage((s+/home/mkosek/freeipa-clean/ipalib/errors.pyt_ís t PublicErrorcBs/eZdZddd„ZdZdZdZRS(sU **900** Base class for exceptions that can be forwarded in an RPC response. cKs3tj||||tt|ƒj|jƒdS(N(tmessagestprocess_message_argumentstsuperRR R(RRRR((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR ösi„iN(R RRtNoneR terrnotrvalR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRòs t VersionErrorcBs eZdZdZedƒZRS(s/ **901** Raised when client and server versions are incompatible. For example: >>> raise VersionError(cver='2.0', sver='2.1', server='https://localhost') Traceback (most recent call last): ... VersionError: 2.0 client incompatible with 2.1 server at 'https://localhost' i…sA%(cver)s client incompatible with %(sver)s server at '%(server)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR%ÿs t UnknownErrorcBs eZdZdZedƒZRS(s) **902** Raised when client does not know error it caught from server. For example: >>> raise UnknownError(code=57, server='localhost', error=u'a new error') ... Traceback (most recent call last): ... UnknownError: unknown error 57 from localhost: a new error i†s1unknown error %(code)d from %(server)s: %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR&s t InternalErrorcBs,eZdZdZedƒZdd„ZRS(sÏ **903** Raised to conceal a non-public exception. For example: >>> raise InternalError() Traceback (most recent call last): ... InternalError: an internal error has occurred i‡san internal error has occurredcCstj|ƒdS(sN Security issue: ignore any information given to constructor. N(RR (RR((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR 1sN(R RRR#RRR"R (((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR'"s  tServerInternalErrorcBs eZdZdZedƒZRS(s' **904** Raised when client catches an `InternalError` from server. For example: >>> raise ServerInternalError(server='https://localhost') Traceback (most recent call last): ... ServerInternalError: an internal error has occurred on server at 'https://localhost' iˆs8an internal error has occurred on server at '%(server)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR(8s t CommandErrorcBs eZdZdZedƒZRS(sÔ **905** Raised when an unknown command is called. For example: >>> raise CommandError(name='foobar') Traceback (most recent call last): ... CommandError: unknown command 'foobar' i‰sunknown command '%(name)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR)Hs tServerCommandErrorcBs eZdZdZedƒZRS(sZ **906** Raised when client catches a `CommandError` from server. For example: >>> e = CommandError(name='foobar') >>> raise ServerCommandError(error=e.message, server='https://localhost') Traceback (most recent call last): ... ServerCommandError: error on server 'https://localhost': unknown command 'foobar' iŠs'error on server '%(server)s': %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR*Xs t NetworkErrorcBs eZdZdZedƒZRS(s/ **907** Raised when a network connection cannot be created. For example: >>> raise NetworkError(uri='ldap://localhost:389', error=_(u'Connection refused')) Traceback (most recent call last): ... NetworkError: cannot connect to 'ldap://localhost:389': Connection refused i‹s&cannot connect to '%(uri)s': %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR+is tServerNetworkErrorcBs eZdZdZedƒZRS(sJ **908** Raised when client catches a `NetworkError` from server. iŒs'error on server '%(server)s': %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR,yst JSONErrorcBs eZdZdZedƒZRS(sK **909** Raised when server recieved a malformed JSON-RPC request. is#Invalid JSON-RPC request: %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR-‚stXMLRPCMarshallErrorcBs eZdZdZedƒZRS(s8 **910** Raised when the XML-RPC lib cannot marshall the request For example: >>> raise XMLRPCMarshallError(error=_('int exceeds XML-RPC limits')) Traceback (most recent call last): ... XMLRPCMarshallError: error marshalling data for XML-RPC transport: int exceeds XML-RPC limits iŽs7error marshalling data for XML-RPC transport: %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR.‹s t RefererErrorcBs eZdZdZedƒZRS(s÷ **911** Raised when the request does not contain an HTTP referer For example: >>> raise RefererError(referer='referer') Traceback (most recent call last): ... RefererError: Missing or invalid HTTP Referer, referer is,Missing or invalid HTTP Referer, %(referer)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR/›s tAuthenticationErrorcBseZdZdZRS(sH **1000** Base class for authentication errors (*1000 - 1999*). iè(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR0­st KerberosErrorcBs eZdZdZedƒZRS(s§ **1100** Base class for Kerberos authentication errors (*1100 - 1199*). For example: >>> raise KerberosError(major=_('Unspecified GSS failure. Minor code may provide more information'), minor=_('No credentials cache found')) Traceback (most recent call last): ... KerberosError: Kerberos error: Unspecified GSS failure. Minor code may provide more information/No credentials cache found iLs#Kerberos error: %(major)s/%(minor)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR1µs t CCacheErrorcBs eZdZdZedƒZRS(sã **1101** Raised when sever does not recieve Kerberose credentials. For example: >>> raise CCacheError() Traceback (most recent call last): ... CCacheError: did not receive Kerberos credentials iMs$did not receive Kerberos credentials(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR2Æs t ServiceErrorcBs eZdZdZedƒZRS(s **1102** Raised when service is not found in Kerberos DB. For example: >>> raise ServiceError(service='HTTP@localhost') Traceback (most recent call last): ... ServiceError: Service 'HTTP@localhost' not found in Kerberos database iNs4Service '%(service)s' not found in Kerberos database(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR3×s t NoCCacheErrorcBs eZdZdZedƒZRS(sâ **1103** Raised when a client attempts to use Kerberos without a ccache. For example: >>> raise NoCCacheError() Traceback (most recent call last): ... NoCCacheError: No credentials cache found iOsNo credentials cache found(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR4çs t TicketExpiredcBs eZdZdZedƒZRS(sÍ **1104** Raised when a client attempts to use an expired ticket For example: >>> raise TicketExpired() Traceback (most recent call last): ... TicketExpired: Ticket expired iPsTicket expired(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR5÷s tBadCCachePermscBs eZdZdZedƒZRS(sê **1105** Raised when a client has bad permissions on their ccache For example: >>> raise BadCCachePerms() Traceback (most recent call last): ... BadCCachePerms: Credentials cache permissions incorrect iQs'Credentials cache permissions incorrect(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR6s tBadCCacheFormatcBs eZdZdZedƒZRS(sÙ **1106** Raised when a client has a misformated ccache For example: >>> raise BadCCacheFormat() Traceback (most recent call last): ... BadCCacheFormat: Bad format in credentials cache iRsBad format in credentials cache(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR7s tCannotResolveKDCcBs eZdZdZedƒZRS(sÚ **1107** Raised when the KDC can't be resolved For example: >>> raise CannotResolveKDC() Traceback (most recent call last): ... CannotResolveKDC: Cannot resolve KDC for requested realm iSs&Cannot resolve KDC for requested realm(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR8's t SessionErrorcBs eZdZdZedƒZRS(sT **1200** Base class for Session errors (*1200 - 1299*). For example: i°s Session error(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR97stInvalidSessionPasswordcBs eZdZdZedƒZRS(sF **1201** Raised when we cannot obtain a TGT for a principal. i±s<Principal %(principal)s cannot be authenticated: %(message)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR:CstAuthorizationErrorcBseZdZdZRS(sG **2000** Base class for authorization errors (*2000 - 2999*). iÐ(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR;LstACIErrorcBs eZdZdZedƒZRS(sK **2100** Base class for ACI authorization errors (*2100 - 2199*). i4sInsufficient access: %(info)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR<TstInvocationErrorcBseZdZdZRS(sL **3000** Base class for command invocation errors (*3000 - 3999*). i¸ (R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR=ast EncodingErrorcBseZdZdZRS(sD **3001** Raised when received text is incorrectly encoded. i¹ (R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR>istBinaryEncodingErrorcBseZdZdZRS(sK **3002** Raised when received binary data is incorrectly encoded. iº (R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR?qstZeroArgumentErrorcBs eZdZdZedƒZRS(sû **3003** Raised when a command is called with arguments but takes none. For example: >>> raise ZeroArgumentError(name='ping') Traceback (most recent call last): ... ZeroArgumentError: command 'ping' takes no arguments i» s%command '%(name)s' takes no arguments(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR@ys tMaxArgumentErrorcBs eZdZdZdd„ZRS(s  **3004** Raised when a command is called with too many arguments. For example: >>> raise MaxArgumentError(name='user_add', count=2) Traceback (most recent call last): ... MaxArgumentError: command 'user_add' takes at most 2 arguments i¼ cKsE|dkr%tdd|dƒ}nd}tj||||dS(Ns3command '%(name)s' takes at most %(count)d arguments4command '%(name)s' takes at most %(count)d argumentstcount(R"t ungettextR=R (RRRR((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR —s N(R RRR#R"R (((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRA‰s t OptionErrorcBseZdZdZRS(sH **3005** Raised when a command is called with unknown options. i½ (R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRD£st OverlapErrorcBs eZdZdZedƒZRS(s **3006** Raised when arguments and options overlap. For example: >>> raise OverlapError(names=['givenname', 'login']) Traceback (most recent call last): ... OverlapError: overlapping arguments and options: ['givenname', 'login'] i¾ s,overlapping arguments and options: %(names)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRE«s tRequirementErrorcBs eZdZdZedƒZRS(sç **3007** Raised when a required parameter is not provided. For example: >>> raise RequirementError(name='givenname') Traceback (most recent call last): ... RequirementError: 'givenname' is required i¿ s'%(name)s' is required(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRF»s tConversionErrorcBs eZdZdZedƒZRS(s **3008** Raised when parameter value can't be converted to correct type. For example: >>> raise ConversionError(name='age', error=_(u'must be an integer')) Traceback (most recent call last): ... ConversionError: invalid 'age': must be an integer iÀ sinvalid '%(name)s': %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRGËs tValidationErrorcBs eZdZdZedƒZRS(s" **3009** Raised when a parameter value fails a validation rule. For example: >>> raise ValidationError(name='sn', error=_(u'can be at most 128 characters')) Traceback (most recent call last): ... ValidationError: invalid 'sn': can be at most 128 characters iÁ sinvalid '%(name)s': %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRHÛs tNoSuchNamespaceErrorcBs eZdZdZedƒZRS(s÷ **3010** Raised when an unknown namespace is requested. For example: >>> raise NoSuchNamespaceError(name='Plugins') Traceback (most recent call last): ... NoSuchNamespaceError: api has no such namespace: 'Plugins' i s%api has no such namespace: '%(name)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRIës tPasswordMismatchcBs eZdZdZedƒZRS(sM **3011** Raise when password and password confirmation don't match. ià sPasswords do not match(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRJûstNotImplementedErrorcBs eZdZdZedƒZRS(sA **3012** Raise when a function hasn't been implemented. iÄ sCommand not implemented(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRKstNotConfiguredErrorcBs eZdZdZedƒZRS(s7 **3013** Raise when there is no configuration iÅ s1Client is not configured. Run ipa-client-install.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRL st PromptFailedcBs eZdZdZedƒZRS(s; **3014** Raise when an interactive prompt failed. iÆ s$Could not get %(name)s interactively(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRMstDeprecationErrorcBs eZdZdZedƒZRS(s  **3015** Raise when a command has been deprecated For example: >>> raise DeprecationError(name='hbacrule_add_sourcehost') Traceback (most recent call last): ... DeprecationError: Command 'hbacrule_add_sourcehost' has been deprecated iÇ s&Command '%(name)s' has been deprecated(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRNs tExecutionErrorcBseZdZdZRS(sC **4000** Base class for execution errors (*4000 - 4999*). i (R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRO1stNotFoundcBs&eZdZdZdZedƒZRS(sà **4001** Raised when an entry is not found. For example: >>> raise NotFound(reason='no such user') Traceback (most recent call last): ... NotFound: no such user i¡is %(reason)s(R RRR#R$RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRP8s tDuplicateEntrycBs eZdZdZedƒZRS(sÇ **4002** Raised when an entry already exists. For example: >>> raise DuplicateEntry Traceback (most recent call last): ... DuplicateEntry: This entry already exists i¢sThis entry already exists(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRQIs t HostServicecBs eZdZdZedƒZRS(sí **4003** Raised when a host service principal is requested For example: >>> raise HostService Traceback (most recent call last): ... HostService: You must enroll a host in order to create a host service i£s8You must enroll a host in order to create a host service(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRRYs tMalformedServicePrincipalcBs eZdZdZedƒZRS(sj **4004** Raised when a service principal is not of the form: service/fully-qualified host name For example: >>> raise MalformedServicePrincipal(reason=_('missing service')) Traceback (most recent call last): ... MalformedServicePrincipal: Service principal is not of the form: service/fully-qualified host name: missing service i¤sSService principal is not of the form: service/fully-qualified host name: %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRSis t RealmMismatchcBs eZdZdZedƒZRS(s  **4005** Raised when the requested realm does not match the IPA realm For example: >>> raise RealmMismatch Traceback (most recent call last): ... RealmMismatch: The realm for the principal does not match the realm for this IPA server i¥sHThe realm for the principal does not match the realm for this IPA server(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRTys t RequiresRootcBs eZdZdZedƒZRS(sà **4006** Raised when a command requires the unix super-user to run For example: >>> raise RequiresRoot Traceback (most recent call last): ... RequiresRoot: This command requires root access i¦s!This command requires root access(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRU‰s tAlreadyPosixGroupcBs eZdZdZedƒZRS(sÙ **4007** Raised when a group is already a posix group For example: >>> raise AlreadyPosixGroup Traceback (most recent call last): ... AlreadyPosixGroup: This is already a posix group i§sThis is already a posix group(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRV™s tMalformedUserPrincipalcBs eZdZdZedƒZRS(s4 **4008** Raised when a user principal is not of the form: user@REALM For example: >>> raise MalformedUserPrincipal(principal='jsmith@@EXAMPLE.COM') Traceback (most recent call last): ... MalformedUserPrincipal: Principal is not of the form user@REALM: 'jsmith@@EXAMPLE.COM' i¨s8Principal is not of the form user@REALM: '%(principal)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRW©s t AlreadyActivecBs eZdZdZedƒZRS(sá **4009** Raised when an entry is made active that is already active For example: >>> raise AlreadyActive() Traceback (most recent call last): ... AlreadyActive: This entry is already enabled i©sThis entry is already enabled(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRX¹s tAlreadyInactivecBs eZdZdZedƒZRS(sê **4010** Raised when an entry is made inactive that is already inactive For example: >>> raise AlreadyInactive() Traceback (most recent call last): ... AlreadyInactive: This entry is already disabled iªsThis entry is already disabled(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRYÉs tHasNSAccountLockcBs eZdZdZedƒZRS(sð **4011** Raised when an entry has the nsAccountLock attribute set For example: >>> raise HasNSAccountLock() Traceback (most recent call last): ... HasNSAccountLock: This entry cannot be enabled or disabled i«s(This entry cannot be enabled or disabled(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRZÙs tNotGroupMembercBs eZdZdZedƒZRS(sæ **4012** Raised when a non-member is attempted to be removed from a group For example: >>> raise NotGroupMember() Traceback (most recent call last): ... NotGroupMember: This entry is not a member i¬sThis entry is not a member(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR[és tRecursiveGroupcBs eZdZdZedƒZRS(sã **4013** Raised when a group is added as a member of itself For example: >>> raise RecursiveGroup() Traceback (most recent call last): ... RecursiveGroup: A group may not be a member of itself i­s%A group may not be a member of itself(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR\ùs tAlreadyGroupMembercBs eZdZdZedƒZRS(sí **4014** Raised when a member is attempted to be re-added to a group For example: >>> raise AlreadyGroupMember() Traceback (most recent call last): ... AlreadyGroupMember: This entry is already a member i®sThis entry is already a member(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR] s tBase64DecodeErrorcBs eZdZdZedƒZRS(s **4015** Raised when a base64-encoded blob cannot decoded For example: >>> raise Base64DecodeError(reason=_('Incorrect padding')) Traceback (most recent call last): ... Base64DecodeError: Base64 decoding failed: Incorrect padding i¯s"Base64 decoding failed: %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR^s tRemoteRetrieveErrorcBs eZdZdZedƒZRS(s **4016** Raised when retrieving data from a remote server fails For example: >>> raise RemoteRetrieveError(reason=_("Failed to get certificate chain.")) Traceback (most recent call last): ... RemoteRetrieveError: Failed to get certificate chain. i°s %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR_)s tSameGroupErrorcBs eZdZdZedƒZRS(sê **4017** Raised when adding a group as a member of itself For example: >>> raise SameGroupError() Traceback (most recent call last): ... SameGroupError: A group may not be added as a member of itself i±s.A group may not be added as a member of itself(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR`9s tDefaultGroupErrorcBs eZdZdZedƒZRS(sæ **4018** Raised when removing the default user group For example: >>> raise DefaultGroupError() Traceback (most recent call last): ... DefaultGroupError: The default users group cannot be removed i²s)The default users group cannot be removed(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRaIs tDNSNotARecordErrorcBs eZdZdZedƒZRS(sí **4019** Raised when a hostname is not a DNS A record For example: >>> raise DNSNotARecordError() Traceback (most recent call last): ... DNSNotARecordError: Host does not have corresponding DNS A record i³s-Host does not have corresponding DNS A record(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRbYs tManagedGroupErrorcBs eZdZdZedƒZRS(sú **4020** Raised when a managed group is deleted For example: >>> raise ManagedGroupError() Traceback (most recent call last): ... ManagedGroupError: Deleting a managed group is not allowed. It must be detached first. i´sCDeleting a managed group is not allowed. It must be detached first.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRcis tManagedPolicyErrorcBs eZdZdZedƒZRS(sû **4021** Raised when password policy is assigned to a managed group For example: >>> raise ManagedPolicyError() Traceback (most recent call last): ... ManagedPolicyError: A managed group cannot have a password policy. iµs.A managed group cannot have a password policy.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRdxs t FileErrorcBs eZdZdZedƒZRS(sÛ **4022** Errors when dealing with files For example: >>> raise FileError(reason=_("cannot write file 'test'")) Traceback (most recent call last): ... FileError: cannot write file 'test' i¶s %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyReˆs tNoCertificateErrorcBs eZdZdZedƒZRS(s **4023** Raised when trying to retrieve a certificate that doesn't exist. For example: >>> raise NoCertificateError(entry='ipa.example.com') Traceback (most recent call last): ... NoCertificateError: 'ipa.example.com' doesn't have a certificate. i·s''%(entry)s' doesn't have a certificate.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRf˜s tManagedGroupExistsErrorcBs eZdZdZedƒZRS(s, **4024** Raised when adding a user and its managed group exists For example: >>> raise ManagedGroupExistsError(group=u'engineering') Traceback (most recent call last): ... ManagedGroupExistsError: Unable to create private group. A group 'engineering' already exists. i¸sCUnable to create private group. A group '%(group)s' already exists.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRg¨s tReverseMemberErrorcBs eZdZdZedƒZRS(si **4025** Raised when verifying that all reverse members have been added or removed. For example: >>> raise ReverseMemberError(verb=_('added'), exc=_("Group 'foo' not found.")) Traceback (most recent call last): ... ReverseMemberError: A problem was encountered when verifying that all members were added: Group 'foo' not found. i¹sPA problem was encountered when verifying that all members were %(verb)s: %(exc)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRh¸s tAttrValueNotFoundcBs&eZdZdZdZedƒZRS(s **4026** Raised when an Attribute/Value pair is not found. For example: >>> raise AttrValueNotFound(attr='ipasudoopt', value='authenticate') Traceback (most recent call last): ... AttrValueNotFound: ipasudoopt does not contain 'authenticate' iºis%%(attr)s does not contain '%(value)s'(R RRR#R$RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRiÈs tSingleMatchExpectedcBs&eZdZdZdZedƒZRS(s **4027** Raised when a search should return a single match For example: >>> raise SingleMatchExpected(found=9) Traceback (most recent call last): ... SingleMatchExpected: The search criteria was not specific enough. Expected 1 and found 9. i»isLThe search criteria was not specific enough. Expected 1 and found %(found)d.(R RRR#R$RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRjÚs tAlreadyExternalGroupcBs eZdZdZedƒZRS(s÷ **4028** Raised when a group is already an external member group For example: >>> raise AlreadyExternalGroup Traceback (most recent call last): ... AlreadyExternalGroup: This group already allows external members i¼s*This group already allows external members(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRkës tExternalGroupViolationcBs eZdZdZedƒZRS(s? **4029** Raised when a group is already an external member group and an attempt is made to use it as posix group For example: >>> raise ExternalGroupViolation Traceback (most recent call last): ... ExternalGroupViolation: This group cannot be posix because it is external i½s1This group cannot be posix because it is external(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRlûs tPosixGroupViolationcBs eZdZdZedƒZRS(s6 **4030** Raised when a group is already a posix group and cannot be converted to external For example: >>> raise PosixGroupViolation Traceback (most recent call last): ... PosixGroupViolation: This is already a posix group and cannot be converted to external one i¾sEThis is already a posix group and cannot be converted to external one(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRm s t BuiltinErrorcBseZdZdZRS(sK **4100** Base class for builtin execution errors (*4100 - 4199*). i(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRnst HelpErrorcBs eZdZdZedƒZRS(sê **4101** Raised when requesting help for an unknown topic. For example: >>> raise HelpError(topic='newfeature') Traceback (most recent call last): ... HelpError: no command nor help topic 'newfeature' is%no command nor help topic '%(topic)s'(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRo%s t LDAPErrorcBseZdZdZRS(sH **4200** Base class for LDAP execution errors (*4200 - 4299*). ih(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRp5stMidairCollisioncBs eZdZdZedƒZRS(sá **4201** Raised when a change collides with another change For example: >>> raise MidairCollision() Traceback (most recent call last): ... MidairCollision: change collided with another change iis#change collided with another change(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRq=s t EmptyModlistcBs eZdZdZedƒZRS(sÒ **4202** Raised when an LDAP update makes no changes For example: >>> raise EmptyModlist() Traceback (most recent call last): ... EmptyModlist: no modifications to be performed ijs no modifications to be performed(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRrMs t DatabaseErrorcBs eZdZdZedƒZRS(s! **4203** Raised when an LDAP error is not otherwise handled For example: >>> raise DatabaseError(desc=_("Can't contact LDAP server"), info=_('Info goes here')) Traceback (most recent call last): ... DatabaseError: Can't contact LDAP server: Info goes here iks%(desc)s: %(info)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRs]s tLimitsExceededcBs eZdZdZedƒZRS(sÐ **4204** Raised when search limits are exceeded. For example: >>> raise LimitsExceeded() Traceback (most recent call last): ... LimitsExceeded: limits exceeded for this query ilslimits exceeded for this query(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRtms tObjectclassViolationcBs eZdZdZedƒZRS(s4 **4205** Raised when an entry is missing a required attribute or objectclass For example: >>> raise ObjectclassViolation(info=_('attribute "krbPrincipalName" not allowed')) Traceback (most recent call last): ... ObjectclassViolation: attribute "krbPrincipalName" not allowed ims%(info)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRu|s tNotAllowedOnRDNcBs eZdZdZedƒZRS(sÖ **4206** Raised when an RDN value is modified. For example: >>> raise NotAllowedOnRDN() Traceback (most recent call last): ... NotAllowedOnRDN: modifying primary key is not allowed ins$modifying primary key is not allowed(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRv‹s tOnlyOneValueAllowedcBs eZdZdZedƒZRS(s  **4207** Raised when trying to set more than one value to single-value attributes For example: >> raise OnlyOneValueAllowed(attr='ipasearchtimelimit') Traceback (most recent call last): ... OnlyOneValueAllowed: ipasearchtimelimit: Only one value allowed. ios!%(attr)s: Only one value allowed.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRw›s t InvalidSyntaxcBs eZdZdZedƒZRS(sô **4208** Raised when an value does not match the required syntax For example: >> raise InvalidSyntax(attr='ipahomesrootdir') Traceback (most recent call last): ... InvalidSyntax: ipahomesrootdir: Invalid syntax ips%(attr)s: Invalid syntax.(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRx«s tBadSearchFiltercBs eZdZdZedƒZRS(sö **4209** Raised when an invalid LDAP search filter is used For example: >>> raise BadSearchFilter(info=_('invalid syntax')) Traceback (most recent call last): ... BadSearchFilter: Bad search filter invalid syntax iqsBad search filter %(info)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRy»s tNotAllowedOnNonLeafcBs eZdZdZedƒZRS(sê **4210** Raised when operation is not allowed on a non-leaf entry For example: >>> raise NotAllowedOnNonLeaf() Traceback (most recent call last): ... NotAllowedOnNonLeaf: Not allowed on non-leaf entry irsNot allowed on non-leaf entry(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRzËs tDatabaseTimeoutcBs eZdZdZedƒZRS(s» **4211** Raised when an LDAP call times out For example: >>> raise DatabaseTimeout() Traceback (most recent call last): ... DatabaseTimeout: LDAP timeout iss LDAP timeout(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR{Ûs tCertificateErrorcBseZdZdZRS(sO **4300** Base class for Certificate execution errors (*4300 - 4399*). iÌ(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR|ëstCertificateOperationErrorcBs eZdZdZedƒZRS(s2 **4301** Raised when a certificate operation cannot be completed For example: >>> raise CertificateOperationError(error=_(u'bad serial number')) Traceback (most recent call last): ... CertificateOperationError: Certificate operation cannot be completed: bad serial number iÍs4Certificate operation cannot be completed: %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR}ós tCertificateFormatErrorcBs eZdZdZedƒZRS(sD **4302** Raised when a certificate is badly formatted For example: >>> raise CertificateFormatError(error=_(u'improperly formated DER-encoded certificate')) Traceback (most recent call last): ... CertificateFormatError: Certificate format error: improperly formated DER-encoded certificate iÎs#Certificate format error: %(error)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR~s tMutuallyExclusiveErrorcBs eZdZdZedƒZRS(s] **4303** Raised when an operation would result in setting two attributes which are mutually exlusive. For example: >>> raise MutuallyExclusiveError(reason=_(u'hosts may not be added when hostcategory=all')) Traceback (most recent call last): ... MutuallyExclusiveError: hosts may not be added when hostcategory=all iÏs %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRs t NonFatalErrorcBs eZdZdZedƒZRS(sA **4304** Raised when part of an operation succeeds and the part that failed isn't critical. For example: >>> raise NonFatalError(reason=_(u'The host was added but the DNS update failed')) Traceback (most recent call last): ... NonFatalError: The host was added but the DNS update failed iÐs %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR€%s tAlreadyRegisteredErrorcBs eZdZdZedƒZRS(sè **4305** Raised when registering a user that is already registered. For example: >>> raise AlreadyRegisteredError() Traceback (most recent call last): ... AlreadyRegisteredError: Already registered iÑsAlready registered(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR6s tNotRegisteredErrorcBs eZdZdZedƒZRS(sÞ **4306** Raised when not registered and a registration is required For example: >>> raise NotRegisteredError() Traceback (most recent call last): ... NotRegisteredError: Not registered yet iÒsNot registered yet(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR‚Gs tDependentEntrycBs eZdZdZedƒZRS(s9 **4307** Raised when an entry being deleted has dependencies For example: >>> raise DependentEntry(label=u'SELinux User Map', key=u'test', dependent=u'test1') Traceback (most recent call last): ... DependentEntry: test cannot be deleted because SELinux User Map test1 requires it iÓsE%(key)s cannot be deleted because %(label)s %(dependent)s requires it(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyRƒWs tLastMemberErrorcBs eZdZdZedƒZRS(sa **4308** Raised when an entry being deleted or disabled is last member of a protected group For example: >>> raise LastMemberError(key=u'admin', label=u'group', container=u'admins') Traceback (most recent call last): ... LastMemberError: admin cannot be deleted or disabled because it is the last member of group admins iÔs^%(key)s cannot be deleted or disabled because it is the last member of %(label)s %(container)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR„gs tProtectedEntryErrorcBs eZdZdZedƒZRS(sX **4309** Raised when an entry being deleted or modified in a forbidden way is protected For example: >>> raise ProtectedEntryError(label=u'group', key=u'admins', reason=_(u'privileged group')) Traceback (most recent call last): ... ProtectedEntryError: group admins cannot be deleted/modified: privileged group iÕs8%(label)s %(key)s cannot be deleted/modified: %(reason)s(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR…ws tCertificateInvalidErrorcBs eZdZdZedƒZRS(sì **4310** Raised when a certificate is not valid For example: >>> raise CertificateInvalidError(name=_(u'CA')) Traceback (most recent call last): ... CertificateInvalidError: CA certificate is not valid iÖs!%(name)s certificate is not valid(R RRR#RR(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR†‡s t GenericErrorcBseZdZdZRS(sR **5000** Base class for errors that don't fit elsewhere (*5000 - 5999*). iˆ(R RRR#(((s+/home/mkosek/freeipa-clean/ipalib/errors.pyR‡›sRcCs|jS(N(R#(tE((s+/home/mkosek/freeipa-clean/ipalib/errors.pyt¥st__main__s public errors(yRt ipalib.textRRCRR RRRRRRRRRRRR%R&R'R(R)R*R+R,R-R.R/R0R1R2R3R4R5R6R7R8R9R:R;R<R=R>R?R@RARDRERFRGRHRIRJRKRLRMRNRORPRQRRRSRTRURVRWRXRYRZR[R\R]R^R_R`RaRbRcRdReRfRgRhRiRjRkRlRmRnRoRpRqRrRsRtRuRvRwRxRyRzR{R|R}R~RR€RR‚RƒR„R…R†R‡ttupletsortedt iter_messagestglobalst public_errorsR t print_report(((s+/home/mkosek/freeipa-clean/ipalib/errors.pytgsä              $ freeipa-3.3.4/ipalib/crud.py0000664000175000017500000002732512271663206015267 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Base classes for standard CRUD operations. These base classes are for `Method` plugins that provide standard Create, Retrieve, Updated, and Delete operations (CRUD) for their corresponding `Object` plugin. In particuar, these base classes provide logic to automatically create the plugin args and options by inspecting the params on their corresponding `Object` plugin. This provides a single point of definition for LDAP attributes and enforces a simple, consistent API for CRUD operations. For example, say we want CRUD operations on a hypothetical "user" entry. First we need an `Object` plugin: >>> from ipalib import Object, Str >>> class user(Object): ... takes_params = ( ... Str('login', primary_key=True), ... Str('first'), ... Str('last'), ... Str('ipauniqueid', flags=['no_create', 'no_update']), ... ) ... Next we need `Create`, `Retrieve`, `Updated`, and `Delete` plugins, and optionally a `Search` plugin. For brevity, we'll just define `Create` and `Retrieve` plugins: >>> from ipalib import crud >>> class user_add(crud.Create): ... pass ... >>> class user_show(crud.Retrieve): ... pass ... Now we'll register the plugins and finalize the `plugable.API` instance: >>> from ipalib import create_api >>> api = create_api() >>> api.register(user) >>> api.register(user_add) >>> api.register(user_show) >>> api.finalize() First, notice that our ``user`` `Object` has the params we defined with the ``takes_params`` tuple: >>> list(api.Object.user.params) ['login', 'first', 'last', 'ipauniqueid'] >>> api.Object.user.params.login Str('login', primary_key=True) Although we defined neither ``takes_args`` nor ``takes_options`` for our ``user_add`` plugin, the `Create` base class automatically generated them for us: >>> list(api.Command.user_add.args) ['login'] >>> list(api.Command.user_add.options) ['first', 'last', 'all', 'raw', 'version'] Notice that ``'ipauniqueid'`` isn't included in the options for our ``user_add`` plugin. This is because of the ``'no_create'`` flag we used when defining the ``ipauniqueid`` param. Often times there are LDAP attributes that are automatically created by the server and therefor should not be supplied as an option to the `Create` plugin. Often these same attributes shouldn't be update-able either, in which case you can also supply the ``'no_update'`` flag, as we did with our ``ipauniqueid`` param. Lastly, you can also use the ``'no_search'`` flag for attributes that shouldn't be search-able (because, for example, the attribute isn't indexed). As with our ``user_add` plugin, we defined neither ``takes_args`` nor ``takes_options`` for our ``user_show`` plugin; instead the `Retrieve` base class created them for us: >>> list(api.Command.user_show.args) ['login'] >>> list(api.Command.user_show.options) ['all', 'raw', 'version'] As you can see, `Retrieve` plugins take a single argument (the primary key) and no options. If needed, you can still specify options for your `Retrieve` plugin with a ``takes_options`` tuple. Flags like ``'no_create'`` remove LDAP attributes from those that can be supplied as *input* to a `Method`, but they don't effect the attributes that can be returned as *output*. Regardless of what flags have been used, the output entry (or list of entries) can contain all the attributes defined on the `Object` plugin (in our case, the above ``user.params``). For example, compare ``user.params`` with ``user_add.output_params`` and ``user_show.output_params``: >>> list(api.Object.user.params) ['login', 'first', 'last', 'ipauniqueid'] >>> list(api.Command.user_add.output_params) ['login', 'first', 'last', 'ipauniqueid'] >>> list(api.Command.user_show.output_params) ['login', 'first', 'last', 'ipauniqueid'] Note that the above are all equal. """ from frontend import Method, Object import backend, frontend, parameters, output class Create(Method): """ Create a new entry. """ has_output = output.standard_entry def get_args(self): if self.obj.primary_key: yield self.obj.primary_key.clone(attribute=True) def get_options(self): if self.extra_options_first: for option in super(Create, self).get_options(): yield option for option in self.obj.params_minus(self.args): attribute = 'virtual_attribute' not in option.flags if 'no_create' in option.flags: continue if 'ask_create' in option.flags: yield option.clone( attribute=attribute, query=False, required=False, autofill=False, alwaysask=True ) else: yield option.clone(attribute=attribute) if not self.extra_options_first: for option in super(Create, self).get_options(): yield option class PKQuery(Method): """ Base class for `Retrieve`, `Update`, and `Delete`. """ def get_args(self): if self.obj.primary_key: # Don't enforce rules on the primary key so we can reference # any stored entry, legal or not yield self.obj.primary_key.clone(attribute=True, query=True) class Retrieve(PKQuery): """ Retrieve an entry by its primary key. """ has_output = output.standard_entry class Update(PKQuery): """ Update one or more attributes on an entry. """ has_output = output.standard_entry def get_options(self): if self.extra_options_first: for option in super(Update, self).get_options(): yield option for option in self.obj.params_minus_pk(): new_flags = option.flags attribute = 'virtual_attribute' not in option.flags if option.required: # Required options turn into non-required, since not specifying # them means that they are not changed. # However, they cannot be empty (i.e. explicitly set to None). new_flags = new_flags.union(['nonempty']) if 'no_update' in option.flags: continue if 'ask_update' in option.flags: yield option.clone( attribute=attribute, query=False, required=False, autofill=False, alwaysask=True, flags=new_flags, ) elif 'req_update' in option.flags: yield option.clone( attribute=attribute, required=True, alwaysask=False, flags=new_flags, ) else: yield option.clone(attribute=attribute, required=False, autofill=False, flags=new_flags, ) if not self.extra_options_first: for option in super(Update, self).get_options(): yield option class Delete(PKQuery): """ Delete one or more entries. """ has_output = output.standard_delete class Search(Method): """ Retrieve all entries that match a given search criteria. """ has_output = output.standard_list_of_entries def get_args(self): yield parameters.Str('criteria?', noextrawhitespace=False) def get_options(self): if self.extra_options_first: for option in super(Search, self).get_options(): yield option for option in self.obj.params_minus(self.args): attribute = 'virtual_attribute' not in option.flags if 'no_search' in option.flags: continue if 'ask_search' in option.flags: yield option.clone( attribute=attribute, query=True, required=False, autofill=False, alwaysask=True ) elif isinstance(option, parameters.Flag): yield option.clone_retype( option.name, parameters.Bool, attribute=attribute, query=True, required=False, autofill=False ) else: yield option.clone( attribute=attribute, query=True, required=False, autofill=False ) if not self.extra_options_first: for option in super(Search, self).get_options(): yield option class CrudBackend(backend.Connectible): """ Base class defining generic CRUD backend API. """ def create(self, **kw): """ Create a new entry. This method should take key word arguments representing the attributes the created entry will have. If this methods constructs the primary_key internally, it should raise an exception if the primary_key was passed. Likewise, if this method requires the primary_key to be passed in from the caller, it should raise an exception if the primary key was *not* passed. This method should return a dict of the exact entry as it was created in the backing store, including any automatically created attributes. """ raise NotImplementedError('%s.create()' % self.name) def retrieve(self, primary_key, attributes): """ Retrieve an existing entry. This method should take a two arguments: the primary_key of the entry in question and a list of the attributes to be retrieved. If the list of attributes is None then all non-operational attributes will be returned. If such an entry exists, this method should return a dict representing that entry. If no such entry exists, this method should return None. """ raise NotImplementedError('%s.retrieve()' % self.name) def update(self, primary_key, **kw): """ Update an existing entry. This method should take one required argument, the primary_key of the entry to modify, plus optional keyword arguments for each of the attributes being updated. This method should return a dict representing the entry as it now exists in the backing store. If no such entry exists, this method should return None. """ raise NotImplementedError('%s.update()' % self.name) def delete(self, primary_key): """ Delete an existing entry. This method should take one required argument, the primary_key of the entry to delete. """ raise NotImplementedError('%s.delete()' % self.name) def search(self, **kw): """ Return entries matching specific criteria. This method should take keyword arguments representing the search criteria. If a key is the name of an entry attribute, the value should be treated as a filter on that attribute. The meaning of keys outside this namespace is left to the implementation. This method should return and iterable containing the matched entries, where each entry is a dict. If no entries are matched, this method should return an empty iterable. """ raise NotImplementedError('%s.search()' % self.name) freeipa-3.3.4/ipalib/session.py0000664000175000017500000014237412202434255016011 0ustar mkosekmkosek# Authors: John Dennis # # Copyright (C) 2011 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 . import memcache import random import errors import os import re import time from urllib2 import urlparse from text import _ from ipapython.ipa_log_manager import * from ipalib import api, errors from ipalib import Command from ipalib.krb_utils import * from ipapython.cookie import Cookie __doc__ = ''' Session Support for IPA John Dennis Goals ===== Provide per-user session data caching which persists between requests. Desired features are: * Integrates cleanly with minimum impact on existing infrastructure. * Provides maximum security balanced against real-world performance demands. * Sessions must be able to be revoked (flushed). * Should be flexible and easy to use for developers. * Should leverage existing technology and code to the maximum extent possible to avoid re-invention, excessive implementation time and to benefit from robustness in field proven components commonly shared in the open source community. * Must support multiple independent processes which share session data. * System must function correctly if session data is available or not. * Must be high performance. * Should not be tied to specific web servers or browsers. Should integrate with our chosen WSGI model. Issues ====== Cookies ------- Most session implementations are based on the use of cookies. Cookies have some inherent problems. * User has the option to disable cookies. * User stored cookie data is not secure. Can be mitigated by setting flags indicating the cookie is only to be used with SSL secured HTTP connections to specific web resources and setting the cookie to expire at session termination. Most modern browsers enforce these. Where to store session data? ---------------------------- Session data may be stored on either on the client or on the server. Storing session data on the client addresses the problem of session data availability when requests are serviced by independent web servers because the session data travels with the request. However there are data size limitations. Storing session data on the client also exposes sensitive data but this can be mitigated by encrypting the session data such that only the server can decrypt it. The more conventional approach is to bind session data to a unique name, the session ID. The session ID is transmitted to the client and the session data is paired with the session ID on the server in a associative data store. The session data is retrieved by the server using the session ID when the receiving the request. This eliminates exposing sensitive session data on the client along with limitations on data size. It however introduces the issue of session data availability when requests are serviced by more than one server process. Multi-process session data availability --------------------------------------- Apache (and other web servers) fork child processes to handle requests in parallel. Also web servers may be deployed in a farm where requests are load balanced in round robin fashion across different nodes. In both cases session data cannot be stored in the memory of a server process because it is not available to other processes, either sibling children of a master server process or server processes on distinct nodes. Typically this is addressed by storing session data in a SQL database. When a request is received by a server process containing a session ID in it's cookie data the session ID is used to perform a SQL query and the resulting data is then attached to the request as it proceeds through the request processing pipeline. This of course introduces coherency issues. For IPA the introduction of a SQL database dependency is undesired and should be avoided. Session data may also be shared by independent processes by storing the session data in files. An alternative solution which has gained considerable popularity recently is the use of a fast memory based caching server. Data is stored in a single process memory and may be queried and set via a light weight protocol using standard socket mechanisms, memcached is one example. A typical use is to optimize SQL queries by storing a SQL result in shared memory cache avoiding the more expensive SQL operation. But the memory cache has distinct advantages in non-SQL situations as well. Possible implementations for use by IPA ======================================= Apache Sessions --------------- Apache has 2.3 has implemented session support via these modules: mod_session Overarching session support based on cookies. See: http://httpd.apache.org/docs/2.3/mod/mod_session.html mod_session_cookie Stores session data in the client. See: http://httpd.apache.org/docs/2.3/mod/mod_session_cookie.html mod_session_crypto Encrypts session data for security. Encryption key is shared configuration parameter visible to all Apache processes and is stored in a configuration file. See: http://httpd.apache.org/docs/2.3/mod/mod_session_crypto.html mod_session_dbd Stores session data in a SQL database permitting multiple processes to access and share the same session data. See: http://httpd.apache.org/docs/2.3/mod/mod_session_dbd.html Issues with Apache sessions ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Although Apache has implemented generic session support and Apache is our web server of preference it nonetheless introduces issues for IPA. * Session support is only available in httpd >= 2.3 which at the time of this writing is currently only available as a Beta release from upstream. We currently only ship httpd 2.2, the same is true for other distributions. * We could package and ship the sessions modules as a temporary package in httpd 2.2 environments. But this has the following consequences: - The code has to be backported. the module API has changed slightly between httpd 2.2 and 2.3. The backporting is not terribly difficult and a proof of concept has been implemented. - We would then be on the hook to package and maintain a special case Apache package. This is maintenance burden as well as a distribution packaging burden. Both of which would be best avoided if possible. * The design of the Apache session modules is such that they can only be manipulated by other Apache modules. The ability of consumers of the session data to control the session data is simplistic, constrained and static during the period the request is processed. Request handlers which are not native Apache modules (e.g. IPA via WSGI) can only examine the session data via request headers and reset it in response headers. * Shared session data is available exclusively via SQL. However using the 2.3 Apache session modules would give us robust session support implemented in C based on standardized Apache interfaces which are widely used. Python Web Frameworks --------------------- Virtually every Python web framework supports cookie based sessions, e.g. Django, Twisted, Zope, Turbogears etc. Early on in IPA we decided to avoid the use of these frameworks. Trying to pull in just one part of these frameworks just to get session support would be problematic because the code does not function outside it's framework. IPA implemented sessions ------------------------ Originally it was believed the path of least effort was to utilize existing session support, most likely what would be provided by Apache. However there are enough basic modular components available in native Python and other standard packages it should be possible to provide session support meeting the aforementioned goals with a modest implementation effort. Because we're leveraging existing components the implementation difficulties are subsumed by other components which have already been field proven and have community support. This is a smart strategy. Proposed Solution ================= Our interface to the web server is via WSGI which invokes a callback per request passing us an environmental context for the request. For this discussion we'll name the WSGI callback "application()", a conventional name in WSGI parlance. Shared session data will be handled by memcached. We will create one instance of memcached on each server node dedicated to IPA exclusively. Communication with memcached will be via a UNIX socket located in the file system under /var/run/ipa_memcached. It will be protected by file permissions and optionally SELinux policy. In application() we examine the request cookies and if there is an IPA session cookie with a session ID we retrieve the session data from our memcached instance. The session data will be a Python dict. IPA components will read or write their session information by using a pre-agreed upon name (e.g. key) in the dict. This is a very flexible system and consistent with how we pass data in most parts of IPA. If the session data is not available an empty session data dict will be created. How does this session data travel with the request in the IPA pipeline? In IPA we use the HTTP request/response to implement RPC. In application() we convert the request into a procedure call passing it arguments derived from the HTTP request. The passed parameters are specific to the RPC method being invoked. The context the RPC call is executing in is not passed as an RPC parameter. How would the contextual information such as session data be bound to the request and hence the RPC call? In IPA when a RPC invocation is being prepared from a request we recognize this will only ever be processed serially by one Python thread. A thread local dict called "context" is allocated for each thread. The context dict is cleared in between requests (e.g. RPC method invocations). The per-thread context dict is populated during the lifetime of the request and is used as a global data structure unique to the request that various IPA component can read from and write to with the assurance the data is unique to the current request and/or method call. The session data dict will be written into the context dict under the session key before the RPC method begins execution. Thus session data can be read and written by any IPA component by accessing ``context.session``. When the RPC method finishes execution the session data bound to the request/method is retrieved from the context and written back to the memcached instance. The session ID is set in the response sent back to the client in the ``Set-Cookie`` header along with the flags controlling it's usage. Issues and details ------------------ IPA code cannot depend on session data being present, however it should always update session data with the hope it will be available in the future. Session data may not be available because: * This is the first request from the user and no session data has been created yet. * The user may have cookies disabled. * The session data may have been flushed. memcached operates with a fixed memory allocation and will flush entries on a LRU basis, like with any cache there is no guarantee of persistence. Also we may have have deliberately expired or deleted session data, see below. Cookie manipulation is done via the standard Python Cookie module. Session cookies will be set to only persist as long as the browser has the session open. They will be tagged so the browser only returns the session ID on SSL secured HTTP requests. They will not be visible to Javascript in the browser. Session ID's will be created by using 48 bits of random data and converted to 12 hexadecimal digits. Newly generated session ID's will be checked for prior existence to handle the unlikely case the random number repeats. memcached will have significantly higher performance than a SQL or file based storage solution. Communication is effectively though a pipe (UNIX socket) using a very simple protocol and the data is held entirely in process memory. memcached also scales easily, it is easy to add more memcached processes and distribute the load across them. At this point in time we don't anticipate the need for this. A very nice feature of the Python memcached module is that when a data item is written to the cache it is done with standard Python pickling (pickling is a standard Python mechanism to marshal and unmarshal Python objects). We adopt the convention the object written to cache will be a dict to meet our internal data handling conventions. The pickling code will recursively handle nested objects in the dict. Thus we gain a lot of flexibility using standard Python data structures to store and retrieve our session data without having to author and debug code to marshal and unmarshal the data if some other storage mechanism had been used. This is a significant implementation win. Of course some common sense limitations need to observed when deciding on what is written to the session cache keeping in mind the data is shared between processes and it should not be excessively large (a configurable option) We can set an expiration on memcached entries. We may elect to do that to force session data to be refreshed periodically. For example we may wish the client to present fresh credentials on a periodic basis even if the cached credentials are otherwise within their validity period. We can explicitly delete session data if for some reason we believe it is stale, invalid or compromised. memcached also gives us certain facilities to prevent race conditions between different processes utilizing the cache. For example you can check of the entry has been modified since you last read it or use CAS (Check And Set) semantics. What has to be protected in terms of cache coherency will likely have to be determined as the session support is utilized and different data items are added to the cache. This is very much data and context specific. Fortunately memcached operations are atomic. Controlling the memcached process --------------------------------- We need a mechanism to start the memcached process and secure it so that only IPA components can access it. Although memcached ships with both an initscript and systemd unit files those are for generic instances. We want a memcached instance dedicated exclusively to IPA usage. To accomplish this we would install a systemd unit file or an SysV initscript to control the IPA specific memcached service. ipactl would be extended to know about this additional service. systemd's cgroup facility would give us additional mechanisms to integrate the IPA memcached service within a larger IPA process group. Protecting the memcached data would be done via file permissions (and optionally SELinux policy) on the UNIX domain socket. Although recent implementations of memcached support authentication via SASL this introduces a performance and complexity burden not warranted when cached is dedicated to our exclusive use and access controlled by OS mechanisms. Conventionally daemons are protected by assigning a system uid and/or gid to the daemon. A daemon launched by root will drop it's privileges by assuming the effective uid:gid assigned to it. File system access is controlled by the OS via the effective identity and SELinux policy can be crafted based on the identity. Thus the memcached UNIX socket would be protected by having it owned by a specific system user and/or membership in a restricted system group (discounting for the moment SELinux). Unfortunately we currently do not have an IPA system uid whose identity our processes operate under nor do we have an IPA system group. IPA does manage a collection of related processes (daemons) and historically each has been assigned their own uid. When these unrelated processes communicate they mutually authenticate via other mechanisms. We do not have much of a history of using shared file system objects across identities. When file objects are created they are typically assigned the identity of daemon needing to access the object and are not accessed by other daemons, or they carry root identity. When our WSGI application runs in Apache it is run as a WSGI daemon. This means when Apache starts up it forks off WSGI processes for us and we are independent of other Apache processes. When WSGI is run in this mode there is the ability to set the uid:gid of the WSGI process hosting us, however we currently do not take advantage of this option. WSGI can be run in other modes as well, only in daemon mode can the uid:gid be independently set from the rest of Apache. All processes started by Apache can be set to a common uid:gid specified in the global Apache configuration, by default it's apache:apache. Thus when our IPA code executes it is running as apache:apache. To protect our memcached UNIX socket we can do one of two things: 1. Assign it's uid:gid as apache:apache. This would limit access to our cache only to processes running under httpd. It's somewhat restricted but far from ideal. Any code running in the web server could potentially access our cache. It's difficult to control what the web server runs and admins may not understand the consequences of configuring httpd to serve other things besides IPA. 2. Create an IPA specific uid:gid, for example ipa:ipa. We then configure our WSGI application to run as the ipa:ipa user and group. We also configure our memcached instance to run as the ipa:ipa user and group. In this configuration we are now fully protected, only our WSGI code can read & write to our memcached UNIX socket. However there may be unforeseen issues by converting our code to run as something other than apache:apache. This would require some investigation and testing. IPA is dependent on other system daemons, specifically Directory Server (ds) and Certificate Server (cs). Currently we configure ds to run under the dirsrv:dirsrv user and group, an identity of our creation. We allow cs to default to it's pkiuser:pkiuser user and group. Should these other cooperating daemons also run under the common ipa:ipa user and group identities? At first blush there would seem to be an advantage to coalescing all process identities under a common IPA user and group identity. However these other processes do not depend on user and group permissions when working with external agents, processes, etc. Rather they are designed to be stand-alone network services which authenticate their clients via other mechanisms. They do depend on user and group permission to manage their own file system objects. If somehow the ipa user and/or group were compromised or malicious code somehow executed under the ipa identity there would be an advantage in having the cooperating processes cordoned off under their own identities providing one extra layer of protection. (Note, these cooperating daemons may not even be co-located on the same node in which case the issue is moot) The UNIX socket behavior (ldapi) with Directory Server is as follows: * The socket ownership is: root:root * The socket permissions are: 0666 * When connecting via ldapi you must authenticate as you would normally with a TCP socket, except ... * If autobind is enabled and the uid:gid is available via SO_PEERCRED and the uid:gid can be found in the set of users known to the Directory Server then that connection will be bound as that user. * Otherwise an anonymous bind will occur. memcached UNIX socket behavior is as follows: * memcached can be invoked with a user argument, no group may be specified. The effective uid is the uid of the user argument and the effective gid is the primary group of the user, let's call this euid:egid * The socket ownership is: euid:egid * The socket permissions are 0700 by default, but this can be modified by the -a mask command line arg which sets the umask (defaults to 0700). Overview of authentication in IPA ================================= This describes how we currently authenticate and how we plan to improve authentication performance. First some definitions. There are 4 major players: 1. client 2. mod_auth_kerb (in Apache process) 3. wsgi handler (in IPA wsgi python process) 4. ds (directory server) There are several resources: 1. /ipa/ui (unprotected, web UI static resources) 2. /ipa/xml (protected, xmlrpc RPC used by command line clients) 3. /ipa/json (protected, json RPC used by javascript in web UI) 4. ds (protected, wsgi acts as proxy, our LDAP server) Current Model ------------- This describes how things work in our current system for the web UI. 1. Client requests /ipa/ui, this is unprotected, is static and contains no sensitive information. Apache replies with html and javascript. The javascript requests /ipa/json. 2. Client sends post to /ipa/json. 3. mod_auth_kerb is configured to protect /ipa/json, replies 401 authenticate negotiate. 4. Client resends with credentials 5. mod_auth_kerb validates credentials a. if invalid replies 403 access denied (stops here) b. if valid creates temporary ccache, adds KRB5CCNAME to request headers 6. Request passed to wsgi handler a. validates request, KRB5CCNAME must be present, referrer, etc. b. ccache saved and used to bind to ds c. routes to specified RPC handler. 7. wsgi handler replies to client Proposed new session based optimization --------------------------------------- The round trip negotiate and credential validation in steps 3,4,5 is expensive. This can be avoided if we can cache the client credentials. With client sessions we can store the client credentials in the session bound to the client. A few notes about the session implementation. * based on session cookies, cookies must be enabled * session cookie is secure, only passed on secure connections, only passed to our URL resource, never visible to client javascript etc. * session cookie has a session id which is used by wsgi handler to retrieve client session data from shared multi-process cache. Changes to Apache's resource protection --------------------------------------- * /ipa/json is no longer protected by mod_auth_kerb. This is necessary to avoid the negotiate expense in steps 3,4,5 above. Instead the /ipa/json resource will be protected in our wsgi handler via the session cookie. * A new protected URI is introduced, /ipa/login. This resource does no serve any data, it is used exclusively for authentication. The new sequence is: 1. Client requests /ipa/ui, this is unprotected. Apache replies with html and javascript. The javascript requests /ipa/json. 2. Client sends post to /ipa/json, which is unprotected. 3. wsgi handler obtains session data from session cookie. a. if ccache is present in session data and is valid - request is further validated - ccache is established for bind to ds - request is routed to RPC handler - wsgi handler eventually replies to client b. if ccache is not present or not valid processing continues ... 4. wsgi handler replies with 401 Unauthorized 5. client sends request to /ipa/login to obtain session credentials 6. mod_auth_kerb replies 401 negotiate on /ipa/login 7. client sends credentials to /ipa/login 8. mod_auth_kerb validates credentials a. if valid - mod_auth_kerb permits access to /ipa/login. wsgi handler is invoked and does the following: * establishes session for client * retrieves the ccache from KRB5CCNAME and stores it a. if invalid - mod_auth_kerb sends 403 access denied (processing stops) 9. client now posts the same data again to /ipa/json including session cookie. Processing repeats starting at step 2 and since the session data now contains a valid ccache step 3a executes, a successful reply is sent to client. Command line client using xmlrpc -------------------------------- The above describes the web UI utilizing the json RPC mechanism. The IPA command line tools utilize a xmlrpc RPC mechanism on the same HTTP server. Access to the xmlrpc is via the /ipa/xml URI. The json and xmlrpc API's are the same, they differ only on how their procedure calls are marshalled and unmarshalled. Under the new scheme /ipa/xml will continue to be Kerberos protected at all times. Apache's mod_auth_kerb will continue to require the client provides valid Kerberos credentials. When the WSGI handler routes to /ipa/xml the Kerberos credentials will be extracted from the KRB5CCNAME environment variable as provided by mod_auth_kerb. Everything else remains the same. ''' #------------------------------------------------------------------------------- default_max_session_duration = 60*60 # number of seconds ISO8601_DATETIME_FMT = '%Y-%m-%dT%H:%M:%S' # FIXME, this should be defined elsewhere def fmt_time(timestamp): return time.strftime(ISO8601_DATETIME_FMT, time.localtime(timestamp)) #------------------------------------------------------------------------------- class AuthManager(object): ''' This class is an abstract base class and is meant to be subclassed to provide actual functionality. The purpose is to encapsulate all the callbacks one might need to manage authenticaion. Different authentication mechanisms will instantiate a subclass of this and register it with the SessionAuthManger. When an authentication event occurs the matching method will be called for each registered class. This allows the SessionAuthManager to notify interested parties. ''' def __init__(self, name): log_mgr.get_logger(self, True) self.name = name def logout(self, session_data): ''' Called when a user requests to be logged out of their session. :parameters: session_data The current session data :returns: None ''' self.debug('AuthManager.logout.%s:', self.name) class SessionAuthManager(object): ''' ''' def __init__(self): ''' ''' log_mgr.get_logger(self, True) self.auth_managers = {} def register(self, name, auth_mgr): self.debug('SessionAuthManager.register: name=%s', name) existing_mgr = self.auth_managers.get(name) if existing_mgr is not None: raise KeyError('cannot register auth manager named "%s" one already exists, name="%s" object=%s', name, existing_mgr.name, repr(existing_mgr)) if not isinstance(auth_mgr, AuthManager): raise TypeError('auth_mgr must be an instance of AuthManager, not %s', auth_mgr.__class__.__name__) self.auth_managers[name] = auth_mgr def unregister(self, name): self.debug('SessionAuthManager.unregister: name=%s', name) if not self.auth_managers.has_key(name): raise KeyError('cannot unregister auth manager named "%s", does not exist', name) del self.auth_managers[name] def logout(self, session_data): ''' ''' self.debug('SessionAuthManager.logout:') for auth_mgr in self.auth_managers.values(): try: auth_mgr.logout(session_data) except Exception, e: self.error('%s auth_mgr logout failed: %s', auth_mgr.name, e) #------------------------------------------------------------------------------- class SessionManager(object): ''' This class is used to manage a set of sessions. Each client connecting to the server is assigned a session id wich is then used to store data bound to the client's session in between server requests. ''' def __init__(self): ''' :returns: `SessionManager` object ''' log_mgr.get_logger(self, True) self.generated_session_ids = set() self.auth_mgr = SessionAuthManager() def generate_session_id(self, n_bits=128): ''' Return a random string to be used as a session id. This implementation creates a string of hexadecimal digits. There is no guarantee of uniqueness, it is the caller's responsibility to validate the returned id is not currently in use. :parameters: n_bits number of bits of random data, will be rounded to next highest multiple of 4 :returns: string of random hexadecimal digits ''' # round up to multiple of 4 n_bits = (n_bits + 3) & ~3 session_id = '%0*x' % (n_bits >> 2, random.getrandbits(n_bits)) return session_id def new_session_id(self, max_retries=5): ''' Returns a new *unique* session id. See `generate_session_id()` for how the session id's are formulated. The scope of the uniqueness of the id is limited to id's generated by this instance of the `SessionManager`. :parameters: max_retries Maximum number of attempts to produce a unique id. :returns: Unique session id as a string. ''' n_retries = 0 while n_retries < max_retries: session_id = self.generate_session_id() if not session_id in self.generated_session_ids: break n_retries += 1 if n_retries >= max_retries: self.error('could not allocate unique new session_id, %d retries exhausted', n_retries) raise errors.ExecutionError(message=_('could not allocate unique new session_id')) self.generated_session_ids.add(session_id) return session_id class MemcacheSessionManager(SessionManager): ''' This class is used to assign a session id to a HTTP server client and then store client specific data associated with the session in a memcached memory cache instance. Multiple processes may share the memory cache permitting session data to be shared between forked HTTP server children handling server requests. The session id is guaranteed to be unique. The session id is set into a session cookie returned to the client and is secure (see `generate_cookie()`). Future requests from the client will send the session id which is then used to retrieve the session data (see `load_session_data()`) ''' memcached_socket_path = '/var/run/ipa_memcached/ipa_memcached' session_cookie_name = 'ipa_session' mc_server_stat_name_re = re.compile(r'(.+)\s+\((\d+)\)') def __init__(self): ''' :returns: `MemcacheSessionManager` object. ''' super(MemcacheSessionManager, self).__init__() self.servers = ['unix:%s' % self.memcached_socket_path] self.mc = memcache.Client(self.servers, debug=0) if not self.servers_running(): self.warning("session memcached servers not running") def get_server_statistics(self): ''' Return memcached server statistics. Return value is a dict whose keys are server names and whose value is a dict of key/value statistics as returned by the memcached server. :returns: dict of server names, each value is dict of key/value server statistics. ''' result = {} stats = self.mc.get_stats() for server in stats: match = self.mc_server_stat_name_re.search(server[0]) if match: name = match.group(1) result[name] = server[1] else: self.warning('unparseable memcached server name "%s"', server[0]) return result def servers_running(self): ''' Check if all configured memcached servers are running and can be communicated with. :returns: True if at least one server is configured and all servers can respond, False otherwise. ''' if len(self.servers) == 0: return False stats = self.get_server_statistics() return len(self.servers) == len(stats) def new_session_id(self, max_retries=5): ''' Returns a new *unique* session id. See `generate_session_id()` for how the session id's are formulated. The scope of the uniqueness of the id is limited to id's generated by this instance of the `SessionManager` and session id's currently stored in the memcache instance. :parameters: max_retries Maximum number of attempts to produce a unique id. :returns: Unique session id as a string. ''' n_retries = 0 while n_retries < max_retries: session_id = super(MemcacheSessionManager, self).new_session_id(max_retries) session_data = self.get_session_data(session_id) if session_data is None: break n_retries += 1 if n_retries >= max_retries: self.error('could not allocate unique new session_id, %d retries exhausted', n_retries) raise errors.ExecutionError(message=_('could not allocate unique new session_id')) return session_id def new_session_data(self, session_id): ''' Return a new session data dict. The session data will be associated with it's session id. The dict will be pre-populated with: session_id The session ID used to identify this session data. session_start_timestamp Timestamp when this session was created. session_access_timestamp Timestamp when the session was last accessed. session_expiration_timestamp Timestamp when session expires. Defaults to zero which implies no expiration. See `set_session_expiration_time()`. :parameters: session_id The session id used to look up this session data. :returns: Session data dict populated with a session_id key. ''' now = time.time() return {'session_id' : session_id, 'session_start_timestamp' : now, 'session_access_timestamp' : now, 'session_expiration_timestamp' : 0, } def session_key(self, session_id): ''' Given a session id return a memcache key used to look up the session data in the memcache. :parameters: session_id The session id from which the memcache key will be derived. :returns: A key (string) used to look up the session data in the memcache. ''' return 'ipa.session.%s' % (session_id) def get_session_data(self, session_id): ''' Given a session id retrieve the session data associated with it. If no session data exists for the session id return None. :parameters: session_id The session id whose session data is desired. :returns: Session data if found, None otherwise. ''' session_key = self.session_key(session_id) session_data = self.mc.get(session_key) if session_data is not None: # update the access timestamp now = time.time() session_data['session_access_timestamp'] = now return session_data def get_session_id_from_http_cookie(self, cookie_header): ''' Parse an HTTP cookie header and search for our session id. Return the session id if found, return None if not found. :parameters: cookie_header An HTTP cookie header. May be None, if None return None. :returns: Session id as string or None if not found. ''' if cookie_header is None: return None session_id = None try: session_cookie = Cookie.get_named_cookie_from_string(cookie_header, self.session_cookie_name) except Exception, e: session_cookie = None if session_cookie: session_id = session_cookie.value if session_id is None: self.debug('no session cookie found') else: self.debug('found session cookie_id = %s', session_id) return session_id def load_session_data(self, cookie_header): ''' Parse an HTTP cookie header looking for our session information. * If no session id is found then a new session id and new session data dict will be generated, stored in the memcache and returned. The new session data dict will contain the new session id. * If the session id is found in the cookie an attempt is made to retrieve the session data from the memcache using the session id. - If existing session data is found in the memcache it is returned. - If no session data is found in the memcache then a new session data dict will be generated, stored in the memcache and returned. The new session data dict will contain the session id found in the cookie header. :parameters: cookie_header An HTTP cookie header. May be None. :returns: Session data dict containing at a minimum the session id it is bound to. ''' session_id = self.get_session_id_from_http_cookie(cookie_header) if session_id is None: session_id = self.new_session_id() self.debug('no session id in request, generating empty session data with id=%s', session_id) session_data = self.new_session_data(session_id) self.store_session_data(session_data) return session_data else: session_data = self.get_session_data(session_id) if session_data is None: self.debug('no session data in cache with id=%s, generating empty session data', session_id) session_data = self.new_session_data(session_id) self.store_session_data(session_data) return session_data else: self.debug('found session data in cache with id=%s', session_id) return session_data def store_session_data(self, session_data): ''' Store the supplied session_data dict in the memcached instance. The session_expiration_timestamp is always passed to memcached when the session data is written back to the memcache. This is because otherwise the memcache expiration will default to zero if it's not specified which implies no expiration. Thus a failure to specify an exiration time when writing an item to memcached will cause a previously set expiration time for the item to be discarded and the item will no longer expire. :parameters: session_data Session data dict, must contain session_id key. :returns: session_id ''' session_id = session_data['session_id'] session_key = self.session_key(session_id) # update the access timestamp now = time.time() session_data['session_access_timestamp'] = now session_expiration_timestamp = session_data['session_expiration_timestamp'] self.debug('store session: session_id=%s start_timestamp=%s access_timestamp=%s expiration_timestamp=%s', session_id, fmt_time(session_data['session_start_timestamp']), fmt_time(session_data['session_access_timestamp']), fmt_time(session_data['session_expiration_timestamp'])) self.mc.set(session_key, session_data, time=session_expiration_timestamp) return session_id def generate_cookie(self, url_path, session_id, expiration=None, add_header=False): ''' Return a session cookie containing the session id. The cookie will be contrainted to the url path, defined for use with HTTP only, and only returned on secure connections (SSL). :parameters: url_path The cookie will be returned in a request if it begins with this url path. session_id The session id identified by the session cookie add_header If true format cookie string with Set-Cookie: header :returns: cookie string ''' if not expiration: # Catch zero unix timestamps expiration = None; cookie = Cookie(self.session_cookie_name, session_id, domain=urlparse.urlparse(api.env.xmlrpc_uri).netloc, path=url_path, httponly=True, secure=True, expires=expiration) if add_header: result = 'Set-Cookie: %s' % cookie else: result = str(cookie) return result def set_session_expiration_time(self, session_data, duration=default_max_session_duration, max_age=None, duration_type='inactivity_timeout'): ''' memcached permits setting an expiration time on entries. The expiration time may either be Unix time (number of seconds since January 1, 1970, as a 32-bit value), or a number of seconds starting from current time. In the latter case, this number of seconds may not exceed 60*60*24*30 (number of seconds in 30 days); if the number sent by a client is larger than that, the server will consider it to be real Unix time value rather than an offset from current time. We never use the duration value (< 30 days), we always use a timestamp, this makes it easier to integrate with other time constraints. When a session is created it's start time is recorded in the session data as the session_start_timestamp value. There are two ways the expiration timestamp can be computed: from_start A session has a fixed duration beginning with the start of the session. The session expires when the duration interval has elapsed relative to the start of the session. inactivity_timeout A session times out after a period of inactivity. The expiration time is advanced by the value of the duration interval everytime the session is updated. After the expiration is computed it may be capped at a maximum value due to other constraints (e.g. authentication credential expiration). If the optional max_age parameter is specified then expiration is constrained to be not greater than the max_age. The final computed expiration is then written into the session_data as the session_expiration_timestamp value. The session_expiration_timestamp is always passed to memcached when the session data is written back to the memcache. This is because otherwise the memcache expiration will default to zero if it's not specified which implies no expiration. Thus a failure to specify an exiration time when writing an item to memcached will cause a previously set expiration time for the item to be discarded and the item will no longer expire. :parameters: session_data Session data dict, must contain session_id key. duration Number of seconds cache entry should live. This is a duration value, not a timestamp. Zero implies no expiration. max_age Unix time value when cache entry must expire by. :returns: expiration timestamp, zero implies no expiration ''' if duration == 0 and max_age is None: # No expiration expiration = 0 session_data['session_expiration_timestamp'] = expiration return expiration if duration_type == 'inactivity_timeout': now = time.time() session_data['session_access_timestamp'] = now expiration = now + duration elif duration_type == 'from_start': session_start_timestamp = session_data['session_start_timestamp'] expiration = session_start_timestamp + duration else: # Don't throw an exception, it's critical the session be # given some expiration, instead log the error and execute # a default action of expiring the session 5 minutes after # it was initiated (similar to from_start but with # hardcoded duration) default = 60*5 self.warning('unknown session duration_type (%s), defaulting to %s seconds from session start', duration_type, default) session_start_timestamp = session_data['session_start_timestamp'] expiration = session_start_timestamp + default # Cap the expiration if max_age is specified if max_age is not None: expiration = min(expiration, max_age) session_data['session_expiration_timestamp'] = expiration self.debug('set_session_expiration_time: duration_type=%s duration=%s max_age=%s expiration=%s (%s)', duration_type, duration, max_age, expiration, fmt_time(expiration)) return expiration def delete_session_data(self, session_id): ''' Given a session id removed the session data bound to the id from the memcache. :parameters: session_id The ID of the session which should be removed from the cache. :returns: None ''' session_key = self.session_key(session_id) self.debug('delete session data from memcache, session_id=%s', session_id) self.mc.delete(session_key) #------------------------------------------------------------------------------- krbccache_dir ='/var/run/ipa_memcached' krbccache_prefix = 'krbcc_' def _get_krbccache_pathname(): return os.path.join(krbccache_dir, '%s%s' % (krbccache_prefix, os.getpid())) def get_ipa_ccache_name(scheme='FILE'): if scheme == 'FILE': name = os.path.join(krbccache_dir, '%s%s' % (krbccache_prefix, os.getpid())) else: raise ValueError('ccache scheme "%s" unsupported', scheme) ccache_name = krb5_unparse_ccache(scheme, name) return ccache_name def load_ccache_data(ccache_name): scheme, name = krb5_parse_ccache(ccache_name) if scheme == 'FILE': root_logger.debug('reading ccache data from file "%s"', name) src = open(name) ccache_data = src.read() src.close() return ccache_data else: raise ValueError('ccache scheme "%s" unsupported (%s)', scheme, ccache_name) def bind_ipa_ccache(ccache_data, scheme='FILE'): if scheme == 'FILE': name = _get_krbccache_pathname() root_logger.debug('storing ccache data into file "%s"', name) dst = open(name, 'w') dst.write(ccache_data) dst.close() else: raise ValueError('ccache scheme "%s" unsupported', scheme) ccache_name = krb5_unparse_ccache(scheme, name) os.environ['KRB5CCNAME'] = ccache_name return ccache_name def release_ipa_ccache(ccache_name): ''' Stop using the current request's ccache. * Remove KRB5CCNAME from the enviroment * Remove the ccache file from the file system Note, we do not demand any of these elements exist, but if they do we'll remove them. ''' if os.environ.has_key('KRB5CCNAME'): if ccache_name != os.environ['KRB5CCNAME']: root_logger.error('release_ipa_ccache: ccache_name (%s) != KRB5CCNAME environment variable (%s)', ccache_name, os.environ['KRB5CCNAME']) del os.environ['KRB5CCNAME'] else: root_logger.debug('release_ipa_ccache: KRB5CCNAME environment variable not set') scheme, name = krb5_parse_ccache(ccache_name) if scheme == 'FILE': if os.path.exists(name): try: os.unlink(name) except Exception, e: root_logger.error('unable to delete session ccache file "%s", %s', name, e) else: raise ValueError('ccache scheme "%s" unsupported (%s)', scheme, ccache_name) #------------------------------------------------------------------------------- from ipalib.request import context class session_logout(Command): ''' RPC command used to log the current user out of their session. ''' def execute(self, *args, **options): session_data = getattr(context, 'session_data', None) if session_data is None: self.debug('session logout command: no session_data found') else: session_id = session_data.get('session_id') self.debug('session logout command: session_id=%s', session_id) # Notifiy registered listeners session_mgr.auth_mgr.logout(session_data) return dict(result=None) api.register(session_logout) #------------------------------------------------------------------------------- session_mgr = MemcacheSessionManager() freeipa-3.3.4/ipalib/parameters.pyc0000664000175000017500000017757112271707517016655 0ustar mkosekmkosekó †fçRc@sàdZddlZddlZddlZddlmZmZddlmZddl m Z ddl m Z mZmZddlmZmZmZddlmZmZdd lmZmZmZdd l mZmZdd lmZdd lmZd e fd„ƒYZ d„Z!e"ƒZ#d„Z de fd„ƒYZ$de$fd„ƒYZ%de%fd„ƒYZ&de$fd„ƒYZ'de'fd„ƒYZ(de'fd„ƒYZ)de$fd„ƒYZ*de*fd „ƒYZ+d!e*fd"„ƒYZ,d#e,fd$„ƒYZ-d%e,fd&„ƒYZ.d'e$fd(„ƒYZ/d)e/fd*„ƒYZ0d+e/fd,„ƒYZ1d-e$fd.„ƒYZ2d/e,fd0„ƒYZ3d1e,fd2„ƒYZ4d3e$fd4„ƒYZ5d5e2fd6„ƒYZ6d7„Z7dS(8s7 Parameter system for command plugins. A `Param` instance can be used to describe an argument or option that a command takes, or an attribute that a command returns. The `Param` base class is not used directly, but there are many subclasses for specific Python data types (like `Str` or `Int`) and specific properties (like `Password`). To create a `Param` instance, you must always provide the parameter *name*, which should be the LDAP attribute name if the parameter describes the attribute of an LDAP entry. For example, we could create an `Str` instance describing the user's last-name attribute like this: >>> from ipalib import Str >>> sn = Str('sn') >>> sn.name 'sn' When creating a `Param`, there are also a number of optional kwargs which which can provide additional meta-data and functionality. For example, every parameter has a *cli_name*, the name used on the command-line-interface. By default the *cli_name* is the same as the *name*: >>> sn.cli_name 'sn' But often the LDAP attribute name isn't user friendly for the command-line, so you can override this with the *cli_name* kwarg: >>> sn = Str('sn', cli_name='last') >>> sn.name 'sn' >>> sn.cli_name 'last' Note that the RPC interfaces (and the internal processing pipeline) always use the parameter *name*, regardless of what the *cli_name* might be. A `Param` also has two translatable kwargs: *label* and *doc*. These must both be `Gettext` instances. They both default to a place-holder `FixMe` instance, a subclass of `Gettext` used to mark a missing translatable string: >>> sn.label FixMe('sn') >>> sn.doc FixMe('sn') The *label* is a short phrase describing the parameter. It's used on the CLI when interactively prompting for values, and as a label for form inputs in the web-UI. The *label* should start with an initial capital. For example: >>> from ipalib import _ >>> sn = Str('sn', ... cli_name='last', ... label=_('Last name'), ... ) >>> sn.label Gettext('Last name', domain='ipa', localedir=None) The *doc* is a longer description of the parameter. It's used on the CLI when displaying the help information for a command, and as extra instruction for a form input on the web-UI. By default the *doc* is the same as the *label*: >>> sn.doc Gettext('Last name', domain='ipa', localedir=None) But you can override this with the *doc* kwarg. Like the *label*, the *doc* should also start with an initial capital and should not end with any punctuation. For example: >>> sn = Str('sn', ... cli_name='last', ... label=_('Last name'), ... doc=_("The user's last name"), ... ) >>> sn.doc Gettext("The user's last name", domain='ipa', localedir=None) Demonstration aside, you should always provide at least the *label* so the various UIs are translatable. Only provide the *doc* if the parameter needs a more detailed description for clarity. iÿÿÿÿN(tMAXINTtMININT(tNoneType(t_(tReadOnlytlockt check_name(tConversionErrortRequirementErrortValidationError(tPasswordMismatchtBase64DecodeError(tNULLSt TYPE_ERRORtCALLABLE_ERROR(tGettexttFixMe(tjson_serialize(tDNt DefaultFromcBs)eZdZd„Zd„Zd„ZRS(sË Derive a default value from other supplied values. For example, say you wanted to create a default for the user's login from the user's first and last names. It could be implemented like this: >>> login = DefaultFrom(lambda first, last: first[0] + last) >>> login(first='John', last='Doe') 'JDoe' If you do not explicitly provide keys when you create a `DefaultFrom` instance, the keys are implicitly derived from your callback by inspecting ``callback.func_code.co_varnames``. The keys are available through the ``DefaultFrom.keys`` instance attribute, like this: >>> login.keys ('first', 'last') The callback is available through the ``DefaultFrom.callback`` instance attribute, like this: >>> login.callback # doctest:+ELLIPSIS at 0x...> >>> login.callback.func_code.co_varnames # The keys ('first', 'last') The keys can be explicitly provided as optional positional arguments after the callback. For example, this is equivalent to the ``login`` instance above: >>> login2 = DefaultFrom(lambda a, b: a[0] + b, 'first', 'last') >>> login2.keys ('first', 'last') >>> login2.callback.func_code.co_varnames # Not the keys ('a', 'b') >>> login2(first='John', last='Doe') 'JDoe' If any keys are missing when calling your `DefaultFrom` instance, your callback is not called and ``None`` is returned. For example: >>> login(first='John', lastname='Doe') is None True >>> login() is None True Any additional keys are simply ignored, like this: >>> login(last='Doe', first='John', middle='Whatever') 'JDoe' As above, because `DefaultFrom.__call__` takes only pure keyword arguments, they can be supplied in any order. Of course, the callback need not be a ``lambda`` expression. This third example is equivalent to both the ``login`` and ``login2`` instances above: >>> def get_login(first, last): ... return first[0] + last ... >>> login3 = DefaultFrom(get_login) >>> login3.keys ('first', 'last') >>> login3.callback.func_code.co_varnames ('first', 'last') >>> login3(first='John', last='Doe') 'JDoe' cGsæt|ƒs.ttd|t|ƒfƒ‚n||_t|ƒdkr„|j}|jd@rntdƒ‚n|j |j |_ n ||_ xH|j D]=}t|ƒt k r—tt dt |t|ƒfƒ‚q—q—Wt|ƒdS(s :param callback: The callable to call when all keys are present. :param keys: Optional keys used for source values. tcallbackii s3callback: variable-length argument list not allowedtkeysN(tcallablet TypeErrorRttypeRtlent func_codetco_flagst ValueErrort co_varnamest co_argcountRtstrR R(tselfRRtfctkey((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt__init__¼s     &cCsC|jjftd„|jDƒƒ}d|jjdj|ƒfS(Ncss|]}t|ƒVqdS(N(trepr(t.0tk((s//home/mkosek/freeipa-clean/ipalib/parameters.pys Õss%s(%s)s, (Rt__name__ttupleRt __class__tjoin(R targs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt__repr__Ôs& c sXt‡fd†|jDƒƒ}d|kr/dSy|j|ŒSWntk rSnXdS(sú Call the callback if all keys are present. If all keys are present, the callback is called and its return value is returned. If any keys are missing, ``None`` is returned. :param kw: The keyword arguments. c3s!|]}ˆj|dƒVqdS(N(tgettNone(R%R&(tkw(s//home/mkosek/freeipa-clean/ipalib/parameters.pys äsN(R(RR.Rt StandardError(R R/tvals((R/s//home/mkosek/freeipa-clean/ipalib/parameters.pyt__call__Ûs   (R't __module__t__doc__R#R,R2(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRusE  cCsÀt|ƒtk r7ttdt|t|ƒfƒ‚nitdtdtƒd6tdtdtƒd6tdtdtƒd6}|d}||kr§|d ||fS|tdtdtƒfS(sà Parse shorthand ``spec`` into to ``(name, kw)``. The ``spec`` string determines the parameter name, whether the parameter is required, and whether the parameter is multivalue according the following syntax: ====== ===== ======== ========== Spec Name Required Multivalue ====== ===== ======== ========== 'var' 'var' True False 'var?' 'var' False False 'var*' 'var' False True 'var+' 'var' True True ====== ===== ======== ========== For example, >>> parse_param_spec('login') ('login', {'required': True, 'multivalue': False}) >>> parse_param_spec('gecos?') ('gecos', {'required': False, 'multivalue': False}) >>> parse_param_spec('telephone_numbers*') ('telephone_numbers', {'required': False, 'multivalue': True}) >>> parse_param_spec('group+') ('group', {'required': True, 'multivalue': True}) :param spec: A spec string. tspectrequiredt multivaluet?t*t+iÿÿÿÿ(RRRR tdicttFalsetTrue(R5t_maptend((s//home/mkosek/freeipa-clean/ipalib/parameters.pytparse_param_specís"  cCstj|ƒ|S(N(t __messagestadd(tmessage((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRs tParamcBsôeZdZeZedƒZedƒZded.fded.fde e fd.fde e fd.fde e fde efd e efd ed.fd ed.fd e efd e efde efded.fded.fdeeƒfdee fd.fde efdedfde efded.ffZd„Zd„Zd„Zd„Zd„Zd„Zd„Zd„Zd „Zd!„Zd"„Zd#„Z d$„Z!d%„Z"d.d&„Z#d.d.d'„Z$d.d(„Z%d)„Z&d/Z'd-„Z(RS(0sÇ Base class for all parameters. Param attributes: ================= The behavior of Param class and subclasses can be controlled using the following set of attributes: - cli_name: option name in CLI - cli_short_name: one character version of cli_name - label: very short description of the parameter. This value is used in when the Command output is printed to CLI or in a Command help - doc: parameter long description used in help - required: the parameter is marked as required for given Command - multivalue: indicates if the attribute is multivalued - primary_key: Command's parameter primary key is used for unique identification of an LDAP object and for sorting - normalizer: a custom function for Param value normalization - default_from: a custom function for generating default values of parameter instance - autofill: by default, only `required` parameters get a default value from the default_from function. When autofill is enabled, optional attributes get the default value filled too - query: this attribute is controlled by framework. When the `query` is enabled, framework assumes that the value is only queried and not inserted in the LDAP. Validation is then relaxed - custom parameter validators are skipped and only basic class validators are executed to check the parameter value - attribute: this attribute is controlled by framework and enabled for all LDAP objects parameters (unless parameter has "virtual_attribute" flag). All parameters with enabled `attribute` are being encoded and placed to an entry passed to LDAP Create/Update calls - include: a list of contexts where this parameter should be included. `Param.use_in_context()` provides further information. - exclude: a list of contexts where this parameter should be excluded. `Param.use_in_context()` provides further information. - flags: there are several flags that can be used to further tune the parameter behavior: * no_display (Output parameters only): do not display the parameter * no_create: do not include the parameter for crud.Create based commands * no_update: do not include the parameter for crud.update based commands * no_option: this attribute is not displayed in the CLI, usually because there's a better way of setting it (for example, a separate command) * virtual_attribute: the parameter is not stored physically in the LDAP and thus attribute `attribute` is not enabled * suppress_empty (Output parameters only): do not display parameter value when empty * ask_create: CLI asks for parameter value even when the parameter is not `required`. Applied for all crud.Create based commands * ask_update: CLI asks for parameter value even when the parameter is not `required`. Applied for all crud.Update based commands * req_update: The parameter is `required` in all crud.Update based commands * nonempty: This is an internal flag; a required attribute should be used instead of it. The value of this parameter must not be empty, but it may not be given at all. All crud.Update commands automatically convert required parameters to `nonempty` ones, so the value can be unspecified (unchanged) but cannot be deleted. - hint: this attribute is currently not used - alwaysask: when enabled, CLI asks for parameter value even when the parameter is not `required` - sortorder: used to sort a list of parameters for Command. See `Command.finalize()` for further information - csv: this multivalue attribute used to be given in CSV format in CLI sincorrect typesOnly one value is allowedtcli_nametcli_short_nametlabeltdocR6R7t primary_keyt normalizert default_fromtautofilltqueryt attributetincludetexcludetflagsthintt alwaysaskt sortorderitcsvt option_groupc Os]||_t|ƒ|_t|tƒr3t|_n t|_t|ƒ\}}d|krk|d|d¦scss|]}|dVqdS(iN((R%RX((s//home/mkosek/freeipa-clean/ipalib/parameters.pys §ss%s: takes no such kwargs: %ss, css|]}t|ƒVqdS(N(R$(R%R&((s//home/mkosek/freeipa-clean/ipalib/parameters.pys ªsRERGRHRKs'kwarg %r conflicts with attribute on %ss_rule_%ss$%s: cannot have both %s=%r and %s=%rRORPs&%s: cannot have csv without multivalues"%s: rules must be callable; got %ris5%s: cli_short_name can only be a single character: %s((3t param_specR;t _Param__kwt isinstancetPasswordR=tpasswordR<R@RtnameR)R'tniceRtAssertionErrorR-tkwargsR(R.tsett issupersetRR*tsortedRRRt_Param__clonekwt frozensettlistRR RthasattrRtsetattrtappendtgetattrRERORPRUR7t class_rulestrulesRMt all_rulesRFRR(R R^RmR/t kw_from_spectextratdfRlR"tkindRWtvaluet rule_nametrule((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#sš     %# )   """"       $cCs#d|jjdj|jƒƒfS(sQ Return an expresion that could construct this `Param` instance. s%s(%s)s, (R)R'R*t_Param__repr_iter(R ((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR,s ccs—t|jƒVx|jD]}|jVqWxft|jƒD]U}|j|}t|ƒrtt|dƒrt|j}n t|ƒ}d||fVq:WdS(NR's%s=%s(R$RYRmR'RdRZRRh(R RuR"Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt __repr_iters    cKs|tkr|j|}n|j|j|ƒƒ}t|dƒrm|j||jjd|j|kƒn|j|d|j|kƒ|S(s$ One stop shopping. tenvtsupplied( R t get_defaulttconvertt normalizeRhtvalidateRxtcontextR^(R RsR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR2s (cCs|j}|s|j}n|S(sÑ Return the right name of an attribute depending on usage. Normally errors should use cli_name, our "friendly" name. When using the API directly or *attr return the real name. (RER^(R R^((s//home/mkosek/freeipa-clean/ipalib/parameters.pytget_param_name)s  ccs]xVt|jƒD]E}|j|}t|ƒrJt|dƒrJ|j}n||fVqWdS(sW Iterate through ``(key,value)`` for all kwargs passed to constructor. R'N(RdRZRRhR'(R R"Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR/5s   cCsB|jdk r|j|jkS|jdk r>|j|jkStS(s Return ``True`` if this parameter should be used in ``env.context``. If a parameter is created with niether the ``include`` nor the ``exclude`` kwarg, this method will always return ``True``. For example: >>> from ipalib.config import Env >>> param = Param('my_param') >>> param.use_in_context(Env(context='foo')) True >>> param.use_in_context(Env(context='bar')) True If a parameter is created with an ``include`` kwarg, this method will only return ``True`` if ``env.context`` is in ``include``. For example: >>> param = Param('my_param', include=['foo', 'whatever']) >>> param.include frozenset(['foo', 'whatever']) >>> param.use_in_context(Env(context='foo')) True >>> param.use_in_context(Env(context='bar')) False If a paremeter is created with an ``exclude`` kwarg, this method will only return ``True`` if ``env.context`` is not in ``exclude``. For example: >>> param = Param('my_param', exclude=['foo', 'whatever']) >>> param.exclude frozenset(['foo', 'whatever']) >>> param.use_in_context(Env(context='foo')) False >>> param.use_in_context(Env(context='bar')) True Note that the ``include`` and ``exclude`` kwargs are mutually exclusive and that at most one can be suppelied to `Param.__init__()`. For example: >>> param = Param('nope', include=['foo'], exclude=['bar']) Traceback (most recent call last): ... ValueError: Param('nope'): cannot have both include=frozenset(['foo']) and exclude=frozenset(['bar']) So that subclasses can add additional logic based on other environment variables, the entire `config.Env` instance is passed in rather than just the value of ``env.context``. N(ROR.R~RPR=(R Rx((s//home/mkosek/freeipa-clean/ipalib/parameters.pytuse_in_context?s 3cCs|jr|dk rdS|S(sk Return a value safe for logging. This is used so that passwords don't get logged. If this is a `Password` instance and ``value`` is not ``None``, a constant ``u'********'`` is returned. For example: >>> p = Password('my_password') >>> p.safe_value(u'This is my password') u'********' >>> p.safe_value(None) is None True If this is not a `Password` instance, ``value`` is returned unchanged. For example: >>> s = Str('my_str') >>> s.safe_value(u'Some arbitrary value') u'Some arbitrary value' u********N(R]R.(R Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt safe_valuexscKs|j|j|S(sD Return a new `Param` instance similar to this one. (t clone_renameR^(R t overrides((s//home/mkosek/freeipa-clean/ipalib/parameters.pytclone‘scKs|j||j|S(sZ Return a new `Param` instance similar to this one, but named differently (t clone_retypeR)(R R^Rƒ((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR‚—scKs/t|jƒ}|j|ƒ|||j|ŽS(s\ Return a new `Param` instance similar to this one, but of a different type (R;RetupdateRm(R R^tklassRƒR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR…s csdˆjr0t|ƒttfkr0|f}q0nˆjrSt‡fd†|DƒƒSˆj|ƒSdS(s Normalize ``value`` using normalizer callback. For example: >>> param = Param('telephone', ... normalizer=lambda value: value.replace('.', '-') ... ) >>> param.normalize(u'800.123.4567') u'800-123-4567' If this `Param` instance was created with a normalizer callback and ``value`` is a unicode instance, the normalizer callback is called and *its* return value is returned. On the other hand, if this `Param` instance was *not* created with a normalizer callback, if ``value`` is *not* a unicode instance, or if an exception is caught when calling the normalizer callback, ``value`` is returned unchanged. :param value: A proposed value for this parameter. c3s|]}ˆj|ƒVqdS(N(t_normalize_scalar(R%tv(R (s//home/mkosek/freeipa-clean/ipalib/parameters.pys ÁsN(R7RR(RgRˆ(R Rs((R s//home/mkosek/freeipa-clean/ipalib/parameters.pyR|¥s  cCs=|jdkr|Sy|j|ƒSWntk r8|SXdS(so Normalize a scalar value. This method is called once for each value in a multivalue. N(RJR.R0(R Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRˆÆs  cs’|tkrdSˆjr…t|ƒttfkr=|f}nt‡fd†td„t|ƒƒDƒƒ}t|ƒdkrdS|Sˆj|ƒS(sá Convert ``value`` to the Python type required by this parameter. For example: >>> scalar = Str('my_scalar') >>> scalar.type >>> scalar.convert(43.2) u'43.2' (Note that `Str` is a subclass of `Param`.) All values in `constants.NULLS` will be converted to ``None``. For example: >>> scalar.convert(u'') is None # An empty string True >>> scalar.convert([]) is None # An empty list True Likewise, values in `constants.NULLS` will be filtered out of a multivalue parameter. For example: >>> multi = Str('my_multi', multivalue=True) >>> multi.convert([1.5, '', 17, None, u'Hello']) (u'1.5', u'17', u'Hello') >>> multi.convert([None, u'']) is None # Filters to an empty list True Lastly, multivalue parameters will always return a ``tuple`` (assuming they don't return ``None`` as in the last example above). For example: >>> multi.convert(42) # Called with a scalar value (u'42',) >>> multi.convert([0, 1]) # Called with a list value (u'0', u'1') Note that how values are converted (and from what types they will be converted) completely depends upon how a subclass implements its `Param._convert_scalar()` method. For example, see `Str._convert_scalar()`. :param value: A proposed value for this parameter. Nc3s'|]\}}ˆj||ƒVqdS(N(t_convert_scalar(R%tiR‰(R (s//home/mkosek/freeipa-clean/ipalib/parameters.pys scSs|dtkS(Ni(R (tiv((s//home/mkosek/freeipa-clean/ipalib/parameters.pytsi( R R7RR(Rgtfiltert enumerateRRŠ(R Rstvalues((R s//home/mkosek/freeipa-clean/ipalib/parameters.pyR{Ós.   cCsDt|ƒ|jkr|Std|jd|dt|jƒƒ‚dS(s0 Convert a single scalar value. R^tindexterrorN(RRR^tugettextt type_error(R RsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠsc Cs|dkrd|js*|r`d|jkr`|dkrKtd|jƒ‚q`td|jƒ‚ndS|jrõt|ƒtk r¤t t dt|t|ƒfƒ‚nt |ƒdkrÅt dƒ‚nx:t |ƒD]\}}|j||ƒqÒWn |j|ƒdS(sê Check validity of ``value``. :param value: A proposed value for this parameter. :param context: The context we are running in. :param supplied: True if this parameter was supplied explicitly. tnonemptytcliR^NRsis,value: empty tuple must be converted to None(R.R6RQRRER^R7RR(RR RRRt_validate_scalar(R RsR~RyR‹R‰((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR}s   "c Csæt|ƒ|jk r@tt|j|j|t|ƒfƒ‚n|dk rƒt|ƒtk rƒttdt|t|ƒfƒ‚nx\|jD]Q}|t|ƒ}|dk rtd|j ƒd|d|d|d|ƒ‚qqWdS(NR‘R^RsR’Ru( RRR R^R.tintRnR“R R(R RsR‘RuR’((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR—5s("  cKse|jdk r^|j|}|dk r^y|j|j|ƒƒSWq[tk rWq[Xq^n|jS(s/ Return the static default or construct and return a dynamic default. (In these examples, we will use the `Str` and `Bytes` classes, which both subclass from `Param`.) The *default* static default is ``None``. For example: >>> s = Str('my_str') >>> s.default is None True >>> s.get_default() is None True However, you can provide your own static default via the ``default`` keyword argument when you create your `Param` instance. For example: >>> s = Str('my_str', default=u'My Static Default') >>> s.default u'My Static Default' >>> s.get_default() u'My Static Default' If you need to generate a dynamic default from other supplied parameter values, provide a callback via the ``default_from`` keyword argument. This callback will be automatically wrapped in a `DefaultFrom` instance if it isn't one already (see the `DefaultFrom` class for all the gory details). For example: >>> login = Str('login', default=u'my-static-login-default', ... default_from=lambda first, last: (first[0] + last).lower(), ... ) >>> isinstance(login.default_from, DefaultFrom) True >>> login.default_from.keys ('first', 'last') Then when all the keys needed by the `DefaultFrom` instance are present, the dynamic default is constructed and returned. For example: >>> kw = dict(last=u'Doe', first=u'John') >>> login.get_default(**kw) u'jdoe' Or if any keys are missing, your *static* default is returned. For example: >>> kw = dict(first=u'John', department=u'Engineering') >>> login.get_default(**kw) u'my-static-login-default' N(RKR.R{R|R0RW(R R/RW((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRzIs4   t falsehoodsttruthstversioncCsi}xË|jD]À\}}}||jkr4qn|ttfkrLqqtt||ƒtƒrgt||gƒD] }|^qw||tBoolc Bs{eZdZeZedƒZejde e dde ddgƒfde e dd e d d gƒffZd d „Z RS(sG A parameter for boolean values (stored in the ``bool`` type). smust be True or FalseRšiu1utrueuTRUER™iu0ufalseuFALSEcCsÊt|ƒ|jkr|St|tƒr7|jƒ}n||jkrJtS||jkr]tSt|ƒtt fkrŸt d|j d|dt |j ƒƒ‚nt d|j d|dt |jƒƒ‚dS(s0 Convert a single scalar value. R^R‘R’N(RR[R¥tlowerRšR=R™R<R(RgRR^R“R¤R”(R RsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRаsN(R'R3R4R¦RRR”RDRaRfR=R<R.RŠ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR¨¡s !(tFlagcBseZdZd„ZRS(sR A boolean parameter that always gets filled in with a default value. This `Bool` subclass forces ``autofill=True`` in `Flag.__init__()`. If no default is provided, it also fills in a default value of ``False``. Lastly, unlike the `Bool` class, the default must be either ``True`` or ``False`` and cannot be ``None``. For example: >>> flag = Flag('my_flag') >>> (flag.autofill, flag.default) (True, False) To have a default value of ``True``, create your `Flag` intance with ``default=True``. For example: >>> flag = Flag('my_flag', default=True) >>> (flag.autofill, flag.default) (True, True) Also note that creating a `Flag` instance with ``autofill=False`` will have no effect. For example: >>> flag = Flag('my_flag', autofill=False) >>> flag.autofill True cOsˆt|d maxvalue (minvalue=%r, maxvalue=%r)(R«R¯R#R°R±R.RR_(R R^RmR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#s 0cCsût|ƒttfkr|St|ƒtkr–|jdƒdkrnytt|ƒƒSWq“tk rjq“Xq–yt|dƒSWq–tk r’q–Xnt|ƒtkrÍyt|ƒSWqÍtk rÉqÍXntd|jƒd|dt |j ƒƒ‚dS(s0 Convert a single scalar value. u.iR^R‘R’N( RR˜R­R§tfindR®RRRR“R”(R RsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠs&   cCsKt|ƒttfkst‚||jkrG|dƒtd|jƒSdS(s' Check min constraint. smust be at least %(minvalue)dR°N(RR˜R­R`R°R;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_minvalue9scCsKt|ƒttfkst‚||jkrG|dƒtd|jƒSdS(s' Check max constraint. scan be at most %(maxvalue)dR±N(RR˜R­R`R±R;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_maxvalueCsc Csét|ƒttfkrCtt|j|j|t|ƒfƒ‚n|dk r†t|ƒtk r†ttdt|t|ƒfƒ‚nx\|jD]Q}|t|ƒ}|dk rt d|j ƒd|d|d|d|ƒ‚qqWdS(s» This duplicates _validate_scalar in the Param class with the exception that it allows both int and long types. The min/max rules handle size enforcement. R‘R^RsR’RuN( RR˜R­RR R^R.RnR“R R(R RsR‘RuR’((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR—Ms("  N(R'R3R4R˜RRR”RDRaR­RRR#R.RŠR³R´R—(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR¯s   tDecimalc BsÆeZdZejZedƒZej dejdfdejdfde dfde e fdedffZ d „Zd „Zd „Zd „Zd„Zd„Zd„Zdd„Zd„ZRS(sj A parameter for floating-point values (stored in the ``Decimal`` type). Python Decimal type helps overcome problems tied to plain "float" type, e.g. problem with representation or value comparison. In order to safely transfer the value over RPC libraries, it is being converted to string which is then converted back to Decimal number. smust be a decimal numberR°R±t precisiont exponentialt numberclasss-Normals+Zeros+NormalcOsEx™dD]‘}|j|ƒ}|dkr.qnt|ttfƒrytj|ƒ}Wn2tk rŠ}td||t |ƒfƒ‚nX||| maxvalue (minvalue=%s, maxvalue=%s)is %s: precision must be at least 0(sminvaluesmaxvaluesdefault(R-R.R[R¥R®tdecimalRµt ExceptionRRR«R#R°R±R_R¶(R R^RmR/tkwparamRste((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#s*  cCsHt|ƒtjkst‚||jkrD|dƒtd|jƒSdS(s' Check min constraint. smust be at least %(minvalue)sR°N(RR¹RµR`R°R;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR³šscCsHt|ƒtjkst‚||jkrD|dƒtd|jƒSdS(s' Check max constraint. scan be at most %(maxvalue)sR±N(RR¹RµR`R±R;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR´¤sc Csb|jƒ}||jkr^td|jƒdtdƒtd|ddj|jƒƒƒ‚ndS(NR^R’sWnumber class '%(cls)s' is not included in a list of allowed number classes: %(allowed)stclstallowedu, (t number_classR¸R RRR;R*(R RsR¸((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_enforce_numberclass®s    cCs•t|ƒtjkst‚|jdk r‘tjdƒ|j }y|j|ƒ}Wq‘tjk r}td|j ƒdt |ƒƒ‚q‘Xn|S(Ni R^R’( RR¹RµR`R¶R.tquantizetDecimalExceptionRRR§(R Rst quantize_expR¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_enforce_precision¸scCsŸt|ƒtjkst‚|js›y:||jƒkrQ|jtjdƒƒn |jƒ}Wq›tjk r—}t d|j ƒdt |ƒƒ‚q›Xn|S(NiR^R’( RR¹RµR`R·t to_integralRÁR|RÂRRR§(R RsR¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_remove_exponentÃs *cCs/|j|ƒ|j|ƒ}|j|ƒ}|S(s¼ This method is run in conversion and normalization methods to test that the Decimal number conforms to Parameter boundaries and then normalizes the value. (RÀRÆRÄ(R Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_test_and_normalizeÒs cCs£t|ttfƒrkytj|ƒ}Wqktjk rg}td|jƒd|dt|ƒƒ‚qkXnt|tjƒrŠ|j |ƒSt t|ƒj ||ƒS(NR^R‘R’( R[R¥R®R¹RµRÂRRR§RÇR«RŠ(R RsR‘R¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠÝs cCs5t|tjƒr|j|ƒStt|ƒj|ƒS(N(R[R¹RµRÇR«Rˆ(R Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRˆês N(s-Normals+Zeros+Normal(R'R3R4R¹RµRRR”RDRaR.R˜R¦R<R(R#R³R´RÀRÄRÆRÇRŠRˆ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRµgs$       tDatacBs{eZdZejdedfdedfdedfdefdfdefdffZdZdZ d„Z d„Z RS( s+ Base class for the `Bytes` and `Str` parameters. Previously `Str` was as subclass of `Bytes`. Now the common functionality has been split into this base class so that ``isinstance(foo, Bytes)`` wont be ``True`` when ``foo`` is actually an `Str` instance (which is confusing). t minlengtht maxlengthtlengthtpatterntpattern_errmsgc Os`tt|ƒj|||Ž|jdkpF|jdkoF|jdks_td|jƒ‚n|jdk rœ|jdkrœtd|j|jfƒ‚n|jdk rÙ|jdkrÙtd|j|jfƒ‚nd|j|jfkr\|j|jkr(td|j|j|jfƒ‚q\|j|jkr\td|j|jfƒ‚q\ndS(Ns1%s: cannot mix length with minlength or maxlengthis"%s: minlength must be >= 1; got %rs"%s: maxlength must be >= 1; got %rs6%s: minlength > maxlength (minlength=%r, maxlength=%r)s1%s: minlength == maxlength; use length=%d instead( R«RÈR#RËR.RÉRÊRR_(R R^RmR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#s(cCstt|ƒ|jkst‚|jj|ƒdkrp|jrS|jtd|jƒS|dƒtd|jƒSndS(s2 Check pattern (regex) contraint. RÌs must match pattern "%(pattern)s"N(RR`tretmatchR.t re_errmsgR;RÌ(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _rule_pattern%s  N( R'R3R4RDRaR˜R.R¥RÎRÐR#RÑ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÈðs    !tBytescBsPeZdZeZedƒZd„Zd„Zd„Z d„Z dd„Z RS(s( A parameter for binary data (stored in the ``str`` type). This class is named *Bytes* instead of *Str* so it's aligned with the Python v3 ``(str, unicode) => (bytes, str)`` clean-up. See: http://docs.python.org/3.0/whatsnew/3.0.html Also see the `Str` parameter. smust be binary datacOso|jddƒdkr$d|_ntj|dƒ|_|jddƒ|_tt|ƒj|||ŽdS(NRÌRÍ(R-R.RÎtcompileRÐR«RÒR#(R R^RmR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#Bs  cCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s- Check minlength constraint. s$must be at least %(minlength)d bytesRÉN(RRR`RRÉR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_minlengthJscCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s- Check maxlength constraint. s"can be at most %(maxlength)d bytesRÊN(RRR`RRÊR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_maxlengthTscCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s* Check length constraint. s must be exactly %(length)d bytesRËN(RRR`RRËR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _rule_length^scCsit|tƒrPytj|ƒ}WqPtk rL}tdt|ƒƒ‚qPXntt|ƒj ||ƒS(Ntreason( R[R§tbase64t b64decodeRR RR«RÒRŠ(R RsR‘R¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠhs N( R'R3R4RRRR”R#RÔRÕRÖR.RŠ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÒ3s    tStrcBsreZdZejdeeffZeZe dƒZ d„Z d d„Z d„Zd„Zd„Zd„ZRS( s1 A parameter for Unicode text (stored in the ``unicode`` type). This class is named *Str* instead of *Unicode* so it's aligned with the Python v3 ``(str, unicode) => (bytes, str)`` clean-up. See: http://docs.python.org/3.0/whatsnew/3.0.html Also see the `Bytes` parameter. tnoextrawhitespacesmust be Unicode textcOsu|jddƒdkr$d|_ntj|dtjƒ|_|jddƒ|_tt|ƒj|||ŽdS(NRÌRÍ( R-R.RÎRÓtUNICODERÐR«RÚR#(R R^RmR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#„s  cCs´t|ƒ|jkr|St|ƒttttjfkrG|j|ƒSt|ƒttfkr‰td|j d|dt |j ƒƒ‚ntd|j d|dt |j ƒƒ‚dS(s0 Convert a single scalar value. R^R‘R’N( RR˜R­R®R¹RµR(RgRR^R“R¤R”(R RsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠŒs! cCsWt|ƒtkst‚|jtkr+dSt|ƒt|jƒƒkrS|dƒSdS(s7 Do not allow leading/trailing spaces. Ns+Leading and trailing spaces are not allowed(RR§R`RÛR<Rtstrip(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_noextrawhitespace›s cCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s- Check minlength constraint. s)must be at least %(minlength)d charactersRÉN(RR§R`RRÉR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÔ¥scCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s- Check maxlength constraint. s'can be at most %(maxlength)d charactersRÊN(RR§R`RRÊR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÕ¯scCsKt|ƒtkst‚t|ƒ|jkrG|dƒtd|jƒSdS(s* Check length constraint. s%must be exactly %(length)d charactersRËN(RR§R`RRËR;(R RRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÖ¹sN(R'R3R4RÈRaR¦R=R§RRR”R#R.RŠRÞRÔRÕRÖ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRÚqs     tIA5StrcBs#eZdZd„Zdd„ZRS(s# An IA5String per RFC 4517 cOs tt|ƒj|||ŽdS(N(R«RßR#(R R^RmR/((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#Ésc Cs™t|tƒr€xntt|ƒƒD]W}t||ƒdkr"td|jƒd|dtdƒtd||ƒƒ‚q"q"Wnt t |ƒj ||ƒS(NiR^R‘R’s&The character %(char)r is not allowed.tchar( R[R¥txrangeRtordRRRR;R«RßRŠ(R RsR‘R‹((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠÌs !N(R'R3R4R#R.RŠ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRßÄs R\cBs3eZdZejdeeffZdd„ZRS(sE A parameter for passwords (stored in the ``unicode`` type). tconfirmcCs|t|ttfƒrct|ƒdkrc|\}}||krZtd|jd|ƒ‚n|}ntt|ƒj||ƒS(NiR^R‘( R[R(RgRR R^R«R\RŠ(R RsR‘tp1tp2((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠás '   N( R'R3R4RÚRaR¦R=R.RŠ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR\ØstEnumcBs<eZdZejdeeƒffZd„Zd„ZRS(s; Base class for parameters with enumerable values. RcOs»tt|ƒj|||Žxmt|jƒD]\\}}t|ƒ|jk r,d|j|f}tt||j|t|ƒfƒ‚q,q,Wt |jƒdkr·t d|jƒ‚ndS(Ns %s values[%d]is$%s: list of values must not be empty( R«RæR#RRRR_RR RR(R R^RmR/R‹R‰tn((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR#ós)cKs|||jkrxt|jƒdkrB|dƒtd|jdƒSdjd„|jDƒƒ}|dƒtd|ƒSndS( Nismust be '%(value)s'Rsiu, css|]}d|VqdS(s'%s'N((R%Rs((s//home/mkosek/freeipa-clean/ipalib/parameters.pys ssmust be one of %(values)sR(RRR;R*(R RRsR/R((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _rule_valuess (R'R3R4RDRaR(R#Rè(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRæês  t BytesEnumcBseZdZeZRS(sB Enumerable for binary data (stored in the ``str`` type). (R'R3R4R§R(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRéstStrEnumcBseZdZeZRS(sy Enumerable for Unicode text (stored in the ``unicode`` type). For example: >>> enum = StrEnum('my_enum', values=(u'One', u'Two', u'Three')) >>> enum.validate(u'Two', 'cli') is None True >>> enum.validate(u'Four', 'cli') Traceback (most recent call last): ... ValidationError: invalid 'my_enum': must be one of 'One', 'Two', 'Three' (R'R3R4R§R(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRês tAnycBs,eZdZeZdd„Zdd„ZRS(sS A parameter capable of holding values of any type. For internal use only. cCs|S(N((R RsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠ)sc Cs`xY|jD]N}|t|ƒ}|dk r td|jd|d|d|d|ƒ‚q q WdS(NR^RsR‘R’Ru(RnR“R.R R^(R RsR‘RuR’((s//home/mkosek/freeipa-clean/ipalib/parameters.pyR—,s  N(R'R3R4tobjectRR.RŠR—(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRë"s tFilecBs3eZdZejdeefdeeffZRS(sh File parameter type. Accepts file names and loads their content into the parameter value. tstdin_if_missingRÛ(R'R3R4RÈRaR¦R<(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRí9s t AccessTimecBs’eZdZd„Zd„Zddd„Zd„Zd„Zd„Zd „Z d „Z d „Z d „Z d „Z d„Zd„Zd„ZRS(s  Access time parameter type. Accepts values conforming to generalizedTime as defined in RFC 4517 section 3.3.13 without time zone information. cCs´t|ƒdkr!tdƒ‚n|jƒs<tdƒ‚nt|dd!ƒ}|dksg|dkrvtdƒ‚nt|dd!ƒ}|dks¡|dkr°td ƒ‚ndS( Nis&HHMM must be exactly 4 characters longsHHMM non-numericiiisHH out of rangei;sMM out of range(RRt isnumericR˜(R RXthhtmm((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_HHMMMs cCsa|jƒrBt|ƒ}|dks0|dkr]tdƒ‚q]n|d kr]td ƒ‚ndS( Niisday of the week out of rangetMontTuetWedtThutFritSattSunsinvalid day of the week(RôRõRöR÷RøRùRú(RðR˜R(R RXRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_dotwYs    iicCs'|jƒstdƒ‚nt|ƒ}|dkr]|dksK|d kr#td ƒ‚q#nÆ|dkr“|dks|dkr#td ƒ‚q#n|dkr#|d dkrù|ddksÏ|ddkrù|dksç|dkr td ƒ‚q q#|dks|dkr#td ƒ‚q#ndS(Nsday of the month non-numericiiiiii i isday of the month out of rangeiii i iiiidiii(iiiiii i (iii i (RðRR˜(R RXt month_numtyearRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_dotmas     0cCsR|jƒstdƒ‚nt|ƒ}|dks?|dkrNtdƒ‚ndS(Nsweek of the month non-numericiisweek of the month out of range(RðRR˜(R RXRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_wotmss   cCsR|jƒstdƒ‚nt|ƒ}|dks?|dkrNtdƒ‚ndS(Nsweek of the year non-numericii4sweek of the year out of range(RðRR˜(R RXRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_wotyzs   cCsR|jƒstdƒ‚nt|ƒ}|dks?|dkrNtdƒ‚ndS(Nsday of the year non-numericiimsday of the year out of range(RðRR˜(R RXRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_dotys   cCsR|jƒstdƒ‚nt|ƒ}|dks?|dkrNtdƒ‚ndS(Nsmonth number non-numericii smonth number out of range(RðRR˜(R RXRs((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_check_month_numˆs   cCsÈ|jdƒ}x²|D]ª}|s1tdƒ‚n|jdƒ}t|ƒdkratdƒ‚nx|D]}||ƒqhWt|ƒdkrt|dƒt|dƒkrÀtdƒ‚qÀqqWdS(Nt,sinvalid time ranget-iii(tsplitRRR˜(R RXt check_funct intervalsR‹RR‰((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_check_intervals   cCsD||dkrtdƒ‚n|d7}|j|||jƒ|S(Ntdaysinvalid week specifieri(RRRû(R ttsR‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_W_specs  cCsˆ||dkrD|j||d|jƒ|j||dƒ}n@||dkrx|d7}|j|||jƒn tdƒ‚|S(NtweekiiR sinvalid month specifier(RRÿR RþR(R R R‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_M_spec¤s  cCsâ||dkrZ|d7}|j|||jƒt||ƒ}|j||dƒ}n„||dkrž|j||d|jƒ|j||dƒ}n@||dkrÒ|d7}|j|||jƒn tdƒ‚|S(NtmonthiR iR sinvalid year specifier(RRR˜R RR RR(R R R‘Rü((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt _check_Y_spec¯s   cCs<t|ƒtkst‚t|ƒd kr9tdƒ‚n|jƒsTtdƒ‚n|j|dd!ƒt|dd!ƒ}t|dd!ƒ}|j|dd !||ƒt|ƒdkrÑ|j |d d!ƒn|j d |d d!ƒt|ƒdkr8t|dd!ƒ}|dks&|d kr8td ƒ‚q8ndS(Ni i isincomplete generalized timestime non-numericiiiis%s00i<sseconds out of range(i i i( RR§R`RRRðRR˜RþRó(R RXtyear_numRüts((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_check_generalized¿s  cCsŸ|jƒ}|ddkr°t|ƒdkr=tdƒ‚n|j|dƒ|ddkrmtdƒ‚n|j|d ƒt|dƒt|d ƒkr›td ƒ‚q›në|dd krd}|dd krë|j|dƒ}nc|dd kr|j|dƒ}n>|ddkr5|j|dƒ}n|ddkrNd}n|dkrqtd|dƒ‚n|j ||d|j ƒn tdƒ‚dS(NitabsoluteisDinvalid format, must be 'absolute generalizedTime ~ generalizedTime'iit~sinvalid time range separatorisinvalid time rangetperiodictyearlytmonthlytweeklytdailys0period must be yearly, monthy or daily, got '%s's!time neither absolute or periodic( RRRRR˜R.RR R RRó(R ttimeR R‘((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_checkÓs0    cCs~y|j|ƒWnftk rH}td|jƒd|jdƒ‚n2tk rytd|jƒdtdƒƒ‚nXdS(NR^R’isincomplete time value(RRR RR+t IndexErrorR“R.(R RRsR¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt_rule_requiredîs% (R'R3R4RóRûRþRÿRRRRR R RRRR(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRïFs          tDNParamcBseZeZdd„ZRS(cCsjt|ƒ|jkr|Syt|ƒ}Wn:tk re}td|jƒd|dt|ƒƒ‚nX|S(s0 Convert a single scalar value. R^R‘R’(RRRºRRR“(R RsR‘tdnR¼((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRŠýsN(R'R3RRR.RŠ(((s//home/mkosek/freeipa-clean/ipalib/parameters.pyRústDeprecatedParamcBs3eZejdeeffZd„Zd„ZRS(t deprecatecOsWd|kr*t|dƒdg|d>> s = create_param('hometown?') >>> s Str('hometown?') >>> (s.name, s.required, s.multivalue) ('hometown', False, False) On the other hand, if ``spec`` is already a `Param` instance, it is returned unchanged. For example: >>> b = Bytes('cert') >>> create_param(b) is b True As a plugin author, you will not call this function directly (which would be no more convenient than simply creating the `Str` instance). Instead, `frontend.Command` will call it for you when it evaluates the ``takes_args`` and ``takes_options`` attributes, and `frontend.Object` will call it for you when it evaluates the ``takes_params`` attribute. :param spec: A spec string or a `Param` instance. R5(R[RDRRRR RÚ(R5((s//home/mkosek/freeipa-clean/ipalib/parameters.pyt create_params !((8R4RÎR¹RØt xmlrpclibRRttypesRttextRR“tplugableRRRterrorsRRR R R t constantsR R RRRtutilRt ipapython.dnRRR@RbRARDR¨RªR¬R¯RµRÈRÒRÚRßR\RæRéRêRëRíRïRR R$(((s//home/mkosek/freeipa-clean/ipalib/parameters.pytdsN   x -  ÿÿ‚#*a‰C>S ´freeipa-3.3.4/ipalib/aci.py0000775000175000017500000003212012271663206015056 0ustar mkosekmkosek# Authors: # Rob Crittenden # # 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 . import shlex import re # The Python re module doesn't do nested parenthesis # Break the ACI into 3 pieces: target, name, permissions/bind_rules ACIPat = re.compile(r'\(version\s+3.0\s*;\s*acl\s+\"([^\"]*)\"\s*;\s*([^;]*);\s*\)', re.UNICODE) # Break the permissions/bind_rules out PermPat = re.compile(r'(\w+)\s*\((.*)\)\s+(.*)', re.UNICODE) # Break the bind rule out BindPat = re.compile(r'([a-zA-Z0-9;\.]+)\s*(\!?=)\s*(.*)', re.UNICODE) ACTIONS = ["allow", "deny"] PERMISSIONS = ["read", "write", "add", "delete", "search", "compare", "selfwrite", "proxy", "all"] class ACI: """ Holds the basic data for an ACI entry, as stored in the cn=accounts entry in LDAP. Has methods to parse an ACI string and export to an ACI String. """ def __init__(self,acistr=None): self.name = None self.source_group = None self.dest_group = None self.orig_acistr = acistr self.target = {} self.action = "allow" self.permissions = ["write"] self.bindrule = {} if acistr is not None: self._parse_acistr(acistr) def __getitem__(self,key): """Fake getting attributes by key for sorting""" if key == 0: return self.name if key == 1: return self.source_group if key == 2: return self.dest_group raise TypeError("Unknown key value %s" % key) def __repr__(self): """An alias for export_to_string()""" return self.export_to_string() def export_to_string(self): """Output a Directory Server-compatible ACI string""" self.validate() aci = "" for t in self.target: op = self.target[t]['operator'] if type(self.target[t]['expression']) in (tuple, list): target = "" for l in self.target[t]['expression']: target = target + l + " || " target = target[:-4] aci = aci + "(%s %s \"%s\")" % (t, op, target) else: aci = aci + "(%s %s \"%s\")" % (t, op, self.target[t]['expression']) aci = aci + "(version 3.0;acl \"%s\";%s (%s) %s %s \"%s\"" % (self.name, self.action, ",".join(self.permissions), self.bindrule['keyword'], self.bindrule['operator'], self.bindrule['expression']) + ";)" return aci def _remove_quotes(self, s): # Remove leading and trailing quotes if s.startswith('"'): s = s[1:] if s.endswith('"'): s = s[:-1] return s def _parse_target(self, aci): lexer = shlex.shlex(aci.encode('utf-8')) lexer.wordchars = lexer.wordchars + "." l = [] var = False op = "=" for token in lexer: # We should have the form (a = b)(a = b)... if token == "(": var = lexer.next().strip() operator = lexer.next() if operator != "=" and operator != "!=": # Peek at the next char before giving up operator = operator + lexer.next() if operator != "=" and operator != "!=": raise SyntaxError("No operator in target, got '%s'" % operator) op = operator val = lexer.next().strip() val = self._remove_quotes(val) end = lexer.next() if end != ")": raise SyntaxError('No end parenthesis in target, got %s' % end) if var == 'targetattr': # Make a string of the form attr || attr || ... into a list t = re.split('[^a-zA-Z0-9;\*]+', val) self.target[var] = {} self.target[var]['operator'] = op self.target[var]['expression'] = t else: self.target[var] = {} self.target[var]['operator'] = op self.target[var]['expression'] = val def _parse_acistr(self, acistr): vstart = acistr.find('version 3.0') if vstart < 0: raise SyntaxError, "malformed ACI, unable to find version %s" % acistr acimatch = ACIPat.match(acistr[vstart-1:]) if not acimatch or len(acimatch.groups()) < 2: raise SyntaxError, "malformed ACI, match for version and bind rule failed %s" % acistr self._parse_target(acistr[:vstart-1]) self.name = acimatch.group(1) bindperms = PermPat.match(acimatch.group(2)) if not bindperms or len(bindperms.groups()) < 3: raise SyntaxError, "malformed ACI, permissions match failed %s" % acistr self.action = bindperms.group(1) self.permissions = bindperms.group(2).replace(' ','').split(',') self.set_bindrule(bindperms.group(3)) def validate(self): """Do some basic verification that this will produce a valid LDAP ACI. returns True if valid """ if not type(self.permissions) in (tuple, list): raise SyntaxError, "permissions must be a list" for p in self.permissions: if not p.lower() in PERMISSIONS: raise SyntaxError, "invalid permission: '%s'" % p if not self.name: raise SyntaxError, "name must be set" if not isinstance(self.name, basestring): raise SyntaxError, "name must be a string" if not isinstance(self.target, dict) or len(self.target) == 0: raise SyntaxError, "target must be a non-empty dictionary" if not isinstance(self.bindrule, dict): raise SyntaxError, "bindrule must be a dictionary" if not self.bindrule.get('operator') or not self.bindrule.get('keyword') or not self.bindrule.get('expression'): raise SyntaxError, "bindrule is missing a component" return True def set_target_filter(self, filter, operator="="): self.target['targetfilter'] = {} if not filter.startswith("("): filter = "(" + filter + ")" self.target['targetfilter']['expression'] = filter self.target['targetfilter']['operator'] = operator def set_target_attr(self, attr, operator="="): if not attr: if 'targetattr' in self.target: del self.target['targetattr'] return if not type(attr) in (tuple, list): attr = [attr] self.target['targetattr'] = {} self.target['targetattr']['expression'] = attr self.target['targetattr']['operator'] = operator def set_target(self, target, operator="="): assert target.startswith("ldap:///") self.target['target'] = {} self.target['target']['expression'] = target self.target['target']['operator'] = operator def set_bindrule(self, bindrule): match = BindPat.match(bindrule) if not match or len(match.groups()) < 3: raise SyntaxError, "malformed bind rule" self.set_bindrule_keyword(match.group(1)) self.set_bindrule_operator(match.group(2)) self.set_bindrule_expression(match.group(3).replace('"','')) def set_bindrule_keyword(self, keyword): self.bindrule['keyword'] = keyword def set_bindrule_operator(self, operator): self.bindrule['operator'] = operator def set_bindrule_expression(self, expression): self.bindrule['expression'] = expression def isequal(self, b): """ Compare the current ACI to another one to see if they are the same. returns True if equal, False if not. """ assert isinstance(b, ACI) try: if self.name.lower() != b.name.lower(): return False if set(self.permissions) != set(b.permissions): return False if self.bindrule.get('keyword') != b.bindrule.get('keyword'): return False if self.bindrule.get('operator') != b.bindrule.get('operator'): return False if self.bindrule.get('expression') != b.bindrule.get('expression'): return False if self.target.get('targetfilter',{}).get('expression') != b.target.get('targetfilter',{}).get('expression'): return False if self.target.get('targetfilter',{}).get('operator') != b.target.get('targetfilter',{}).get('operator'): return False if set(self.target.get('targetattr', {}).get('expression', ())) != set(b.target.get('targetattr',{}).get('expression', ())): return False if self.target.get('targetattr',{}).get('operator') != b.target.get('targetattr',{}).get('operator'): return False if self.target.get('target',{}).get('expression') != b.target.get('target',{}).get('expression'): return False if self.target.get('target',{}).get('operator') != b.target.get('target',{}).get('operator'): return False except Exception: # If anything throws up then they are not equal return False # We got this far so lets declare them the same return True if __name__ == '__main__': # a = ACI('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)') # print a # a = ACI('(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*) (version 3.0;acl "aci1";allow (write) userdn="ldap:///self";)') # print a # a = ACI(' (targetattr = "givenName || sn || cn || displayName || title || initials || loginShell || gecos || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || secretary || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || employeeType || businessCategory || ou")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)') # print a a = ACI('(target="ldap:///uid=*,cn=users,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user";allow (add) groupdn="ldap:///cn=add_user,cn=taskgroups,dc=example,dc=com";)') print a print "---" a = ACI('(targetattr=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)') print a print "---" a = ACI('(targetattr!=member)(target="ldap:///cn=ipausers,cn=groups,cn=accounts,dc=example,dc=com")(version 3.0;acl "add_user_to_default_group";allow (write) groupdn="ldap:///cn=add_user_to_default_group,cn=taskgroups,dc=example,dc=com";)') print a print "---" a = ACI('(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "change_password"; allow (write) groupdn = "ldap:///cn=change_password,cn=taskgroups,dc=example,dc=com";)') print a print "---" a = ACI() a.name ="foo" a.set_target_attr(['title','givenname'], "!=") # a.set_bindrule("groupdn = \"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"") a.set_bindrule_keyword("groupdn") a.set_bindrule_operator("=") a.set_bindrule_expression ("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"") a.permissions = ['read','write','add'] print a b = ACI() b.name ="foo" b.set_target_attr(['givenname','title'], "!=") b.set_bindrule_keyword("groupdn") b.set_bindrule_operator("=") b.set_bindrule_expression ("\"ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com\"") b.permissions = ['add','read','write'] print b print a.isequal(b) a = ACI('(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)') print a a = ACI('(targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup))")(targetattr != "aci || userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,dc=greyoak,dc=com";)') print a freeipa-3.3.4/ipalib/output.py0000664000175000017500000001021012202434255015645 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # Copyright (C) 2009 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 . """ Simple description of return values. """ from inspect import getdoc from types import NoneType from plugable import ReadOnly, lock from text import _ class Output(ReadOnly): """ Simple description of a member in the return value ``dict``. This class controls both the type of object being returned by a command as well as how the output will be displayed. For example, this class defines two return results: an entry and a value. >>> from ipalib import crud, output >>> class user(crud.Update): ... ... has_output = ( ... output.Entry('result'), ... output.value, ... ) The order of the values in has_output controls the order of output. If you have values that you don't want to be printed then add ``'no_display'`` to flags. The difference between ``'no_display'`` and ``'no_output'`` is that ``'no_output'`` will prevent a Param value from being returned at all. ``'no_display'`` will cause the API to return a value, it simply won't be displayed to the user. This is so some things may be returned that while not interesting to us, but may be to others. >>> from ipalib import crud, output >>> myvalue = output.Output('myvalue', unicode, ... 'Do not print this value', flags=['no_display'], ... ) >>> class user(crud.Update): ... ... has_output = ( ... output.Entry('result'), ... myvalue, ... ) """ type = None validate = None doc = None flags = [] def __init__(self, name, type=None, doc=None, flags=[]): self.name = name if type is not None: self.type = type if doc is not None: self.doc = doc self.flags = flags lock(self) def __repr__(self): return '%s(%r, %r, %r)' % ( self.__class__.__name__, self.name, self.type, self.doc, ) class Entry(Output): type = dict doc = _('A dictionary representing an LDAP entry') emsg = """%s.validate_output() => %s.validate(): output[%r][%d]: need a %r; got a %r: %r""" class ListOfEntries(Output): type = (list, tuple) doc = _('A list of LDAP entries') def validate(self, cmd, entries): assert isinstance(entries, self.type) for (i, entry) in enumerate(entries): if not isinstance(entry, dict): raise TypeError(emsg % (cmd.name, self.__class__.__name__, self.name, i, dict, type(entry), entry) ) result = Output('result', doc=_('All commands should at least have a result')) summary = Output('summary', (unicode, NoneType), _('User-friendly description of action performed') ) value = Output('value', unicode, _("The primary_key value of the entry, e.g. 'jdoe' for a user"), flags=['no_display'], ) standard = (summary, result) standard_entry = ( summary, Entry('result'), value, ) standard_list_of_entries = ( summary, ListOfEntries('result'), Output('count', int, _('Number of entries returned')), Output('truncated', bool, _('True if not all results were returned')), ) standard_delete = ( summary, Output('result', dict, _('List of deletions that failed')), value, ) standard_boolean = ( summary, Output('result', bool, _('True means the operation was successful')), value, ) standard_value = standard_boolean freeipa-3.3.4/ipalib/cli.py0000664000175000017500000013006412271663206015074 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Functionality for Command Line Interface. """ import re import textwrap import sys import getpass import code import optparse import socket import fcntl import termios import struct import base64 try: #pylint: disable=F0401 import default_encoding_utf8 except ImportError: # This is a chicken-and-egg problem. The api can't be imported unless # this is already installed and since it is installed with IPA therein # lies the problem. Skip it for now so ipalib can be imported in-tree # even in cases that IPA isn't installed on the dev machine. pass import frontend import backend import plugable import util from errors import (PublicError, CommandError, HelpError, InternalError, NoSuchNamespaceError, ValidationError, NotFound, NotConfiguredError, PromptFailed, ConversionError) from constants import CLI_TAB from parameters import Password, Bytes, File, Str, StrEnum, Any from text import _ from ipapython.version import API_VERSION def to_cli(name): """ Takes a Python identifier and transforms it into form suitable for the Command Line Interface. """ assert isinstance(name, str) return name.replace('_', '-') def from_cli(cli_name): """ Takes a string from the Command Line Interface and transforms it into a Python identifier. """ return str(cli_name).replace('-', '_') class textui(backend.Backend): """ Backend plugin to nicely format output to stdout. """ def get_tty_width(self): """ Return the width (in characters) of output tty. If stdout is not a tty, this method will return ``None``. """ # /usr/include/asm/termios.h says that struct winsize has four # unsigned shorts, hence the HHHH if sys.stdout.isatty(): try: winsize = fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0)) return struct.unpack('HHHH', winsize)[1] except IOError: return None def max_col_width(self, rows, col=None): """ Return the max width (in characters) of a specified column. For example: >>> ui = textui() >>> rows = [ ... ('a', 'package'), ... ('an', 'egg'), ... ] >>> ui.max_col_width(rows, col=0) # len('an') 2 >>> ui.max_col_width(rows, col=1) # len('package') 7 >>> ui.max_col_width(['a', 'cherry', 'py']) # len('cherry') 6 """ if type(rows) not in (list, tuple): raise TypeError( 'rows: need %r or %r; got %r' % (list, tuple, rows) ) if len(rows) == 0: return 0 if col is None: return max(len(row) for row in rows) return max(len(row[col]) for row in rows) def __get_encoding(self, stream): assert stream in (sys.stdin, sys.stdout) if getattr(stream, 'encoding', None) is None: return 'UTF-8' return stream.encoding def decode(self, value): """ Decode text from stdin. """ if type(value) is str: encoding = self.__get_encoding(sys.stdin) return value.decode(encoding) elif type(value) in (list, tuple): return tuple(self.decode(v) for v in value) return value def encode(self, unicode_text): """ Encode text for output to stdout. """ assert type(unicode_text) is unicode encoding = self.__get_encoding(sys.stdout) return unicode_text.encode(encoding) def choose_number(self, n, singular, plural=None): if n == 1 or plural is None: return singular % n return plural % n def encode_binary(self, value): """ Convert a binary value to base64. We know a value is binary if it is a python str type, otherwise it is a plain string. """ if type(value) is str: return base64.b64encode(value) else: return value def print_plain(self, string): """ Print exactly like ``print`` statement would. """ print unicode(string) def print_line(self, text, width=None): """ Force printing on a single line, using ellipsis if needed. For example: >>> ui = textui() >>> ui.print_line('This line can fit!', width=18) This line can fit! >>> ui.print_line('This line wont quite fit!', width=18) This line wont ... The above example aside, you normally should not specify the ``width``. When you don't, it is automatically determined by calling `textui.get_tty_width()`. """ if width is None: width = self.get_tty_width() if width is not None and width < len(text): text = text[:width - 3] + '...' print unicode(text) def print_paragraph(self, text, width=None): """ Print a paragraph, automatically word-wrapping to tty width. For example: >>> text = ''' ... Python is a dynamic object-oriented programming language that can ... be used for many kinds of software development. ... ''' >>> ui = textui() >>> ui.print_paragraph(text, width=45) Python is a dynamic object-oriented programming language that can be used for many kinds of software development. The above example aside, you normally should not specify the ``width``. When you don't, it is automatically determined by calling `textui.get_tty_width()`. The word-wrapping is done using the Python ``textwrap`` module. See: http://docs.python.org/library/textwrap.html """ if width is None: width = self.get_tty_width() for line in textwrap.wrap(text.strip(), width): print line def print_indented(self, text, indent=1): """ Print at specified indentation level. For example: >>> ui = textui() >>> ui.print_indented('One indentation level.') One indentation level. >>> ui.print_indented('Two indentation levels.', indent=2) Two indentation levels. >>> ui.print_indented('No indentation.', indent=0) No indentation. """ print (CLI_TAB * indent + text) def print_keyval(self, rows, indent=1): """ Print (key = value) pairs, one pair per line. For example: >>> items = [ ... ('in_server', True), ... ('mode', u'production'), ... ] >>> ui = textui() >>> ui.print_keyval(items) in_server = True mode = u'production' >>> ui.print_keyval(items, indent=0) in_server = True mode = u'production' Also see `textui.print_indented`. """ for (key, value) in rows: self.print_indented('%s = %r' % (key, self.encode_binary(value)), indent) def print_attribute(self, attr, value, format='%s: %s', indent=1, one_value_per_line=True): """ Print an ldap attribute. For example: >>> attr = 'dn' >>> ui = textui() >>> ui.print_attribute(attr, u'dc=example,dc=com') dn: dc=example,dc=com >>> attr = 'objectClass' >>> ui.print_attribute(attr, [u'top', u'someClass'], one_value_per_line=False) objectClass: top, someClass >>> ui.print_attribute(attr, [u'top', u'someClass']) objectClass: top objectClass: someClass """ assert isinstance(attr, basestring) if not isinstance(value, (list, tuple)): # single-value attribute self.print_indented(format % (attr, self.encode_binary(value)), indent) else: # multi-value attribute if one_value_per_line: for v in value: self.print_indented(format % (attr, self.encode_binary(v)), indent) else: value = map(lambda v: self.encode_binary(v), value) if len(value) > 0 and type(value[0]) in (list, tuple): # This is where we print failed add/remove members for l in value: text = ': '.join(l) self.print_indented(format % (attr, self.encode_binary(text)), indent) return else: if len(value) > 0: text = ', '.join(str(v) for v in value) else: return line_len = self.get_tty_width() if line_len and text: s_indent = '%s%s' % ( CLI_TAB * indent, ' ' * (len(attr) + 2) ) line_len -= len(s_indent) text = textwrap.wrap( text, line_len, break_long_words=False ) if len(text) == 0: text = [u''] else: text = [text] self.print_indented(format % (attr, text[0]), indent) for line in text[1:]: self.print_plain('%s%s' % (s_indent, line)) def print_entry1(self, entry, indent=1, attr_map={}, attr_order=['dn'], one_value_per_line=True): """ Print an ldap entry dict. """ assert isinstance(entry, dict) assert isinstance(attr_map, dict) assert isinstance(attr_order, (list, tuple)) def print_attr(a): if attr in attr_map: self.print_attribute( attr_map[attr], entry[attr], indent=indent, one_value_per_line=one_value_per_line ) else: self.print_attribute( attr, entry[attr], indent=indent, one_value_per_line=one_value_per_line ) for attr in attr_order: if attr in entry: print_attr(attr) del entry[attr] for attr in sorted(entry): print_attr(attr) def print_entries(self, entries, order=None, labels=None, flags=None, print_all=True, format='%s: %s', indent=1): assert isinstance(entries, (list, tuple)) first = True for entry in entries: if not first: print '' first = False self.print_entry(entry, order, labels, flags, print_all, format, indent) def print_entry(self, entry, order=None, labels=None, flags=None, print_all=True, format='%s: %s', indent=1): """ """ if isinstance(entry, (list, tuple)): entry = dict(entry) assert isinstance(entry, dict) if labels is None: labels = dict() one_value_per_line = True else: one_value_per_line = False if order is not None: for key in order: if key not in entry: continue label = labels.get(key, key) flag = flags.get(key, []) value = entry[key] if 'suppress_empty' in flag and value in [u'', '', [], None]: continue if isinstance(value, dict): if frontend.entry_count(value) == 0: continue self.print_indented(format % (label, ''), indent) self.print_entry( value, order, labels, flags, print_all, format, indent=indent+1 ) else: if isinstance(value, (list, tuple)) and \ all(isinstance(val, dict) for val in value): # this is a list of entries (dicts), not values self.print_attribute(label, u'', format, indent) self.print_entries(value, order, labels, flags, print_all, format, indent+1) else: self.print_attribute( label, value, format, indent, one_value_per_line ) del entry[key] if print_all: for key in sorted(entry): label = labels.get(key, key) self.print_attribute( key, entry[key], format, indent, one_value_per_line ) def print_dashed(self, string, above=True, below=True, indent=0, dash='-'): """ Print a string with a dashed line above and/or below. For example: >>> ui = textui() >>> ui.print_dashed('Dashed above and below.') ----------------------- Dashed above and below. ----------------------- >>> ui.print_dashed('Only dashed below.', above=False) Only dashed below. ------------------ >>> ui.print_dashed('Only dashed above.', below=False) ------------------ Only dashed above. """ assert isinstance(dash, basestring) assert len(dash) == 1 dashes = dash * len(string) if above: self.print_indented(dashes, indent) self.print_indented(string, indent) if below: self.print_indented(dashes, indent) def print_h1(self, text): """ Print a primary header at indentation level 0. For example: >>> ui = textui() >>> ui.print_h1('A primary header') ================ A primary header ================ """ self.print_dashed(text, indent=0, dash='=') def print_h2(self, text): """ Print a secondary header at indentation level 1. For example: >>> ui = textui() >>> ui.print_h2('A secondary header') ------------------ A secondary header ------------------ """ self.print_dashed(text, indent=1, dash='-') def print_name(self, name): """ Print a command name. The typical use for this is to mark the start of output from a command. For example, a hypothetical ``show_status`` command would output something like this: >>> ui = textui() >>> ui.print_name('show_status') ------------ show-status: ------------ """ self.print_dashed('%s:' % to_cli(name)) def print_header(self, msg, output): self.print_dashed(msg % output) def print_summary(self, msg): """ Print a summary at the end of a comand's output. For example: >>> ui = textui() >>> ui.print_summary('Added user "jdoe"') ----------------- Added user "jdoe" ----------------- """ self.print_dashed(msg) def print_count(self, count, singular, plural=None): """ Print a summary count. The typical use for this is to print the number of items returned by a command, especially when this return count can vary. This preferably should be used as a summary and should be the final text a command outputs. For example: >>> ui = textui() >>> ui.print_count(1, '%d goose', '%d geese') ------- 1 goose ------- >>> ui.print_count(['Don', 'Sue'], 'Found %d user', 'Found %d users') ------------- Found 2 users ------------- If ``count`` is not an integer, it must be a list or tuple, and then ``len(count)`` is used as the count. """ if type(count) is not int: assert type(count) in (list, tuple, dict) count = len(count) self.print_dashed( self.choose_number(count, singular, plural) ) def print_error(self, text): print ' ** %s **' % unicode(text) def prompt_helper(self, prompt, label, prompt_func=raw_input): """Prompt user for input Handles encoding the prompt and decoding the input. On end of stream or ctrl+c, raise PromptFailed. """ try: return self.decode(prompt_func(self.encode(prompt))) except (KeyboardInterrupt, EOFError): print raise PromptFailed(name=label) def print_prompt_attribute_error(self, attribute, error): self.print_plain('>>> %s: %s' % (attribute, error)) def prompt(self, label, default=None, get_values=None, optional=False): """ Prompt user for input. """ # TODO: Add tab completion using readline if optional: prompt = u'[%s]' % label else: prompt = u'%s' % label if default is None: prompt = u'%s: ' % prompt else: prompt = u'%s [%s]: ' % (prompt, default) return self.prompt_helper(prompt, label) def prompt_yesno(self, label, default=None): """ Prompt user for yes/no input. This method returns True/False according to user response. Parameter "default" should be True, False or None If Default parameter is not None, user can enter an empty input instead of Yes/No answer. Value passed to Default is returned in that case. If Default parameter is None, user is asked for Yes/No answer until a correct answer is provided. Answer is then returned. """ default_prompt = None if default is not None: if default: default_prompt = "Yes" else: default_prompt = "No" if default_prompt: prompt = u'%s Yes/No (default %s): ' % (label, default_prompt) else: prompt = u'%s Yes/No: ' % label while True: data = self.prompt_helper(prompt, label).lower() #pylint: disable=E1103 if data in (u'yes', u'y'): return True elif data in ( u'n', u'no'): return False elif default is not None and data == u'': return default def prompt_password(self, label, confirm=True): """ Prompt user for a password or read it in via stdin depending on whether there is a tty or not. """ if sys.stdin.isatty(): prompt = u'%s: ' % unicode(label) repeat_prompt = unicode(_('Enter %(label)s again to verify: ') % dict(label=label)) while True: pw1 = self.prompt_helper(prompt, label, prompt_func=getpass.getpass) if not confirm: return pw1 pw2 = self.prompt_helper(repeat_prompt, label, prompt_func=getpass.getpass) if pw1 == pw2: return pw1 self.print_error( _('Passwords do not match!')) else: return self.decode(sys.stdin.readline().strip()) def select_entry(self, entries, format, attrs, display_count=True): """ Display a list of lines in with formatting defined in ``format``. ``attrs`` is a list of attributes in the format. Prompt user for a selection and return the value (index of ``entries`` -1). If only one entry is provided then always return 0. Return: 0..n for the index of the selected entry -1 if all entries should be displayed -2 to quit, no entries to be displayed """ if not self.env.interactive or not sys.stdout.isatty(): return -1 counter = len(entries) if counter == 0: raise NotFound(reason=_("No matching entries found")) i = 1 for e in entries: # There is no guarantee that all attrs are in any given # entry d = {} for a in attrs: d[a] = e.get(a, '') self.print_line("%d: %s" % (i, format % d)) i = i + 1 if display_count: self.print_count(entries, 'Found %d match', 'Found %d matches') while True: try: resp = self.prompt("Choose one: (1 - %s), a for all, q to quit" % counter) except EOFError: return -2 if resp.lower() == "q": #pylint: disable=E1103 return -2 if resp.lower() == "a": #pylint: disable=E1103 return -1 try: selection = int(resp) - 1 if (selection >= 0 and selection < counter): break except: # fall through to the error msg pass self.print_line("Please enter a number between 1 and %s" % counter) self.print_line('') return selection class help(frontend.Local): """ Display help for a command or topic. """ takes_args = ( Str('command?', cli_name='topic', label=_('Topic or Command'), doc=_('The topic or command name.')), ) takes_options = ( Any('outfile?', flags=['no_option']), ) has_output = tuple() _PLUGIN_BASE_MODULE = 'ipalib.plugins' def _get_command_module(self, module): """ Return last part of ``module`` name, or ``None`` if module is this file. For example: """ if module == __name__: return return module.split('.')[-1] def _get_module_topic(self, module_name): if not sys.modules[module_name]: __import__(module_name) module = sys.modules[module_name] topic = getattr(module, 'topic', None) if topic is None: topic = (self._get_command_module(module_name), None) return topic def _count_topic_mcl(self, topic_name, mod_name): mcl = max((self._topics[topic_name][1], len(mod_name))) self._topics[topic_name][1] = mcl def _on_finalize(self): # {topic: ["description", mcl, {"subtopic": ["description", mcl, [commands]]}]} # {topic: ["description", mcl, [commands]]} self._topics = {} # [builtin_commands] self._builtins = [] # build help topics for c in self.Command(): if c.NO_CLI: continue topic = self._get_module_topic(c.module) topic_name = topic[0] if topic_name: if topic[1] is None: # a module without grouping if topic_name in self._topics: self._topics[topic_name][2].append(c) else: m = '%s.%s' % (self._PLUGIN_BASE_MODULE, topic_name) doc = ( unicode(_(sys.modules[m].__doc__)) or '' ).strip().split('\n', 1)[0] self._topics[topic_name] = [doc, 0, [c]] mcl = max((self._topics[topic_name][1], len(c.name))) self._topics[topic_name][1] = mcl else: # a module grouped in a topic doc = ( unicode(_(sys.modules[c.module].__doc__)) or '' ).strip().split('\n', 1)[0] mod_name = c.module.rsplit('.',1)[1] if topic_name in self._topics: if mod_name in self._topics[topic_name][2]: self._topics[topic_name][2][mod_name][2].append(c) else: self._topics[topic_name][2][mod_name] = [doc, 0, [c]] self._count_topic_mcl(topic_name, mod_name) # count mcl for for the subtopic mcl = max((self._topics[topic_name][2][mod_name][1], len(c.name))) self._topics[topic_name][2][mod_name][1] = mcl else: self._topics[topic_name] = [unicode(_(topic[1])), 0, {mod_name: [doc, 0, [c]]}] self._count_topic_mcl(topic_name, mod_name) else: self._builtins.append(c) # compute maximum topic length self._mtl = max( len(s) for s in (self._topics.keys() + [c.name for c in self._builtins]) ) super(help, self)._on_finalize() def run(self, key, outfile=None, **options): if outfile is None: outfile = sys.stdout writer = self._writer(outfile) name = from_cli(key) mod_name = '%s.%s' % (self._PLUGIN_BASE_MODULE, name) if key is None: self.api.parser.print_help(outfile) return if name == "topics": self.print_topics(outfile) return if name in self._topics: self.print_commands(name, outfile) elif name in self.Command: cmd = self.Command[name] if cmd.NO_CLI: raise HelpError(topic=name) self.Backend.cli.build_parser(cmd).print_help(outfile) elif mod_name in sys.modules: self.print_commands(name, outfile) elif name == "commands": mcl = max(len(s) for s in (self.Command)) for cname in self.Command: cmd = self.Command[cname] if cmd.NO_CLI: continue writer('%s %s' % (to_cli(cmd.name).ljust(mcl), cmd.summary)) else: raise HelpError(topic=name) def _writer(self, outfile): def writer(string=''): print >> outfile, unicode(string) return writer def print_topics(self, outfile): writer = self._writer(outfile) for t, topic in sorted(self._topics.items()): writer('%s %s' % (to_cli(t).ljust(self._mtl), topic[0])) def print_commands(self, topic, outfile): writer = self._writer(outfile) if topic in self._topics and type(self._topics[topic][2]) is dict: # we want to display topic which has subtopics for subtopic in self._topics[topic][2]: doc = self._topics[topic][2][subtopic][0] mcl = self._topics[topic][1] writer(' %s %s' % (to_cli(subtopic).ljust(mcl), doc)) else: # we want to display subtopic or a topic which has no subtopics if topic in self._topics: mcl = self._topics[topic][1] commands = self._topics[topic][2] else: commands = [] for t in self._topics: if type(self._topics[t][2]) is not dict: continue if topic not in self._topics[t][2]: continue mcl = self._topics[t][2][topic][1] commands = self._topics[t][2][topic][2] break m = '%s.%s' % (self._PLUGIN_BASE_MODULE, topic) doc = (unicode(_(sys.modules[m].__doc__)) or '').strip() if topic not in self.Command and len(commands) == 0: raise HelpError(topic=topic) writer(doc) if commands: writer() writer(_('Topic commands:')) for c in commands: writer( ' %s %s' % (to_cli(c.name).ljust(mcl), c.summary)) writer() writer(_('To get command help, use:')) writer(_(' ipa --help')) writer() class show_mappings(frontend.Command): """ Show mapping of LDAP attributes to command-line option. """ takes_args = ( Str('command_name', label=_('Command name'), ), ) has_output = tuple() def run(self, command_name, **options): command_name = from_cli(command_name) if command_name not in self.Command: raise CommandError(name=command_name) params = self.Command[command_name].options out = [('Parameter','LDAP attribute'), ('=========','==============')] mcl = len(out[0][0]) for param in params(): if param.exclude and 'webui' in param.exclude: continue out.append((param.cli_name, param.param_spec)) mcl = max(mcl,len(param.cli_name)) for item in out: print to_cli(item[0]).ljust(mcl)+' : '+item[1] class console(frontend.Command): """Start the IPA interactive Python console.""" has_output = tuple() def run(self, **options): code.interact( '(Custom IPA interactive Python console)', local=dict(api=self.api) ) class show_api(frontend.Command): 'Show attributes on dynamic API object' takes_args = ('namespaces*',) def run(self, namespaces): if namespaces is None: names = tuple(self.api) else: for name in namespaces: if name not in self.api: raise NoSuchNamespaceError(name=name) names = namespaces lines = self.__traverse(names) ml = max(len(l[1]) for l in lines) self.Backend.textui.print_name('run') first = True for line in lines: if line[0] == 0 and not first: print '' if first: first = False print '%s%s %r' % ( ' ' * line[0], line[1].ljust(ml), line[2], ) if len(lines) == 1: s = '1 attribute shown.' else: s = '%d attributes show.' % len(lines) self.Backend.textui.print_dashed(s) def __traverse(self, names): lines = [] for name in names: namespace = self.api[name] self.__traverse_namespace('%s' % name, namespace, lines) return lines def __traverse_namespace(self, name, namespace, lines, tab=0): lines.append((tab, name, namespace)) for member_name in namespace: member = namespace[member_name] lines.append((tab + 1, member_name, member)) if not hasattr(member, '__iter__'): continue for n in member: attr = member[n] if isinstance(attr, plugable.NameSpace) and len(attr) > 0: self.__traverse_namespace(n, attr, lines, tab + 2) cli_application_commands = ( help, console, show_api, ) class Collector(object): def __init__(self): object.__setattr__(self, '_Collector__options', {}) def __setattr__(self, name, value): if name in self.__options: v = self.__options[name] if type(v) is tuple: value = v + (value,) else: value = (v, value) self.__options[name] = value object.__setattr__(self, name, value) def __todict__(self): return dict(self.__options) class CLIOptionParserFormatter(optparse.IndentedHelpFormatter): def format_argument(self, name, help_string): result = [] opt_width = self.help_position - self.current_indent - 2 if len(name) > opt_width: name = "%*s%s\n" % (self.current_indent, "", name) indent_first = self.help_position else: # start help on same line as name name = "%*s%-*s " % (self.current_indent, "", opt_width, name) indent_first = 0 result.append(name) if help_string: help_lines = textwrap.wrap(help_string, self.help_width) result.append("%*s%s\n" % (indent_first, "", help_lines[0])) result.extend(["%*s%s\n" % (self.help_position, "", line) for line in help_lines[1:]]) elif name[-1] != "\n": result.append("\n") return "".join(result) class CLIOptionParser(optparse.OptionParser): """ This OptionParser subclass adds an ability to print positional arguments in CLI help. Custom formatter is used to format the argument list in the same way as OptionParser formats options. """ def __init__(self, *args, **kwargs): self._arguments = [] if 'formatter' not in kwargs: kwargs['formatter'] = CLIOptionParserFormatter() optparse.OptionParser.__init__(self, *args, **kwargs) def format_option_help(self, formatter=None): """ Prepend argument help to standard OptionParser's option help """ option_help = optparse.OptionParser.format_option_help(self, formatter) if isinstance(formatter, CLIOptionParserFormatter): heading = unicode(_("Positional arguments")) arguments = [formatter.format_heading(heading)] formatter.indent() for (name, help_string) in self._arguments: arguments.append(formatter.format_argument(name, help_string)) formatter.dedent() if len(arguments) > 1: # there is more than just the heading arguments.append(u"\n") else: arguments = [] option_help = "".join(arguments) + option_help return option_help def add_argument(self, name, help_string): self._arguments.append((name, help_string)) class cli(backend.Executioner): """ Backend plugin for executing from command line interface. """ def get_command(self, argv): """Given CLI arguments, return the Command to use On incorrect invocation, prints out a help message and returns None """ if len(argv) == 0: self.Command.help(outfile=sys.stderr) print >>sys.stderr print >>sys.stderr, 'Error: Command not specified' exit(2) (key, argv) = (argv[0], argv[1:]) name = from_cli(key) if name not in self.Command and len(argv) == 0: try: self.Command.help(unicode(key), outfile=sys.stderr) except HelpError: pass if name not in self.Command or self.Command[name].NO_CLI: raise CommandError(name=key) cmd = self.Command[name] return cmd def process_keyword_arguments(self, cmd, kw): """Get the keyword arguments for a Command""" if self.env.interactive: self.prompt_interactively(cmd, kw) try: callbacks = cmd.get_callbacks('interactive_prompt') except AttributeError: pass else: for callback in callbacks: callback(cmd, kw) kw['version'] = API_VERSION self.load_files(cmd, kw) return kw def run(self, argv): cmd = self.get_command(argv) if cmd is None: return name = cmd.name kw = self.parse(cmd, argv[1:]) if not isinstance(cmd, frontend.Local): self.create_context() try: kw = self.process_keyword_arguments(cmd, kw) result = self.execute(name, **kw) if callable(cmd.output_for_cli): for param in cmd.params(): if param.password and param.name in kw: del kw[param.name] (args, options) = cmd.params_2_args_options(**kw) rv = cmd.output_for_cli(self.api.Backend.textui, result, *args, **options) if rv: return rv else: return 0 finally: self.destroy_context() def parse(self, cmd, argv): parser = self.build_parser(cmd) (collector, args) = parser.parse_args(argv, Collector()) options = collector.__todict__() kw = cmd.args_options_2_params(*args, **options) return dict(self.parse_iter(cmd, kw)) # FIXME: Probably move decoding to Command, use same method regardless of # request source: def parse_iter(self, cmd, kw): """ Decode param values if appropriate. """ for (key, value) in kw.iteritems(): yield (key, self.Backend.textui.decode(value)) def build_parser(self, cmd): parser = CLIOptionParser( usage=' '.join(self.usage_iter(cmd)), description=unicode(cmd.doc), formatter=IPAHelpFormatter(), ) option_groups = {} for option in cmd.options(): kw = dict( dest=option.name, help=unicode(option.doc), ) if 'no_option' in option.flags: continue if option.password and self.env.interactive: kw['action'] = 'store_true' elif option.type is bool and option.autofill: if option.default is True: kw['action'] = 'store_false' else: kw['action'] = 'store_true' elif isinstance(option, StrEnum): kw['metavar'] = metavar=map(lambda x: str(x), option.values) else: kw['metavar'] = metavar=option.__class__.__name__.upper() if option.cli_short_name: o = optparse.make_option('-%s' % option.cli_short_name, '--%s' % to_cli(option.cli_name), **kw) else: o = optparse.make_option('--%s' % to_cli(option.cli_name), **kw) if option.option_group is not None: option_group = option_groups.get(option.option_group) if option_group is None: option_group = optparse.OptionGroup(parser, option.option_group) parser.add_option_group(option_group) option_groups[option.option_group] = option_group option_group.add_option(o) else: parser.add_option(o) for arg in cmd.args(): name = self.__get_arg_name(arg, format_name=False) if 'no_option' in arg.flags or name is None: continue doc = unicode(arg.doc) parser.add_argument(name, doc) return parser def __get_arg_name(self, arg, format_name=True): if arg.password: return name = to_cli(arg.cli_name).upper() if not format_name: return name if arg.multivalue: name = '%s...' % name if arg.required: return name else: return '[%s]' % name def usage_iter(self, cmd): yield 'Usage: %%prog [global-options] %s' % to_cli(cmd.name) for arg in cmd.args(): name = self.__get_arg_name(arg) if name is None: continue yield name yield '[options]' def prompt_interactively(self, cmd, kw): """ Interactively prompt for missing or invalid values. By default this method will only prompt for *required* Param that have a missing or invalid value. However, if ``self.env.prompt_all`` is ``True``, this method will prompt for any params that have a missing values, even if the param is optional. """ honor_alwaysask = True for param in cmd.params(): if param.alwaysask and param.name in kw: honor_alwaysask = False break for param in cmd.params(): if (param.required and param.name not in kw) or \ (param.alwaysask and honor_alwaysask) or self.env.prompt_all: if param.autofill: kw[param.name] = cmd.get_default_of(param.name, **kw) if param.name in kw and kw[param.name] is not None: continue if param.password: kw[param.name] = self.Backend.textui.prompt_password( param.label, param.confirm ) else: default = cmd.get_default_of(param.name, **kw) optional = param.alwaysask or not param.required value = cmd.prompt_param(param, default=default, optional=optional, kw=kw) if value is not None: kw[param.name] = value elif param.password and kw.get(param.name, False) is True: kw[param.name] = self.Backend.textui.prompt_password( param.label, param.confirm ) def load_files(self, cmd, kw): """ Load files from File parameters. This has to be done after all required parameters have been read (i.e. after prompt_interactively has or would have been called) AND before they are passed to the command. This is because: 1) we need to be sure no more files are going to be added 2) we load files from the machine where the command was executed 3) the webUI will use a different way of loading files """ for p in cmd.params(): if isinstance(p, File): # FIXME: this only reads the first file raw = None if p.name in kw: if type(kw[p.name]) in (tuple, list): fname = kw[p.name][0] else: fname = kw[p.name] try: f = open(fname, 'r') raw = f.read() f.close() except IOError, e: raise ValidationError( name=to_cli(p.cli_name), error='%s: %s:' % (fname, e[1]) ) elif p.stdin_if_missing: try: raw = sys.stdin.read() except IOError, e: raise ValidationError( name=to_cli(p.cli_name), error=e[1] ) if not raw: raise ValidationError( name=to_cli(p.cli_name), error=_('No file to read') ) kw[p.name] = self.Backend.textui.decode(raw) class IPAHelpFormatter(optparse.IndentedHelpFormatter): """Formatter suitable for printing IPA command help The default help formatter reflows text to fit the terminal, but it ignores line/paragraph breaks. IPA's descriptions already have correct line breaks. This formatter doesn't touch them (save for removing initial/trailing whitespace). """ def format_description(self, description): if description: return description.strip() else: return "" cli_plugins = ( cli, textui, console, help, show_mappings, ) def run(api): error = None try: (options, argv) = api.bootstrap_with_global_options(context='cli') for klass in cli_plugins: api.register(klass) api.load_plugins() api.finalize() if not 'config_loaded' in api.env: raise NotConfiguredError() sys.exit(api.Backend.cli.run(argv)) except KeyboardInterrupt: print '' api.log.info('operation aborted') except PublicError, e: error = e except StandardError, e: api.log.exception('%s: %s', e.__class__.__name__, str(e)) error = InternalError() if error is not None: assert isinstance(error, PublicError) api.log.error(error.strerror) sys.exit(error.rval) freeipa-3.3.4/ipalib/text.py0000664000175000017500000004107712270466515015321 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # Copyright (C) 2009 Red Hat # see file 'COPYING' for use and warranty contextrmation # # 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 . """ Defers gettext translation till request time. IPA presents some tricky gettext challenges. On the one hand, most translatable message are defined as class attributes on the plugins, which means these get evaluated at module-load time. But on the other hand, each request to the server can be in a different locale, so the actual translation must not occur till request time. The `text` module provides a mechanism for for deferred gettext translation. It was designed to: 1. Allow translatable strings to be marked with the usual ``_()`` and ``ngettext()`` functions so that standard tools like xgettext can still be used 2. Allow programmers to mark strings in a natural way without burdening them with details of the deferred translation mechanism A typical plugin will use the deferred translation like this: >>> from ipalib import Command, _, ngettext >>> class my_plugin(Command): ... my_string = _('Hello, %(name)s.') ... my_plural = ngettext('%(count)d goose', '%(count)d geese', 0) ... With normal gettext usage, the *my_string* and *my_plural* message would be translated at module-load-time when your ``my_plugin`` class is defined. This would mean that all message are translated in the locale of the server rather than the locale of the request. However, the ``_()`` function above is actually a `GettextFactory` instance, which when called returns a `Gettext` instance. A `Gettext` instance stores the message to be translated, and the gettext domain and localedir, but it doesn't perform the translation till `Gettext.__unicode__()` is called. For example: >>> my_plugin.my_string Gettext('Hello, %(name)s.', domain='ipa', localedir=None) >>> unicode(my_plugin.my_string) u'Hello, %(name)s.' Translation can also be performed via the `Gettext.__mod__()` convenience method. For example, these two are equivalent: >>> my_plugin.my_string % dict(name='Joe') u'Hello, Joe.' >>> unicode(my_plugin.my_string) % dict(name='Joe') # Long form u'Hello, Joe.' Similar to ``_()``, the ``ngettext()`` function above is actually an `NGettextFactory` instance, which when called returns an `NGettext` instance. An `NGettext` instance stores the singular and plural messages, and the gettext domain and localedir, but it doesn't perform the translation till `NGettext.__call__()` is called. For example: >>> my_plugin.my_plural NGettext('%(count)d goose', '%(count)d geese', domain='ipa', localedir=None) >>> my_plugin.my_plural(1) u'%(count)d goose' >>> my_plugin.my_plural(2) u'%(count)d geese' Translation can also be performed via the `NGettext.__mod__()` convenience method. For example, these two are equivalent: >>> my_plugin.my_plural % dict(count=1) u'1 goose' >>> my_plugin.my_plural(1) % dict(count=1) # Long form u'1 goose' Lastly, 3rd-party plugins can create factories bound to a different gettext domain. The default domain is ``'ipa'``, which is also the domain of the standard ``ipalib._()`` and ``ipalib.ngettext()`` factories. But 3rd-party plugins can create their own factories like this: >>> from ipalib import GettextFactory, NGettextFactory >>> _ = GettextFactory(domain='ipa_foo') >>> ngettext = NGettextFactory(domain='ipa_foo') >>> class foo(Command): ... msg1 = _('Foo!') ... msg2 = ngettext('%(count)d bar', '%(count)d bars', 0) ... Notice that these messages are bound to the ``'ipa_foo'`` domain: >>> foo.msg1 Gettext('Foo!', domain='ipa_foo', localedir=None) >>> foo.msg2 NGettext('%(count)d bar', '%(count)d bars', domain='ipa_foo', localedir=None) For additional details, see `GettextFactory` and `Gettext`, and for plural forms, see `NGettextFactory` and `NGettext`. """ import threading import locale import gettext from request import context def create_translation(key): assert key not in context.__dict__ (domain, localedir) = key translation = gettext.translation(domain, localedir=localedir, languages=getattr(context, 'languages', None), fallback=True, ) context.__dict__[key] = translation return translation class LazyText(object): """ Base class for deferred translation. This class is not used directly. See the `Gettext` and `NGettext` subclasses. """ __slots__ = ('domain', 'localedir', 'key', 'args') def __init__(self, domain=None, localedir=None): """ Initialize. :param domain: The gettext domain in which this message will be translated, e.g. ``'ipa'`` or ``'ipa_3rd_party'``; default is ``None`` :param localedir: The directory containing the gettext translations, e.g. ``'/usr/share/locale/'``; default is ``None``, in which case gettext will use the default system locale directory. """ self.domain = domain self.localedir = localedir self.key = (domain, localedir) self.args = None def __eq__(self, other): """ Return ``True`` if this instances is equal to *other*. Note that this method cannot be used on the `LazyText` base class itself as subclasses must define an *args* instance attribute. """ if type(other) is not self.__class__: return False return self.args == other.args def __ne__(self, other): """ Return ``True`` if this instances is not equal to *other*. Note that this method cannot be used on the `LazyText` base class itself as subclasses must define an *args* instance attribute. """ return not self.__eq__(other) class Gettext(LazyText): """ Deferred translation using ``gettext.ugettext()``. Normally the `Gettext` class isn't used directly and instead is created via a `GettextFactory` instance. However, for illustration, we can create one like this: >>> msg = Gettext('Hello, %(name)s.') When you create a `Gettext` instance, the message is stored on the *msg* attribute: >>> msg.msg 'Hello, %(name)s.' No translation is performed till `Gettext.__unicode__()` is called. This will translate *msg* using ``gettext.ugettext()``, which will return the translated string as a Python ``unicode`` instance. For example: >>> unicode(msg) u'Hello, %(name)s.' `Gettext.__unicode__()` should be called at request time, which in a nutshell means it should be called from within your plugin's ``Command.execute()`` method. `Gettext.__unicode__()` will perform the translation based on the locale of the current request. `Gettext.__mod__()` is a convenience method for Python "percent" string formatting. It will translate your message using `Gettext.__unicode__()` and then perform the string substitution on the translated message. For example, these two are equivalent: >>> msg % dict(name='Joe') u'Hello, Joe.' >>> unicode(msg) % dict(name='Joe') # Long form u'Hello, Joe.' See `GettextFactory` for additional details. If you need to pick between singular and plural form, use `NGettext` instances via the `NGettextFactory`. """ __slots__ = ('msg') def __init__(self, msg, domain=None, localedir=None): super(Gettext, self).__init__(domain, localedir) self.msg = msg self.args = (msg, domain, localedir) def __repr__(self): return '%s(%r, domain=%r, localedir=%r)' % (self.__class__.__name__, self.msg, self.domain, self.localedir) def __unicode__(self): """ Translate this message and return as a ``unicode`` instance. """ if self.key in context.__dict__: g = context.__dict__[self.key].ugettext else: g = create_translation(self.key).ugettext return g(self.msg) def __json__(self): return self.__unicode__() def __mod__(self, kw): return self.__unicode__() % kw class FixMe(Gettext): """ Non-translated place-holder for UI labels. `FixMe` is a subclass of `Gettext` and is used for automatically created place-holder labels. It generally behaves exactly like `Gettext` except no translation is ever performed. `FixMe` allows programmers to get plugins working without first filling in all the labels that will ultimately be required, while at the same time it creates conspicuous looking UI labels that remind the programmer to "fix-me!". For example, the typical usage would be something like this: >>> class Plugin(object): ... label = None ... def __init__(self): ... self.name = self.__class__.__name__ ... if self.label is None: ... self.label = FixMe(self.name + '.label') ... assert isinstance(self.label, Gettext) ... >>> class user(Plugin): ... pass # Oops, we didn't set user.label yet ... >>> u = user() >>> u.label FixMe('user.label') Note that as `FixMe` is a subclass of `Gettext`, is passes the above type check using ``isinstance()``. Calling `FixMe.__unicode__()` performs no translation, but instead returns said conspicuous looking label: >>> unicode(u.label) u'' For more examples of how `FixMe` is used, see `ipalib.parameters`. """ __slots__ = tuple() def __repr__(self): return '%s(%r)' % (self.__class__.__name__, self.msg) def __unicode__(self): return u'<%s>' % self.msg class NGettext(LazyText): """ Deferred translation for plural forms using ``gettext.ungettext()``. Normally the `NGettext` class isn't used directly and instead is created via a `NGettextFactory` instance. However, for illustration, we can create one like this: >>> msg = NGettext('%(count)d goose', '%(count)d geese') When you create an `NGettext` instance, the singular and plural forms of your message are stored on the *singular* and *plural* instance attributes: >>> msg.singular '%(count)d goose' >>> msg.plural '%(count)d geese' The translation and number selection isn't performed till `NGettext.__call__()` is called. This will translate and pick the correct number using ``gettext.ungettext()``. As a callable, an `NGettext` instance takes a single argument, an integer specifying the count. For example: >>> msg(0) u'%(count)d geese' >>> msg(1) u'%(count)d goose' >>> msg(2) u'%(count)d geese' `NGettext.__mod__()` is a convenience method for Python "percent" string formatting. It can only be used if your substitution ``dict`` contains the count in a ``'count'`` item. For example: >>> msg % dict(count=0) u'0 geese' >>> msg % dict(count=1) u'1 goose' >>> msg % dict(count=2) u'2 geese' Alternatively, these longer forms have the same effect as the three examples above: >>> msg(0) % dict(count=0) u'0 geese' >>> msg(1) % dict(count=1) u'1 goose' >>> msg(2) % dict(count=2) u'2 geese' A ``KeyError`` is raised if your substitution ``dict`` doesn't have a ``'count'`` item. For example: >>> msg2 = NGettext('%(num)d goose', '%(num)d geese') >>> msg2 % dict(num=0) Traceback (most recent call last): ... KeyError: 'count' However, in this case you can still use the longer, explicit form for string substitution: >>> msg2(0) % dict(num=0) u'0 geese' See `NGettextFactory` for additional details. """ __slots__ = ('singular', 'plural') def __init__(self, singular, plural, domain=None, localedir=None): super(NGettext, self).__init__(domain, localedir) self.singular = singular self.plural = plural self.args = (singular, plural, domain, localedir) def __repr__(self): return '%s(%r, %r, domain=%r, localedir=%r)' % (self.__class__.__name__, self.singular, self.plural, self.domain, self.localedir) def __mod__(self, kw): count = kw['count'] return self(count) % kw def __call__(self, count): if self.key in context.__dict__: ng = context.__dict__[self.key].ungettext else: ng = create_translation(self.key).ungettext return ng(self.singular, self.plural, count) class GettextFactory(object): """ Factory for creating ``_()`` functions. A `GettextFactory` allows you to mark translatable messages that are evaluated at initialization time, but deferred their actual translation till request time. When you create a `GettextFactory` you can provide a specific gettext *domain* and *localedir*. By default the *domain* will be ``'ipa'`` and the *localedir* will be ``None``. Both are available via instance attributes of the same name. For example: >>> _ = GettextFactory() >>> _.domain 'ipa' >>> _.localedir is None True When the *localedir* is ``None``, gettext will use the default system localedir (typically ``'/usr/share/locale/'``). In general, you should **not** provide a *localedir*... it is intended only to support in-tree testing. Third party plugins will most likely want to use a different gettext *domain*. For example: >>> _ = GettextFactory(domain='ipa_3rd_party') >>> _.domain 'ipa_3rd_party' When you call your `GettextFactory` instance, it will return a `Gettext` instance associated with the same *domain* and *localedir*. For example: >>> my_msg = _('Hello world') >>> my_msg.domain 'ipa_3rd_party' >>> my_msg.localedir is None True The message isn't translated till `Gettext.__unicode__()` is called, which should be done during each request. See the `Gettext` class for additional details. """ def __init__(self, domain='ipa', localedir=None): """ Initialize. :param domain: The gettext domain in which this message will be translated, e.g. ``'ipa'`` or ``'ipa_3rd_party'``; default is ``'ipa'`` :param localedir: The directory containing the gettext translations, e.g. ``'/usr/share/locale/'``; default is ``None``, in which case gettext will use the default system locale directory. """ self.domain = domain self.localedir = localedir def __repr__(self): return '%s(domain=%r, localedir=%r)' % (self.__class__.__name__, self.domain, self.localedir) def __call__(self, msg): return Gettext(msg, self.domain, self.localedir) class NGettextFactory(GettextFactory): """ Factory for creating ``ngettext()`` functions. `NGettextFactory` is similar to `GettextFactory`, except `NGettextFactory` is for plural forms. So that standard tools like xgettext can find your plural forms, you should reference your `NGettextFactory` instance using a variable named *ngettext*. For example: >>> ngettext = NGettextFactory() >>> ngettext NGettextFactory(domain='ipa', localedir=None) When you call your `NGettextFactory` instance to create a deferred translation, you provide the *singular* message, the *plural* message, and a dummy *count*. An `NGettext` instance will be returned. For example: >>> my_msg = ngettext('%(count)d goose', '%(count)d geese', 0) >>> my_msg NGettext('%(count)d goose', '%(count)d geese', domain='ipa', localedir=None) The *count* is ignored (because the translation is deferred), but you should still provide it so parsing tools aren't confused. For consistency, it is recommended to always provide ``0`` for the *count*. See `NGettext` for details on how the deferred translation is later performed. See `GettextFactory` for details on setting a different gettext *domain* (likely needed for 3rd-party plugins). """ def __call__(self, singular, plural, count): return NGettext(singular, plural, self.domain, self.localedir) # Process wide factories: _ = GettextFactory() ngettext = NGettextFactory() ugettext = _ freeipa-3.3.4/ipalib/crud.pyc0000664000175000017500000002720512271707517015433 0ustar mkosekmkosekó †fçRc@sídZddlmZmZddlZddlZddlZddlZdefd„ƒYZdefd„ƒYZdefd „ƒYZ d efd „ƒYZ d efd „ƒYZ defd„ƒYZ dej fd„ƒYZdS(sâ Base classes for standard CRUD operations. These base classes are for `Method` plugins that provide standard Create, Retrieve, Updated, and Delete operations (CRUD) for their corresponding `Object` plugin. In particuar, these base classes provide logic to automatically create the plugin args and options by inspecting the params on their corresponding `Object` plugin. This provides a single point of definition for LDAP attributes and enforces a simple, consistent API for CRUD operations. For example, say we want CRUD operations on a hypothetical "user" entry. First we need an `Object` plugin: >>> from ipalib import Object, Str >>> class user(Object): ... takes_params = ( ... Str('login', primary_key=True), ... Str('first'), ... Str('last'), ... Str('ipauniqueid', flags=['no_create', 'no_update']), ... ) ... Next we need `Create`, `Retrieve`, `Updated`, and `Delete` plugins, and optionally a `Search` plugin. For brevity, we'll just define `Create` and `Retrieve` plugins: >>> from ipalib import crud >>> class user_add(crud.Create): ... pass ... >>> class user_show(crud.Retrieve): ... pass ... Now we'll register the plugins and finalize the `plugable.API` instance: >>> from ipalib import create_api >>> api = create_api() >>> api.register(user) >>> api.register(user_add) >>> api.register(user_show) >>> api.finalize() First, notice that our ``user`` `Object` has the params we defined with the ``takes_params`` tuple: >>> list(api.Object.user.params) ['login', 'first', 'last', 'ipauniqueid'] >>> api.Object.user.params.login Str('login', primary_key=True) Although we defined neither ``takes_args`` nor ``takes_options`` for our ``user_add`` plugin, the `Create` base class automatically generated them for us: >>> list(api.Command.user_add.args) ['login'] >>> list(api.Command.user_add.options) ['first', 'last', 'all', 'raw', 'version'] Notice that ``'ipauniqueid'`` isn't included in the options for our ``user_add`` plugin. This is because of the ``'no_create'`` flag we used when defining the ``ipauniqueid`` param. Often times there are LDAP attributes that are automatically created by the server and therefor should not be supplied as an option to the `Create` plugin. Often these same attributes shouldn't be update-able either, in which case you can also supply the ``'no_update'`` flag, as we did with our ``ipauniqueid`` param. Lastly, you can also use the ``'no_search'`` flag for attributes that shouldn't be search-able (because, for example, the attribute isn't indexed). As with our ``user_add` plugin, we defined neither ``takes_args`` nor ``takes_options`` for our ``user_show`` plugin; instead the `Retrieve` base class created them for us: >>> list(api.Command.user_show.args) ['login'] >>> list(api.Command.user_show.options) ['all', 'raw', 'version'] As you can see, `Retrieve` plugins take a single argument (the primary key) and no options. If needed, you can still specify options for your `Retrieve` plugin with a ``takes_options`` tuple. Flags like ``'no_create'`` remove LDAP attributes from those that can be supplied as *input* to a `Method`, but they don't effect the attributes that can be returned as *output*. Regardless of what flags have been used, the output entry (or list of entries) can contain all the attributes defined on the `Object` plugin (in our case, the above ``user.params``). For example, compare ``user.params`` with ``user_add.output_params`` and ``user_show.output_params``: >>> list(api.Object.user.params) ['login', 'first', 'last', 'ipauniqueid'] >>> list(api.Command.user_add.output_params) ['login', 'first', 'last', 'ipauniqueid'] >>> list(api.Command.user_show.output_params) ['login', 'first', 'last', 'ipauniqueid'] Note that the above are all equal. iÿÿÿÿ(tMethodtObjectNtCreatecBs)eZdZejZd„Zd„ZRS(s Create a new entry. ccs*|jjr&|jjjdtƒVndS(Nt attribute(tobjt primary_keytclonetTrue(tself((s)/home/mkosek/freeipa-clean/ipalib/crud.pytget_args…s c csö|jr1x%tt|ƒjƒD] }|VqWnx|jj|jƒD]v}d|jk}d|jkrqqGnd|jkr¬|jd|dt dt dt dt ƒVqG|jd|ƒVqGW|jsòx%tt|ƒjƒD] }|VqàWndS( Ntvirtual_attributet no_createt ask_createRtquerytrequiredtautofillt alwaysask( textra_options_firsttsuperRt get_optionsRt params_minustargstflagsRtFalseR(RtoptionR((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR‰s    (t__name__t __module__t__doc__toutputtstandard_entryt has_outputR R(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR~s  tPKQuerycBseZdZd„ZRS(s< Base class for `Retrieve`, `Update`, and `Delete`. ccs0|jjr,|jjjdtdtƒVndS(NRR (RRRR(R((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR ¢s (RRRR (((s)/home/mkosek/freeipa-clean/ipalib/crud.pyRstRetrievecBseZdZejZRS(s/ Retrieve an entry by its primary key. (RRRRRR(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR ©stUpdatecBs eZdZejZd„ZRS(s4 Update one or more attributes on an entry. ccsd|jr1x%tt|ƒjƒD] }|VqWnxû|jjƒD]ê}|j}d|jk}|jr}|jdgƒ}nd|jkr’qAnd|jkrÓ|j d|dt dt dt d t d |ƒVqAd |jkr|j d|dt d t d |ƒVqA|j d|dt dt d |ƒVqAW|js`x%tt|ƒjƒD] }|VqNWndS( NR tnonemptyt no_updatet ask_updateRR RRRRt req_update( RRR!RRtparams_minus_pkRRtunionRRR(RRt new_flagsR((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR¸s.        (RRRRRRR(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR!±s tDeletecBseZdZejZRS(s% Delete one or more entries. (RRRRtstandard_deleteR(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR)ÙstSearchcBs)eZdZejZd„Zd„ZRS(sB Retrieve all entries that match a given search criteria. ccstjddtƒVdS(Ns criteria?tnoextrawhitespace(t parameterstStrR(R((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR èsc csL|jr1x%tt|ƒjƒD] }|VqWnxã|jj|jƒD]Ì}d|jk}d|jkrqqGnd|jkr¬|jd|dt dt dt dt ƒVqGt |t j ƒrð|j|jt jd|dt dt dt ƒVqG|jd|dt dt dt ƒVqGW|jsHx%tt|ƒjƒD] }|Vq6WndS( NR t no_searcht ask_searchRR RRR(RRR+RRRRRRRRt isinstanceR-tFlagt clone_retypetnametBool(RRR((s)/home/mkosek/freeipa-clean/ipalib/crud.pyRës(     (RRRRtstandard_list_of_entriesRR R(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR+ás  t CrudBackendcBs;eZdZd„Zd„Zd„Zd„Zd„ZRS(s7 Base class defining generic CRUD backend API. cKstd|jƒ‚dS(sa Create a new entry. This method should take key word arguments representing the attributes the created entry will have. If this methods constructs the primary_key internally, it should raise an exception if the primary_key was passed. Likewise, if this method requires the primary_key to be passed in from the caller, it should raise an exception if the primary key was *not* passed. This method should return a dict of the exact entry as it was created in the backing store, including any automatically created attributes. s %s.create()N(tNotImplementedErrorR4(Rtkw((s)/home/mkosek/freeipa-clean/ipalib/crud.pytcreate scCstd|jƒ‚dS(sÌ Retrieve an existing entry. This method should take a two arguments: the primary_key of the entry in question and a list of the attributes to be retrieved. If the list of attributes is None then all non-operational attributes will be returned. If such an entry exists, this method should return a dict representing that entry. If no such entry exists, this method should return None. s %s.retrieve()N(R8R4(RRt attributes((s)/home/mkosek/freeipa-clean/ipalib/crud.pytretrieves cKstd|jƒ‚dS(s— Update an existing entry. This method should take one required argument, the primary_key of the entry to modify, plus optional keyword arguments for each of the attributes being updated. This method should return a dict representing the entry as it now exists in the backing store. If no such entry exists, this method should return None. s %s.update()N(R8R4(RRR9((s)/home/mkosek/freeipa-clean/ipalib/crud.pytupdate+s cCstd|jƒ‚dS(s“ Delete an existing entry. This method should take one required argument, the primary_key of the entry to delete. s %s.delete()N(R8R4(RR((s)/home/mkosek/freeipa-clean/ipalib/crud.pytdelete9scKstd|jƒ‚dS(s! Return entries matching specific criteria. This method should take keyword arguments representing the search criteria. If a key is the name of an entry attribute, the value should be treated as a filter on that attribute. The meaning of keys outside this namespace is left to the implementation. This method should return and iterable containing the matched entries, where each entry is a dict. If no entries are matched, this method should return an empty iterable. s %s.search()N(R8R4(RR9((s)/home/mkosek/freeipa-clean/ipalib/crud.pytsearchBs (RRRR:R<R=R>R?(((s)/home/mkosek/freeipa-clean/ipalib/crud.pyR7s     (RtfrontendRRtbackendR-RRRR R!R)R+t ConnectibleR7(((s)/home/mkosek/freeipa-clean/ipalib/crud.pytxs0 (%freeipa-3.3.4/ipalib/plugins/0000775000175000017500000000000012271707517015434 5ustar mkosekmkosekfreeipa-3.3.4/ipalib/plugins/config.pyc0000664000175000017500000002341712271707517017425 0ustar mkosekmkosekó †fçRc@sddlmZddlmZmZmZmZmZmZddlTddl m Z ddlm Z ddl m Z dZe d ƒZd „Zdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdS(iÿÿÿÿ(tapi(tBooltInttStrtIA5StrtStrEnumtDNParam(t*(tvalidate_selinuxuser(t_(tValidationErrort nsaccountlocktmembertmemberoftmemberindirecttmemberofindirects´ Server configuration Manage the default values that IPA uses and some of its tuning parameters. NOTES: The password notification value (--pwdexpnotify) is stored here so it will be replicated. It is not currently used to notify users in advance of an expiring password. Some attributes are read-only, provided only for information purposes. These include: Certificate Subject base: the configured certificate subject base, e.g. O=EXAMPLE.COM. This is configurable only at install time. Password plug-in features: currently defines additional hashes that the password will generate (there may be other conditions). When setting the order list for mapping SELinux users you may need to quote the value so it isn't interpreted by the shell. EXAMPLES: Show basic server configuration: ipa config-show Show all configuration options: ipa config-show --all Change maximum username length to 99 characters: ipa config-mod --maxusername=99 Increase default time and size limits for maximum IPA server search: ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000 Set default user e-mail domain: ipa config-mod --emaildomain=example.com Enable migration mode to make "ipa migrate-ds" command operational: ipa config-mod --enable-migration=TRUE Define SELinux user map order: ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023' cCs.|dkr*tdddtdƒƒ‚ndS(Nitnametipasearchtimelimitterrors"searchtimelimit must be -1 or > 1.(R R tNone(tugettexttlimit((s3/home/mkosek/freeipa-clean/ipalib/plugins/config.pytvalidate_searchtimelimitNs tconfigcBs_eZdZedƒZdddddddd d d d d ddddgZedƒZedƒZeddddedƒddƒe ddddedƒdedƒƒe ddddedƒdedƒƒe ddd ded!ƒded"ƒƒe d#dd$ded%ƒded%ƒƒede dd&ded'ƒded(ƒdd)ƒeddd*ded+ƒded,ƒdd)ƒe d dd-ded.ƒded/ƒƒe d dd0dd1ded2ƒƒe d dd3ded4ƒded4ƒƒe d dd5ded6ƒded7ƒd8d9gƒe d:dd;ded<ƒded=ƒd>eƒe d?dd@dedAƒdedBƒd>eƒed ddCdedDƒdedEƒddFƒedGdddedHƒdedIƒdJd[d>eƒe ddedNƒdedOƒƒe dPdedQƒdedRƒƒedSddTdedUƒdedVƒdJd\d>eƒfZdZ„ZRS(]s" IPA configuration object sconfiguration optionstipamaxusernamelengthtipahomesrootdirtipadefaultloginshelltipadefaultprimarygrouptipadefaultemaildomainRtipasearchrecordslimittipausersearchfieldstipagroupsearchfieldstipamigrationenabledtipacertificatesubjectbasetipapwdexpadvnotifytipaselinuxusermapordertipaselinuxusermapdefaulttipaconfigstringtipakrbauthzdatat Configurationtcli_namet maxusernametlabelsMaximum username lengthtminvalueit homedirectorysHome directory basetdocs$Default location of home directoriest defaultshells Default shellsDefault shell for new userst defaultgroupsDefault users groupsDefault group for new userssipadefaultemaildomain?t emaildomainsDefault e-mail domaintsearchtimelimitsSearch time limitsHMaximum amount of time (seconds) for a search (> 0, or -1 for unlimited)iÿÿÿÿtsearchrecordslimitsSearch size limits5Maximum number of records to search (-1 is unlimited)t usersearchsUser search fieldssFA comma-separated list of fields to search in when searching for userst groupsearchsGroup search fieldssGA comma-separated list of fields to search in when searching for groupstenable_migrationsEnable migration modetsubjectsCertificate Subject bases1Base for certificate subjects (OU=Test,O=Example)tflagst no_updatesipagroupobjectclasses+tgroupobjectclassessDefault group objectclassess2Default group objectclasses (comma-separated list)tcsvsipauserobjectclasses+tuserobjectclassessDefault user objectclassess1Default user objectclasses (comma-separated list)t pwdexpnotifys'Password Expiration Notification (days)s8Number of days's notice of impending password expirationisipaconfigstring*sPassword plugin featuress,Extra hashes to generate in password plug-intvaluesu AllowNThashuKDC:Disable Last SuccessuKDC:Disable LockoutsSELinux user map orders=Order in increasing priority of SELinux users, delimited by $sipaselinuxusermapdefault?sDefault SELinux users?Default SELinux user when no match is found in SELinux map rulesipakrbauthzdata*tpac_typesDefault PAC typess+Default types of PAC supported for servicesuMS-PACuPADunfs:NONEcOstddtjjƒS(Ntcnt ipaconfigtetc(scnR@(scnsetc(tDNRtenvtbasedn(tselftkeystkwargs((s3/home/mkosek/freeipa-clean/ipalib/plugins/config.pytget_dnÊs(u AllowNThashuKDC:Disable Last SuccessuKDC:Disable Lockout(uMS-PACuPADunfs:NONE(t__name__t __module__t__doc__R t object_nametdefault_attributesR*tlabel_singularRRRRRRtTrueRt takes_paramsRH(((s3/home/mkosek/freeipa-clean/ipalib/plugins/config.pyRSs¸                                                            t config_modcBseZedƒZd„ZRS(sModify configuration options.c Os§t|tƒst‚d|kru|d}ytjdj|ƒWqutjk rqtjdtdƒƒ‚quXni}d|kr”d|ds . ,  z g freeipa-3.3.4/ipalib/plugins/service.pyc0000664000175000017500000005012412271707517017613 0ustar mkosekmkosekó †fçRc@sÏddlZddlZddlmZmZmZddlmZmZmZm Z m Z ddl Tddlm Z ddlm Z mZddlmZddljZddlmZdd lmZe d ƒZed d e d ƒƒedd dƒedd e dƒƒedd e dƒƒedd e dƒƒedd e dƒƒedd e dƒƒedd e dƒƒedd e dƒƒedd e dƒƒed d e d!ƒƒf Ze d"d#d$d e d%ƒd&e d'ƒd(d)d*gƒe d+d#d,d e d-ƒd&e d.ƒd(d)d*gƒfZid/d06d1d26Zed0Zd3„Zd4„Zd5„Zd6„Zd7„Zd8„Zd9„Z d:„Z!d;e"fd<„ƒYZ#ej$e#ƒd=e%fd>„ƒYZ&ej$e&ƒd?e'fd@„ƒYZ(ej$e(ƒdAe)fdB„ƒYZ*ej$e*ƒdCe+fdD„ƒYZ,ej$e,ƒdEe-fdF„ƒYZ.ej$e.ƒdGe/fdH„ƒYZ0ej$e0ƒdIe1fdJ„ƒYZ2ej$e2ƒdKe3fdL„ƒYZ4ej$e4ƒdS(MiÿÿÿÿN(tapiterrorstutil(tStrtFlagtBytestStrEnumtBool(t*(tx509(t_tngettext(R(t NSPRError(t file_existss1 Services A IPA service represents a service that runs on a host. The IPA service record can store a Kerberos principal, an SSL certificate, or both. An IPA service can be managed directly from a machine, provided that machine has been given the correct permission. This is true even for machines other than the one the service is associated with. For example, requesting an SSL certificate using the host service principal credentials of the host. To manage a service using host credentials you need to kinit as the host: # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM Adding an IPA service allows the associated service to request an SSL certificate or keytab, but this is performed as a separate step; they are not produced as a result of adding the service. Only the public aspect of a certificate is stored in a service record; the private key is not stored. EXAMPLES: Add a new IPA service: ipa service-add HTTP/web.example.com Allow a host to manage an IPA service certificate: ipa service-add-host --hosts=web.example.com HTTP/web.example.com ipa role-add-member --hosts=web.example.com certadmin Override a default list of supported PAC types for the service: ipa service-mod HTTP/web.example.com --pac-type=MS-PAC A typical use case where overriding the PAC type is needed is NFS. Currently the related code in the Linux kernel can only handle Kerberos tickets up to a maximal size. Since the PAC data can become quite large it is recommended to set --pac-type=NONE for NFS services. Delete an IPA service: ipa service-del HTTP/web.example.com Find all IPA services associated with a host: ipa service-find web.example.com Find all HTTP services: ipa service-find HTTP Disable the service Kerberos key and SSL certificate: ipa service-disable HTTP/web.example.com Request a certificate for an IPA service: ipa cert-request --principal=HTTP/web.example.com example.csr Generate and retrieve a keytab for an IPA service: ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/httpd.keytab t has_keytabtlabeltKeytabtmanagedby_hosts Managed bytsubjecttSubjectt serial_numbers Serial Numbertserial_number_hexsSerial Number (hex)tissuertIssuertvalid_not_befores Not Beforetvalid_not_afters Not Aftertmd5_fingerprintsFingerprint (MD5)tsha1_fingerprintsFingerprint (SHA1)srevocation_reason?sRevocation reasonsipakrbrequirespreauth?tcli_nametrequires_pre_authsRequires pre-authenticationtdocs.Pre-authentication is required for the servicetflagstvirtual_attributet no_searchsipakrbokasdelegate?tok_as_delegatesTrusted for delegations2Client credentials may be delegated to the servicei€tipakrbrequirespreauthitipakrbokasdelegatecCs0d}}}|jdƒ}t|ƒdkrJtjdtdƒƒ‚n|d}t|ƒdkrtjdtdƒƒ‚n|djdƒ}t|ƒdkrÁtjdtd ƒƒ‚n|djƒ}t|ƒdkr|djƒ}|tj j kr#tj ƒ‚q#n tj j }|||fS( Nt/itreasonsmissing serviceis blank serviceit@sunable to determine realm( tNonetsplittlenRtMalformedServicePrincipalR tlowertupperRtenvtrealmt RealmMismatch(t principaltservicethostnameR/tsptsr((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytsplit_principal˜s$   cCst|ƒ\}}}dS(N(R6R((tugettextR1R2R3((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytvalidate_principalµscCs2t|ƒ\}}}d|||f}t|ƒS(Ns%s/%s@%s(R6tunicode(R1R2R3R/((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytnormalize_principal¹scCs[|rWtj|ƒrWytj|ƒWqWtk rS}tjdt|ƒƒ‚qWXndS(sA For now just verify that it is properly base64-encoded. R&N(Rtisvalid_base64tbase64t b64decodet ExceptionRtBase64DecodeErrortstr(R7tcertte((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytvalidate_certificateÀs cCs:d|krdSt|dƒttfkr=|dd}n |d}tj|ƒ}tj|dtjƒ}t|jƒ|dDssusercertificate?t certificatet Certificates"Base-64 encoded server certificateRR!sipakrbauthzdata*tpac_typesPAC typesOverride default list of supported PAC types. Use 'NONE' to disable PAC support for this service, e.g. this might be necessary for NFS services.tvaluesuMS-PACuPADuNONEtcsvcCs’|jdgƒ}|sdSt|ttfƒsCt|gƒ}n t|ƒ}d|krŽt|ƒdkrŽtjdddtdƒƒ‚ndS(NR„uNONEiRYRZs2NONE value cannot be combined with other PAC types( Rut isinstanceRGRHtsetR*RR\R (tselftentryt new_value((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytvalidate_ipakrbauthzdataWs (s Managed byR‡Rˆ(R‰R(uMS-PACuPADuNONE(t__name__t __module__t__doc__RR.tcontainer_servicet container_dnR t object_nametobject_name_pluralt object_classtpossible_objectclassestsearch_attributestdefault_attributestuuid_attributetattribute_memberstTruetbindablet relationshipstpassword_attributesRtlabel_singularRR8RRCRtticket_flags_paramst takes_paramsRš(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyR2"sL                         t service_addcBsveZedƒZedƒZdgZejeZej e ddedƒdedƒƒfZ d„Z d „Z RS( sAdd a new IPA new service.sAdded service "%(value)s"RƒtforceRtForceRs'force principal name even if not in DNSc Oszt|tƒst‚t|dƒ\}}} |jƒdkrZ|d rZtjƒ‚nytjd|ƒd} Wn0tj k r§tj dt dƒ|ƒ‚nX|j j |ƒ|j dƒ} | rütj| ƒ} tj||| ƒ| |ds  !( R›RœR RRÅt LDAPRetrieveRÉRRÇRÈRÃRð(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyRê*s     tservice_add_hostcBs*eZedƒZdgZejeZRS(s'Add hosts that can manage this service.Rƒ(R›RœR RRÅt LDAPAddMemberRÇRÈ(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyRõMs  tservice_remove_hostcBs*eZedƒZdgZejeZRS(s*Remove hosts that can manage this service.Rƒ(R›RœR RRÅtLDAPRemoveMemberRÇRÈ(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyR÷Vs  tservice_disablecBs?eZedƒZejZedƒZej e Z d„Z RS(s:Disable the Kerberos key and SSL certificate of a service.sDisabled service "%(value)s"cOs|jj}|jj||Ž}|j|dgƒ\}}t|dƒ\}}}t|||ƒt} d|kr¬|jjj rŒt j |j dƒdƒ} yžt t j| t jƒƒ} yhtjdt | ƒƒd} d| kr'y!tjdt | ƒddƒWq'tjk r#q'XnWntjk r>nXWqŒtk rˆ} | jd kr|jjd | jd ƒq‰| ‚qŒXn|j|idd6ƒt} n|jj|||ƒ|d râ|j|ƒt} n| s÷tjƒ‚ntdtd |dƒS(NRDiÿÿÿÿiRËR³RÌRÍii àÿÿsProblem decoding certificate %siRRo(R»tbackendtget_dnRbR6R^RvRR.RÎR RIRuR9RÐRKR¹RRÑR RÒR¾RÓRÔt update_entryR(R¨Rætremove_principal_keytAlreadyInactiveRò(R—R¿RkRVRcRSR2R3R/t done_workRARÕR³RÖ((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pytexecutefsF   !      ( R›RœR Rtoutputtstandard_valuet has_outputRÄt LDAPQueryRÇRÈR(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyRù_s     (5R<tostipalibRRRRRRRRtipalib.plugins.baseldapR R R tnss.nssRNt nss.errorR tipapython.ipautilR RRÈR­R`RhR6R8R:RCRTR^RrRyt LDAPObjectR2tregisterRÆR¯t LDAPDeleteRÊRÜR×RéRÝRôRêRöRõRøR÷RRù(((s4/home/mkosek/freeipa-clean/ipalib/plugins/service.pyts”  ( 9                                    D ; * - # !   <freeipa-3.3.4/ipalib/plugins/selfservice.py0000664000175000017500000001470612271663206020324 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib import api, _, ngettext from ipalib import Flag, Str from ipalib.request import context from ipalib import api, crud, errors from ipalib import output from ipalib import Object, Command from ipalib.plugins.baseldap import gen_pkey_only_option __doc__ = _(""" Self-service Permissions A permission enables fine-grained delegation of permissions. Access Control Rules, or instructions (ACIs), grant permission to permissions to perform given tasks such as adding a user, modifying a group, etc. A Self-service permission defines what an object can change in its own entry. EXAMPLES: Add a self-service rule to allow users to manage their address (using Bash brace expansion): ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c,st} "Users manage their own address" When managing the list of attributes you need to include all attributes in the list, including existing ones. Add telephoneNumber to the list (using Bash brace expansion): ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} "Users manage their own address" Display our updated rule: ipa selfservice-show "Users manage their own address" Delete a rule: ipa selfservice-del "Users manage their own address" """) ACI_PREFIX=u"selfservice" output_params = ( Str('aci', label=_('ACI'), ), ) class selfservice(Object): """ Selfservice object. """ bindable = False object_name = _('self service permission') object_name_plural = _('self service permissions') label = _('Self Service Permissions') label_singular = _('Self Service Permission') takes_params = ( Str('aciname', cli_name='name', label=_('Self-service name'), doc=_('Self-service name'), primary_key=True, pattern='^[-_ a-zA-Z0-9]+$', pattern_errmsg="May only contain letters, numbers, -, _, and space", ), Str('permissions*', cli_name='permissions', label=_('Permissions'), doc=_('Permissions to grant (read, write). Default is write.'), csv=True, ), Str('attrs+', cli_name='attrs', label=_('Attributes'), doc=_('Attributes to which the permission applies.'), csv=True, normalizer=lambda value: value.lower(), ), ) def __json__(self): json_friendly_attributes = ( 'label', 'label_singular', 'takes_params', 'bindable', 'name', 'object_name', 'object_name_plural', ) json_dict = dict( (a, getattr(self, a)) for a in json_friendly_attributes ) json_dict['primary_key'] = self.primary_key.name json_dict['methods'] = [m for m in self.methods] return json_dict def postprocess_result(self, result): try: # do not include prefix in result del result['aciprefix'] except KeyError: pass api.register(selfservice) class selfservice_add(crud.Create): __doc__ = _('Add a new self-service permission.') msg_summary = _('Added selfservice "%(value)s"') has_output_params = output_params def execute(self, aciname, **kw): if not 'permissions' in kw: kw['permissions'] = (u'write',) kw['selfaci'] = True kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_add'](aciname, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(selfservice_add) class selfservice_del(crud.Delete): __doc__ = _('Delete a self-service permission.') has_output = output.standard_boolean msg_summary = _('Deleted selfservice "%(value)s"') def execute(self, aciname, **kw): result = api.Command['aci_del'](aciname, aciprefix=ACI_PREFIX) self.obj.postprocess_result(result) return dict( result=True, value=aciname, ) api.register(selfservice_del) class selfservice_mod(crud.Update): __doc__ = _('Modify a self-service permission.') msg_summary = _('Modified selfservice "%(value)s"') has_output_params = output_params def execute(self, aciname, **kw): if 'attrs' in kw and kw['attrs'] is None: raise errors.RequirementError(name='attrs') kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_mod'](aciname, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(selfservice_mod) class selfservice_find(crud.Search): __doc__ = _('Search for a self-service permission.') msg_summary = ngettext( '%(count)d selfservice matched', '%(count)d selfservices matched', 0 ) takes_options = (gen_pkey_only_option("name"),) has_output_params = output_params def execute(self, term, **kw): kw['selfaci'] = True kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_find'](term, **kw)['result'] for aci in result: self.obj.postprocess_result(aci) return dict( result=result, count=len(result), truncated=False, ) api.register(selfservice_find) class selfservice_show(crud.Retrieve): __doc__ = _('Display information about a self-service permission.') has_output_params = output_params def execute(self, aciname, **kw): result = api.Command['aci_show'](aciname, aciprefix=ACI_PREFIX, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(selfservice_show) freeipa-3.3.4/ipalib/plugins/selfservice.pyc0000664000175000017500000001700012271707517020461 0ustar mkosekmkosekó †fçRc@s¦ddlmZmZmZddlmZmZddlmZddlmZmZm Z ddlm Z ddlm Z m Z ddl mZedƒZd Zed d ed ƒƒfZd e fd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdS(iÿÿÿÿ(tapit_tngettext(tFlagtStr(tcontext(Rtcrudterrors(toutput(tObjecttCommand(tgen_pkey_only_optionsÏ Self-service Permissions A permission enables fine-grained delegation of permissions. Access Control Rules, or instructions (ACIs), grant permission to permissions to perform given tasks such as adding a user, modifying a group, etc. A Self-service permission defines what an object can change in its own entry. EXAMPLES: Add a self-service rule to allow users to manage their address (using Bash brace expansion): ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c,st} "Users manage their own address" When managing the list of attributes you need to include all attributes in the list, including existing ones. Add telephoneNumber to the list (using Bash brace expansion): ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} "Users manage their own address" Display our updated rule: ipa selfservice-show "Users manage their own address" Delete a rule: ipa selfservice-del "Users manage their own address" u selfservicetacitlabeltACIt selfservicecBsøeZdZeZedƒZedƒZedƒZedƒZ e dddded ƒd ed ƒd e d d ddƒe ddddedƒd edƒde ƒe ddddedƒd edƒde dd„ƒfZ d„Z d„ZRS(s Selfservice object. sself service permissionsself service permissionssSelf Service PermissionssSelf Service Permissiontacinametcli_nametnameR sSelf-service nametdoct primary_keytpatterns^[-_ a-zA-Z0-9]+$tpattern_errmsgs2May only contain letters, numbers, -, _, and spaces permissions*t permissionst Permissionss5Permissions to grant (read, write). Default is write.tcsvsattrs+tattrst Attributess+Attributes to which the permission applies.t normalizercCs |jƒS(N(tlower(tvalue((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyt`scsVd }t‡fd†|Dƒƒ}ˆjj|d jsRtmethods(slabelslabel_singulars takes_paramssbindablesnames object_namesobject_name_plural(tdictRRR)(R(tjson_friendly_attributest json_dicttm((R(s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyt__json__ds cCs#y |d=Wntk rnXdS(Nt aciprefix(tKeyError(R(tresult((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pytpostprocess_resultps  (t__name__t __module__t__doc__tFalseR"RR#R$R R RtTrueR!R.R2(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyRAs4              tselfservice_addcBs/eZedƒZedƒZeZd„ZRS(s"Add a new self-service permission.sAdded selfservice "%(value)s"cKsjd|krd|d(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyR8zs  tselfservice_delcBs2eZedƒZejZedƒZd„ZRS(s!Delete a self-service permission.sDeleted selfservice "%(value)s"cKs<tjd|dtƒ}|jj|ƒtdtd|ƒS(Ntaci_delR/R1R(RR R;R<R2R*R7(R(RR=R1((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyR>–s ( R3R4RR5Rtstandard_booleant has_outputR?R>(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyRBs   tselfservice_modcBs/eZedƒZedƒZeZd„ZRS(s!Modify a self-service permission.s Modified selfservice "%(value)s"cKsxd|kr1|ddkr1tjddƒ‚nt|d¨s (R3R4RR5R?R@RAR>(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyRF¢s  tselfservice_findcBsDeZedƒZedddƒZedƒfZeZ d„Z RS(s%Search for a self-service permission.s%(count)d selfservice matcheds%(count)d selfservices matchediRcKsnt|dÂs    ( R3R4RR5RR?R t takes_optionsR@RAR>(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyRJ¸s  tselfservice_showcBs#eZedƒZeZd„ZRS(s4Display information about a self-service permission.cKsCtjd|dt|d}|jj|ƒtd|d|ƒS(Ntaci_showR/R1R(RR R;R<R2R*(R(RR=R1((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyR>Øs  (R3R4RR5R@RAR>(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyRQÓs N(tipalibRRRRRtipalib.requestRRRRR R tipalib.plugins.baseldapR R5R;R@RtregistertCreateR8tDeleteRBtUpdateRFtSearchRJtRetrieveRQ(((s8/home/mkosek/freeipa-clean/ipalib/plugins/selfservice.pyts.  6      freeipa-3.3.4/ipalib/plugins/sudocmd.py0000664000175000017500000001075112271663206017444 0ustar mkosekmkosek# Authors: # Jr Aquino # # Copyright (C) 2010 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 . import platform import os import sys from ipalib import api, errors, util from ipalib import Str from ipalib.plugins.baseldap import * from ipalib import _, ngettext __doc__ = _(""" Sudo Commands Commands used as building blocks for sudo EXAMPLES: Create a new command ipa sudocmd-add --desc='For reading log files' /usr/bin/less Remove a command ipa sudocmd-del /usr/bin/less """) topic = ('sudo', _('commands for controlling sudo configuration')) class sudocmd(LDAPObject): """ Sudo Command object. """ container_dn = api.env.container_sudocmd object_name = _('sudo command') object_name_plural = _('sudo commands') object_class = ['ipaobject', 'ipasudocmd'] # object_class_config = 'ipahostobjectclasses' search_attributes = [ 'sudocmd', 'description', ] default_attributes = [ 'sudocmd', 'description', 'memberof', ] attribute_members = { 'memberof': ['sudocmdgroup'], } uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' label = _('Sudo Commands') label_singular = _('Sudo Command') takes_params = ( Str('sudocmd', cli_name='command', label=_('Sudo Command'), primary_key=True, ), Str('description?', cli_name='desc', label=_('Description'), doc=_('A description of this command'), ), ) def get_dn(self, *keys, **options): if keys[-1].endswith('.'): keys[-1] = keys[-1][:-1] dn = super(sudocmd, self).get_dn(*keys, **options) try: self.backend.get_entry(dn, ['']) except errors.NotFound: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( 'sudocmd', keys[-1], self.object_class, [''], DN(self.container_dn, api.env.basedn) ) except errors.NotFound: pass return dn api.register(sudocmd) class sudocmd_add(LDAPCreate): __doc__ = _('Create new Sudo Command.') msg_summary = _('Added Sudo Command "%(value)s"') api.register(sudocmd_add) class sudocmd_del(LDAPDelete): __doc__ = _('Delete Sudo Command.') msg_summary = _('Deleted Sudo Command "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): filters = [ ldap.make_filter_from_attr(attr, dn) for attr in ('memberallowcmd', 'memberdenycmd')] filter = ldap.combine_filters(filters, ldap.MATCH_ANY) filter = ldap.combine_filters( (filter, ldap.make_filter_from_attr('objectClass', 'ipasudorule')), ldap.MATCH_ALL) dependent_sudorules = [] try: entries, truncated = ldap.find_entries( filter, ['cn'], base_dn=DN(api.env.container_sudorule, api.env.basedn)) except errors.NotFound: pass else: for entry_dn, entry_attrs in entries: [cn] = entry_attrs['cn'] dependent_sudorules.append(cn) if dependent_sudorules: raise errors.DependentEntry( key=keys[0], label='sudorule', dependent=', '.join(dependent_sudorules)) return dn api.register(sudocmd_del) class sudocmd_mod(LDAPUpdate): __doc__ = _('Modify Sudo Command.') msg_summary = _('Modified Sudo Command "%(value)s"') api.register(sudocmd_mod) class sudocmd_find(LDAPSearch): __doc__ = _('Search for Sudo Commands.') msg_summary = ngettext( '%(count)d Sudo Command matched', '%(count)d Sudo Commands matched', 0 ) api.register(sudocmd_find) class sudocmd_show(LDAPRetrieve): __doc__ = _('Display Sudo Command.') api.register(sudocmd_show) freeipa-3.3.4/ipalib/plugins/host.pyc0000664000175000017500000007177712271707517017151 0ustar mkosekmkosekó †fçRc@s4ddlZddlZddlZddlmZddljZddlZddlZddl m Z m Z m Z ddl m Z mZmZddlTddlmZmZmZmZmZmZddlmZmZmZmZmZmZddlmZdd l mZm Z dd l m!Z!dd l"m#Z#dd l$m%Z%m&Z&m'Z'dd l(m)Z)m*Z*ddl+m,Z,ddl-m.Z.edƒZ/ej0ej1dZ2d„Z3d„Z4eddedƒƒe dddƒe dddƒe ddedƒƒe ddedƒƒe dded ƒƒe d!ded"ƒƒe d#ded$ƒƒe d%ded&ƒƒe d'ded(ƒƒe d)ded*ƒƒe d+ded,ƒƒe d-ded.ƒƒe d/ded0ƒƒfZ5d1„Z6d2„Z7d3e8fd4„ƒYZ9e j:e9ƒd5e;fd6„ƒYZ<e j:e<ƒd7e=fd8„ƒYZ>e j:e>ƒd9e?fd:„ƒYZ@e j:e@ƒd;eAfd<„ƒYZBe j:eBƒd=eCfd>„ƒYZDe j:eDƒd?eEfd@„ƒYZFe j:eFƒdAeGfdB„ƒYZHe j:eHƒdCeIfdD„ƒYZJe j:eJƒdS(EiÿÿÿÿN(t NSPRError(tapiterrorstutil(tStrtFlagtBytes(t*(tsplit_principaltvalidate_certificatetset_certificate_attrstticket_flags_paramstupdate_krbticketflagstset_kerberos_attrs(tdns_container_existst _record_typestadd_records_for_host_validationtadd_records_for_hostt_hostname_validatortget_reverse_zone(R(t_tngettext(tx509(tcontext(tnormalize_sshpubkeytvalidate_sshpubkey_no_optionstconvert_sshpubkey_post(tipa_generate_passwordtCheckedIPAddress(t SSHPublicKey(tDNsC Hosts/Machines A host represents a machine. It can be used in a number of contexts: - service entries are associated with a host - a host stores the host/ service principal - a host can be used in Host-based Access Control (HBAC) rules - every enrolled client generates a host entry ENROLLMENT: There are three enrollment scenarios when enrolling a new client: 1. You are enrolling as a full administrator. The host entry may exist or not. A full administrator is a member of the hostadmin role or the admins group. 2. You are enrolling as a limited administrator. The host must already exist. A limited administrator is a member a role with the Host Enrollment privilege. 3. The host has been created with a one-time password. RE-ENROLLMENT: Host that has been enrolled at some point, and lost its configuration (e.g. VM destroyed) can be re-enrolled. For more information, consult the manual pages for ipa-client-install. A host can optionally store information such as where it is located, the OS that it runs, etc. EXAMPLES: Add a new host: ipa host-add --location="3rd floor lab" --locality=Dallas test.example.com Delete a host: ipa host-del test.example.com Add a new host with a one-time password: ipa host-add --os='Fedora 12' --password=Secret123 test.example.com Add a new host with a random one-time password: ipa host-add --os='Fedora 12' --random test.example.com Modify information about a host: ipa host-mod --os='Fedora 12' test.example.com Remove SSH public keys of a host and update DNS to reflect this change: ipa host-mod --sshpubkey= --updatedns test.example.com Disable the host Kerberos key, SSL certificate and all of its services: ipa host-disable test.example.com Add a host that can manage this host's keytab and certificate: ipa host-add-managedby --hosts=test2 test s_,.@+-=cCs²tjjd|ƒyDt|ƒ\}}id||fd6}tjd|||Wntjk rnnXy(i||6}tjd|||Wntjk r­nXdS(Nsdeleting ipaddr %ss%s.%st ptrrecordt dnsrecord_del(RtlogtdebugRtCommandRtNotFound(tipaddrthosttdomaint recordtypetrevzonetrevnametdelkw((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytremove_fwd_ptros cCsd|krdS|dpd}g}x¤|D]œ}yt|ƒjƒ}Wntk ra}q-nX|dk r~|j|ƒnyt|ƒjƒ}Wntk r¬}q-nX|dk r-|j|ƒq-q-Wytjd||d|ƒWntj k rnXdS(Nt ipasshpubkeyt dnsrecord_modt sshfprecord(( Rtfingerprint_dns_sha1t ValueErrortNonetappendtfingerprint_dns_sha256RR#Rt EmptyModlist(tzonetrecordt entry_attrstpubkeystsshfpstpubkeytsshfptUnicodeDecodeError((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytupdate_sshfp_recordƒs*    t has_keytabtlabeltKeytabtmanagedby_hosts Managed byt managing_hosttManagingtsubjecttSubjectt serial_numbers Serial Numbertserial_number_hexsSerial Number (hex)tissuertIssuertvalid_not_befores Not Beforetvalid_not_afters Not Aftertmd5_fingerprintsFingerprint (MD5)tsha1_fingerprintsFingerprint (SHA1)srevocation_reason?sRevocation reasont managedbysFailed managedbys sshpubkeyfp*sSSH public key fingerprintcCs7yt|dtƒ}Wntk r2}t|ƒSXdS(s= Verify that we have either an IPv4 or IPv6 address. t match_localN(RtFalset ExceptiontunicodeR2(tugettextR%tipte((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytvalidate_ipaddrÉs  cCs,|jdƒr|d }n|jƒ}|S(s-Use common fqdn form without the trailing dotu.iÿÿÿÿ(tendswithtlower(thostname((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytnormalize_hostnameÓs  R&cBseZdZejjZedƒZedƒZ dddddgZ dd d d d d ddgZ dd d d d d ddddddddgZ dZ idgd6dddddgd6dgd6dgd6dddddgd6ZeZidsd6dtd6dud6dvd6ZdwdxgZed/ƒZed0ƒZeded1d2d3ed4ƒd5ed6eƒed7d1d8d3ed9ƒd:ed;ƒƒed<d1d=d3ed>ƒd:ed?ƒƒed@d1dAd3edBƒd:edCƒƒedDd1dEd3edFƒd:edGƒƒedHd1dId3edJƒd:edKƒƒedLd1dMd3edNƒd:edOƒƒedPd:edQƒdRdydUeƒedVd3edWƒdRdzƒedZed1d[d3ed\ƒd:ed]ƒƒed^d3ed_ƒdRdXdYdSgƒed`d6da„dbdcdddedfed3edgƒd:edhƒƒedied1djd3edkƒd6edfedRdSgƒedld1dmd3ednƒd:edoƒƒfeZdp„Z dq„Z!dr„Z"RS({s Host object. R&thostst ipaobjecttnshosttipahosttpkiusert ipaservicetfqdnt descriptiontltnshostlocationtkrbprincipalnametnshardwareplatformt nsosversionROtusercertificatetmemberoftmemberindirecttmemberofindirectt macaddresst userclasst ipauniqueidtusert enrolledbyt hostgrouptnetgrouptrolethbacruletsudoruletmanagings Member Oftin_tnot_in_s Enrolled byt enroll_by_tnot_enroll_by_s Managed bytman_by_t not_man_by_RDtman_tnot_man_t userpasswordt has_passwordtkrbprincipalkeyR?tHoststHosttcli_nameRZR@s Host namet primary_keyt normalizers description?tdesct DescriptiontdocsA description of this hostsl?tlocalitytLocalitys$Host locality (e.g. "Baltimore, MD")snshostlocation?tlocationtLocationsHost location (e.g. "Lab 2")snshardwareplatform?tplatformtPlatforms*Host hardware platform (e.g. "Lenovo T61")s nsosversion?tossOperating systems3Host operating system and version (e.g. "Fedora 9")s userpassword?tpasswords User passwords Password used in bulk enrollmentsrandom?s8Generate a random password to be used in bulk enrollmenttflagst no_searchtvirtual_attributetdefaultsrandompassword?sRandom passwordt no_createt no_updatesusercertificate?t certificatet Certificates"Base-64 encoded server certificateskrbprincipalname?sPrincipal names macaddress*cCs |jƒS(N(tupper(tvalue((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyt;stpatterns*^([a-fA-F0-9]{2}[:|\-]?){5}[a-fA-F0-9]{2}$tpattern_errmsgsOMust be of the form HH:HH:HH:HH:HH:HH, where each H is a hexadecimal character.tcsvs MAC addresss%Hardware MAC address(es) on this hosts ipasshpubkey*t sshpubkeysSSH public keys userclass*tclasstClasssOHost category (semantics placed on this attribute are for local interpretation)cOs±|d}tt|ƒj||}y|jj|dgƒWnktjk r¬y@|jjd||jdgt |j t j j ƒƒ\}}Wq­tjk r¨q­XnX|S(Niÿÿÿÿttserverhostname(tsuperR&tget_dntbackendt get_entryRR$tfind_entry_by_attrt object_classRt container_dnRtenvtbasedn(tselftkeystoptionsRZtdnR8((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyR§Qs  %c Cs d|}dg}|jjj}g}y\|jdt|jtjjƒd|d|ƒ\}}x|D]}|j|dƒqhWWnt j k r›gSX|S(Ns managedBy=%sRbtbase_dntfiltert attrs_listi( RtBackendtldap2t find_entriesRR¬R­R®R3RR$( R¯R²t host_filtert host_attrstldapt managed_hostsR\t truncatedR&((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytget_managed_hosts_s    cCsÁttjjtjjƒ}xŸt|jdgƒƒD]…}t|ƒ}|j|ƒs[q4n|jidd6ƒ}y |j ||j |dgƒWnt j k r§q4X|dj |ƒq4WdS(sp We don't want to show managed netgroups so remove them from the memberofindirect list. Rltmepmanagedentryt objectclassR¤N(RRR­tcontainer_netgroupR®tlisttgetRXt make_filtert get_entriest SCOPE_BASERR$tremove(R¯R»R8t ng_containertmembertmemberdnR´((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytsuppress_netgroup_memberofqs  (s Member Ofsin_snot_in_(s Enrolled byRzR{(s Managed bysman_by_s not_man_by_(RDR~R(R€s has_password(skrbprincipalkeys has_keytab(s no_searchsvirtual_attribute(s no_creates no_updates no_searchsvirtual_attribute(#t__name__t __module__t__doc__RR­tcontainer_hostR¬Rt object_nametobject_name_pluralR«tsearch_attributestdefault_attributestuuid_attributetattribute_memberstTruetbindablet relationshipstpassword_attributesR@tlabel_singularRRR[RRQRR RRR t takes_paramsR§R¾RË(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyR&Úsº                                                       thost_addc Bs¯eZedƒZejeZedƒZdgZej e ddedƒdedƒƒe dded ƒƒe d e ded ƒded ƒƒfZ d „Z d„ZRS(sAdd a new host.sAdded host "%(value)s"ROtforceR@tForceRŠs"force host name even if not in DNSt no_reversesskip reverse DNS detections ip_address?s(Add the host to DNS with this IP addresss IP Addressc Osât|tƒst‚|jdƒrŸt|ƒrŸ|djdƒ}|d}tdj|dƒƒ} |jdtƒ } t d|| |ddt d| ƒn|jd tƒ rØd|krØt j |j |dƒnd |krõ|d |d RRtgetattrRtAttributeErrorRt NonFatalErrorRtdictR R tobjR¾tget_password_attributesR( R¯R»R²R8R°R±RþRøR&R'RüRV((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyt post_callbackÊsB          (RÌRÍRRÎt LDAPCreatethas_output_paramsthost_output_paramst msg_summarytmember_attributest takes_optionsRRRWRúR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyR܇s            /thost_delcBsSeZedƒZedƒZdgZeddedƒdeƒfZd„Z RS(sDelete a host.sDeleted host "%(value)s"ROs updatedns?RŠsRemove entries from DNSR–c OsÃt|tƒst‚td|dƒdk rZtjd|dƒd}|dd}n |d}t||ƒt}x§|r y+tjd|ƒ}|d}|d} Wnt j k rÂPqzXxW| D]O} | dd} t | ƒ\} } }| j ƒ|krÊtjd | ƒqÊqÊWqzW|j d tƒ}|riyt|ƒ}Wqit j k ret}qiXn|rb|jd ƒ}td j|d ƒƒ}y)tjd |ƒd}|dd}Wn$t j k ræ|jj|ŒnXtjd|d|dƒd}xW|D]L}d|krCt|dd|d|dƒnd|krqt|dd|d|dƒqgtD]}td|j ƒƒ^qx}x¾|D]¶}|dkr¡||kr¡x‘tt||ƒƒD]y}|||j|dƒs|||j|d ƒrÖi|||t|ƒ6}tjd||dd|qÖqÖWPq¡q¡WqWn|jjjr¿y|j|dgƒ\}} Wn$t j k r¶|jj|ŒnX| jddƒ}|r¿tj |ƒ}y’ttj!|tj"ƒƒ}y\tjd|ƒd}d|krWytjd|ddƒWqWt j#k rSqWXnWnt j#k rnnXWq¼t$k r¸}|j%dkr¯|j&j'd|j(d ƒq¹|‚q¼Xq¿n|S(Niÿÿÿÿt host_showtresultRbit service_findR½Rft service_delt updatednsRáit dnszone_showtidnsnametdnsrecord_findtarecordt aaaarecords%srecordR Rit cert_showtrevocation_reasont cert_revokeii àÿÿsProblem decoding certificate %s(sarecords aaaarecord()RîRRïRR2RR#thost_is_masterRÖRR$RRYRÃRQRRðRSRñRthandle_not_foundR,RtstrtxrangetlenRXR­t enable_raR©t single_valueRRötget_serial_numbertDERtNotImplementedErrorRterrnoR!tinfotargs(R¯R»R²R°R±t hostentryRbR½trettservicesR8t principaltserviceRZRóRRøR'RtrecordsR7ttt_attribute_typestattrtiR+Rùtserialtnsprerr((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRúsœ      !     )       ( RÌRÍRRÎR R RRQR Rú(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyR ûs      thost_modc BseZedƒZejeZedƒZdgZej e ddddedƒded ƒd e ƒe d ded ƒd e ƒfZ d„Zd„ZRS(s Modify information about a host.sModified host "%(value)s"ROskrbprincipalname?R…t principalnameR@sPrincipal nameRŠs%Kerberos principal name for this hostt attributes updatedns?sUpdate DNS entriesR–c Ost|tƒst‚|jdƒs3|jdƒrˆi}|jj|||ƒ|d rˆ|drˆtjdddtdƒƒ‚qˆnd |kr¯tj d td ƒƒ‚nd |krÌ|d |d R RÖ(R¯R»R²R8RµR°R±tentrytentry_attrs_oldtmsgt obj_classesRùtoldcertR2RR3t_dnt _entry_attrsRøR'((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRús¦$                         cOsÙt|tƒst‚|jdtƒrCtttdƒƒ|d|jdƒ|jdƒnd|ksVd|kr°g}|jdƒdk rDx‘|jdgƒD]}} |jj| ƒ} y|j | dgƒ\} } Wn$t j k rá|jj | ƒnX|jt | jddƒƒƒq„Wttd„|ƒƒ}|sD|j|df|jƒ}qDng} |jdƒdk rÿxˆ|jdgƒD]t} |jj| ƒ} y|j | dgƒ\} } Wn$t j k rÏ|jj | ƒnX| | jdgƒ7} qrWtt | ƒƒ} nx®||jf| |jffD]‹\} }g| D]}t|ƒd d ^q1}g|D]}|j|j|jƒ^qX}|j||ƒ}|j||f|jƒ}qWn|jddƒ||fS( NR‹Rdtman_hostt not_man_hostROR¤cSs||@S(N((ts1ts2((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyR ss(objectclass=disabled)i(RîRRïRÇR3RÃR2RR§R©RR$RtsetRÂtreducetcombine_filterst MATCH_ALLt MATCH_ANYt MATCH_NONEtmake_filter_from_attrR0Rœtreplace(R¯R»R´RµR³tscopeR'R±R\tpkeyR²R8t not_hostst target_hostst filter_opR&t hosts_avastavat hosts_filterst hosts_filter((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRúsH  #'+c OsÍ|jdtƒr|Sx°|D]¨}|\}}t|ƒt||ƒ|jj|||ƒ|jj||ƒ|dr†t|dy+tjd|ƒ}|d}|d} Wnt j k r¿PqwXxx| D]p} | dd} t | ƒ\} } }| j ƒ|krÇytjd | ƒt}Wq7t j k r3q7XqÇqÇWqwW|jj||Ž}y|j|d gƒ\}} Wn$t j k r™|jj|ŒnX| jd dƒ}|rÎ|jjjr®tj|ƒ}y’ttj|tjƒƒ}y\tjd |ƒd}d |krIytjd |d dƒWqIt jk rEqIXnWnt jk r`nXWq®tk rª}|jdkr¡|jjd|jdƒq«|‚q®Xn|j|idd 6ƒt}n|jj ||| ƒ| dr|j!|ƒt}n|st j ƒ‚nt"dtd|dƒS(NiÿÿÿÿRRRbiRR½Rftservice_disableRiRRRii àÿÿsProblem decoding certificate %siR?Rœ(#RR¨RR2RR#RRQRÖRR$RRYtAlreadyInactiveR§R©RR!R­R RRöRSR"R#R$RR%R!R&R't update_entryRtremove_principal_keyR(R¯R°R±R»R(Rbt done_workR½R)R*R8R+R,RZRóR²RùR2RR3((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pytexecutesz                cOs,t|tƒst‚|jj||ƒ|S(N(RîRRïRRË(R¯R»R²R8R°R±((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRàs( RÌRÍRRÎtoutputtstandard_valuet has_outputR RmR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRg‡s     Sthost_add_managedbycBs9eZedƒZdgZejeZeZ d„Z RS(s$Add hosts that can manage this host.ROcOs2t|tƒst‚|jj||ƒ||fS(N(RîRRïRRË(R¯R»t completedtfailedR²R8R°R±((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRîs( RÌRÍRRÎR t LDAPAddMemberRR RÖt allow_sameR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRqçs    thost_remove_managedbycBs3eZedƒZdgZejeZd„ZRS(s'Remove hosts that can manage this host.ROcOs2t|tƒst‚|jj||ƒ||fS(N(RîRRïRRË(R¯R»RrRsR²R8R°R±((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRüs( RÌRÍRRÎR tLDAPRemoveMemberRR R(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyRvös   (KRR‘tsyst nss.errorRtnss.nsstnsstnetaddrtstringtipalibRRRRRRtipalib.plugins.baseldaptipalib.plugins.serviceRR R R R R tipalib.plugins.dnsRRRRRRRRRtipalib.requestRt ipalib.utilRRRtipapython.ipautilRRt ipapython.sshRt ipapython.dnRRÎtdigitst ascii_lettersRôR,R>R RWR[t LDAPObjectR&tregisterRRÜt LDAPDeleteR RBR4R^RCRfRt LDAPQueryRgRtRqRwRv(((s1/home/mkosek/freeipa-clean/ipalib/plugins/host.pyts      ..9                             ª q m “ S - ^   freeipa-3.3.4/ipalib/plugins/__init__.py0000664000175000017500000000147412202434255017541 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Sub-package containing all core plugins. """ freeipa-3.3.4/ipalib/plugins/selinuxusermap.py0000664000175000017500000004207612271663206021077 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2011 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 . from ipalib import api, errors from ipalib import Str, StrEnum, Bool from ipalib.plugins.baseldap import * from ipalib import _, ngettext from ipalib.plugins.hbacrule import is_all __doc__ = _(""" SELinux User Mapping Map IPA users to SELinux users by host. Hosts, hostgroups, users and groups can be either defined within the rule or it may point to an existing HBAC rule. When using --hbacrule option to selinuxusermap-find an exact match is made on the HBAC rule name, so only one or zero entries will be returned. EXAMPLES: Create a rule, "test1", that sets all users to xguest_u:s0 on the host "server": ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1 ipa selinuxusermap-add-host --hosts=server.example.com test1 Create a rule, "test2", that sets all users to guest_u:s0 and uses an existing HBAC rule for users and hosts: ipa selinuxusermap-add --usercat=all --hbacrule=webserver --selinuxuser=guest_u:s0 test2 Display the properties of a rule: ipa selinuxusermap-show test2 Create a rule for a specific user. This sets the SELinux context for user john to unconfined_u:s0-s0:c0.c1023 on any machine: ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0.c1023 john_unconfined ipa selinuxusermap-add-user --users=john john_unconfined Disable a rule: ipa selinuxusermap-disable test1 Enable a rule: ipa selinuxusermap-enable test1 Find a rule referencing a specific HBAC rule: ipa selinuxusermap-find --hbacrule=allow_some Remove a rule: ipa selinuxusermap-del john_unconfined SEEALSO: The list controlling the order in which the SELinux user map is applied and the default SELinux user are available in the config-show command. """) notboth_err = _('HBAC rule and local members cannot both be set') def validate_selinuxuser(ugettext, user): """ An SELinux user has 3 components: user:MLS:MCS. user and MLS are required. user traditionally ends with _u but this is not mandatory. The regex is ^[a-zA-Z][a-zA-Z_]* The MLS part can only be: Level: s[0-15](-s[0-15]) Then MCS could be c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123] Meaning s0 s0-s1 s0-s15:c0.c1023 s0-s1:c0,c2,c15.c26 s0-s0:c0.c1023 Returns a message on invalid, returns nothing on valid. """ regex_name = re.compile(r'^[a-zA-Z][a-zA-Z_]*$') regex_mls = re.compile(r'^s[0-9][1-5]{0,1}(-s[0-9][1-5]{0,1}){0,1}$') regex_mcs = re.compile(r'^c(\d+)([.,-]c(\d+))*?$') # If we add in ::: we don't have to check to see if some values are # empty (name, mls, mcs, ignore) = (user + ':::').split(':', 3) if not regex_name.match(name): return _('Invalid SELinux user name, only a-Z and _ are allowed') if not mls or not regex_mls.match(mls): return _('Invalid MLS value, must match s[0-15](-s[0-15])') m = regex_mcs.match(mcs) if mcs and (not m or (m.group(3) and (int(m.group(3)) > 1023))): return _('Invalid MCS value, must match c[0-1023].c[0-1023] ' 'and/or c[0-1023]-c[0-c0123]') return None def validate_selinuxuser_inlist(ldap, user): """ Ensure the user is in the list of allowed SELinux users. Returns nothing if the user is found, raises an exception otherwise. """ config = ldap.get_ipa_config()[1] item = config.get('ipaselinuxusermaporder', []) if len(item) != 1: raise errors.NotFound(reason=_('SELinux user map list not ' 'found in configuration')) userlist = item[0].split('$') if user not in userlist: raise errors.NotFound( reason=_('SELinux user %(user)s not found in ' 'ordering list (in config)') % dict(user=user)) return class selinuxusermap(LDAPObject): """ SELinux User Map object. """ container_dn = api.env.container_selinux object_name = _('SELinux User Map rule') object_name_plural = _('SELinux User Map rules') object_class = ['ipaassociation', 'ipaselinuxusermap'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'ipaenabledflag', 'memberuser', 'memberhost', 'memberhostgroup', 'seealso', 'ipaselinuxuser', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } # These maps will not show as members of other entries label = _('SELinux User Maps') label_singular = _('SELinux User Map') takes_params = ( Str('cn', cli_name='name', label=_('Rule name'), primary_key=True, ), Str('ipaselinuxuser', validate_selinuxuser, cli_name='selinuxuser', label=_('SELinux User'), ), Str('seealso?', cli_name='hbacrule', label=_('HBAC Rule'), doc=_('HBAC Rule that defines the users, groups and hostgroups'), ), StrEnum('usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum('hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), Str('description?', cli_name='desc', label=_('Description'), ), Bool('ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str('memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), ) def _normalize_seealso(self, seealso): """ Given a HBAC rule name verify its existence and return the dn. """ if not seealso: return None try: dn = DN(seealso) return str(dn) except ValueError: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( self.api.Object['hbacrule'].primary_key.name, seealso, self.api.Object['hbacrule'].object_class, [''], DN(self.api.Object['hbacrule'].container_dn, api.env.basedn)) seealso = dn except errors.NotFound: raise errors.NotFound(reason=_('HBAC rule %(rule)s not found') % dict(rule=seealso)) return seealso def _convert_seealso(self, ldap, entry_attrs, **options): """ Convert an HBAC rule dn into a name """ if options.get('raw', False): return if 'seealso' in entry_attrs: (hbac_dn, hbac_attrs) = ldap.get_entry(entry_attrs['seealso'][0], ['cn']) entry_attrs['seealso'] = hbac_attrs['cn'][0] api.register(selinuxusermap) class selinuxusermap_add(LDAPCreate): __doc__ = _('Create a new SELinux User Map.') msg_summary = _('Added SELinux User Map "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # rules are enabled by default entry_attrs['ipaenabledflag'] = 'TRUE' validate_selinuxuser_inlist(ldap, entry_attrs['ipaselinuxuser']) # hbacrule is not allowed when usercat or hostcat is set is_to_be_set = lambda x: x in entry_attrs and entry_attrs[x] != None are_local_members_to_be_set = any(is_to_be_set(attr) for attr in ('usercategory', 'hostcategory')) is_hbacrule_to_be_set = is_to_be_set('seealso') if is_hbacrule_to_be_set and are_local_members_to_be_set: raise errors.MutuallyExclusiveError(reason=notboth_err) if is_hbacrule_to_be_set: entry_attrs['seealso'] = self.obj._normalize_seealso(entry_attrs['seealso']) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj._convert_seealso(ldap, entry_attrs, **options) return dn api.register(selinuxusermap_add) class selinuxusermap_del(LDAPDelete): __doc__ = _('Delete a SELinux User Map.') msg_summary = _('Deleted SELinux User Map "%(value)s"') api.register(selinuxusermap_del) class selinuxusermap_mod(LDAPUpdate): __doc__ = _('Modify a SELinux User Map.') msg_summary = _('Modified SELinux User Map "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, attrs_list) except errors.NotFound: self.obj.handle_not_found(*keys) is_to_be_deleted = lambda x: (x in _entry_attrs and x in entry_attrs) and \ entry_attrs[x] == None # makes sure the local members and hbacrule is not set at the same time # memberuser or memberhost could have been set using --setattr is_to_be_set = lambda x: ((x in _entry_attrs and _entry_attrs[x] != None) or \ (x in entry_attrs and entry_attrs[x] != None)) and \ not is_to_be_deleted(x) are_local_members_to_be_set = any(is_to_be_set(attr) for attr in ('usercategory', 'hostcategory', 'memberuser', 'memberhost')) is_hbacrule_to_be_set = is_to_be_set('seealso') # this can disable all modifications if hbacrule and local members were # set at the same time bypassing this commad, e.g. using ldapmodify if are_local_members_to_be_set and is_hbacrule_to_be_set: raise errors.MutuallyExclusiveError(reason=notboth_err) if is_all(entry_attrs, 'usercategory') and 'memberuser' in entry_attrs: raise errors.MutuallyExclusiveError(reason="user category " "cannot be set to 'all' while there are allowed users") if is_all(entry_attrs, 'hostcategory') and 'memberhost' in entry_attrs: raise errors.MutuallyExclusiveError(reason="host category " "cannot be set to 'all' while there are allowed hosts") if 'ipaselinuxuser' in entry_attrs: validate_selinuxuser_inlist(ldap, entry_attrs['ipaselinuxuser']) if 'seealso' in entry_attrs: entry_attrs['seealso'] = self.obj._normalize_seealso(entry_attrs['seealso']) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj._convert_seealso(ldap, entry_attrs, **options) return dn api.register(selinuxusermap_mod) class selinuxusermap_find(LDAPSearch): __doc__ = _('Search for SELinux User Maps.') msg_summary = ngettext( '%(count)d SELinux User Map matched', '%(count)d SELinux User Maps matched', 0 ) def execute(self, *args, **options): # If searching on hbacrule we need to find the uuid to search on if options.get('seealso'): hbacrule = options['seealso'] try: hbac = api.Command['hbacrule_show'](hbacrule, all=True)['result'] dn = hbac['dn'] except errors.NotFound: return dict(count=0, result=[], truncated=False) options['seealso'] = dn return super(selinuxusermap_find, self).execute(*args, **options) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, attrs) = entry self.obj._convert_seealso(ldap, attrs, **options) return truncated api.register(selinuxusermap_find) class selinuxusermap_show(LDAPRetrieve): __doc__ = _('Display the properties of a SELinux User Map rule.') def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj._convert_seealso(ldap, entry_attrs, **options) return dn api.register(selinuxusermap_show) class selinuxusermap_enable(LDAPQuery): __doc__ = _('Enable an SELinux User Map rule.') msg_summary = _('Enabled SELinux User Map "%(value)s"') has_output = output.standard_value def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'TRUE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: raise errors.AlreadyActive() except errors.NotFound: self.obj.handle_not_found(cn) return dict( result=True, value=cn, ) api.register(selinuxusermap_enable) class selinuxusermap_disable(LDAPQuery): __doc__ = _('Disable an SELinux User Map rule.') msg_summary = _('Disabled SELinux User Map "%(value)s"') has_output = output.standard_value def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'FALSE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: raise errors.AlreadyInactive() except errors.NotFound: self.obj.handle_not_found(cn) return dict( result=True, value=cn, ) api.register(selinuxusermap_disable) class selinuxusermap_add_user(LDAPAddMember): __doc__ = _('Add users and groups to an SELinux User Map rule.') member_attributes = ['memberuser'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercategory' in entry_attrs and \ entry_attrs['usercategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError( reason=_("users cannot be added when user category='all'")) if 'seealso' in entry_attrs: raise errors.MutuallyExclusiveError(reason=notboth_err) return dn api.register(selinuxusermap_add_user) class selinuxusermap_remove_user(LDAPRemoveMember): __doc__ = _('Remove users and groups from an SELinux User Map rule.') member_attributes = ['memberuser'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(selinuxusermap_remove_user) class selinuxusermap_add_host(LDAPAddMember): __doc__ = _('Add target hosts and hostgroups to an SELinux User Map rule.') member_attributes = ['memberhost'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'hostcategory' in entry_attrs and \ entry_attrs['hostcategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError( reason=_("hosts cannot be added when host category='all'")) if 'seealso' in entry_attrs: raise errors.MutuallyExclusiveError(reason=notboth_err) return dn api.register(selinuxusermap_add_host) class selinuxusermap_remove_host(LDAPRemoveMember): __doc__ = _('Remove target hosts and hostgroups from an SELinux User Map rule.') member_attributes = ['memberhost'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(selinuxusermap_remove_host) freeipa-3.3.4/ipalib/plugins/realmdomains.pyc0000664000175000017500000001236512271707517020633 0ustar mkosekmkosekó †fçRc@sddlmZmZddlmZmZddlmZddlmZmZm Z ddl m Z ddl m Z ddlmZddlmZed ƒZd „Zd efd „ƒYZejeƒd efd„ƒYZejeƒde fd„ƒYZejeƒdS(iÿÿÿÿ(tapiterrors(tStrtFlag(t_(t LDAPObjectt LDAPUpdatet LDAPRetrieve(t_domain_name_validator(thas_soa_or_ns_record(tDN(tget_domain_namesø Realm domains Manage the list of domains associated with IPA realm. EXAMPLES: Display the current list of realm domains: ipa realmdomains-show Replace the list of realm domains: ipa realmdomains-mod --domain=example.com ipa realmdomains-mod --domain={example1.com,example2.com,example3.com} Add a domain to the list of realm domains: ipa realmdomains-mod --add-domain=newdomain.com Delete a domain from the list of realm domains: ipa realmdomains-mod --del-domain=olddomain.com cCs|jƒjdƒS(Nt.(tlowertrstrip(td((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyt_domain_name_normalizer4st realmdomainsc BsÂeZdZejjZedƒZdgZ dgZ edƒZ edƒZ e dededdded ƒƒe d ededd ded ƒƒe d ededddedƒƒfZRS(s4 List of domains associated with IPA realm. s Realm domainstassociateddomains Realm Domainssassociateddomain+t normalizertcli_nametdomaintlabeltDomains add_domain?t add_domains Add domains del_domain?t del_domains Delete domain(t__name__t __module__t__doc__Rtenvtcontainer_realm_domainst container_dnRt object_nametsearch_attributestdefault_attributesRtlabel_singularRRRt takes_params(((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyR8s,        trealmdomains_modcBsTeZedƒZejeddedƒdedƒƒfZd„Zd„ZRS(sModify realm domains.tforceRtForcetdocs&Force adding domain even if not in DNSc Ost|tƒst‚|jdƒ}|jdƒ}|jdƒ} |jdƒ} |r|sc| r~tjdtdƒƒ‚ntƒ|kr®tjddd td ƒƒ‚n| sg|D]} t | ƒs»| ^q»} | rd j | ƒ} tjddd td | ƒƒ‚qn|S|j |ƒd d} |r‡| rpt |ƒ rptjddd td|ƒƒ‚n|d=| j |ƒn| r| tƒkr½tjddd td ƒƒ‚n|d=y| j | ƒWqtk rtjddd| ƒ‚qXn| |d<|S(NRRRR&treasonsQyou cannot specify the --domain option together with --add-domain or --del-domaintnameRterrors"cannot delete domain of IPA servers, s*no SOA or NS records found for domains: %sis(no SOA or NS records found for domain %stattrtvalue(t isinstanceR tAssertionErrortgetRtMutuallyExclusiveErrorRR tValidationErrorR tjoint get_entrytappendtremovet ValueErrortAttrValueNotFound(tselftldaptdnt entry_attrst attrs_listtkeystoptionsRRRR&Rt bad_domainstdomains((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyt pre_callbackfs@ !%(%!  c Ost|jj||Ž}|jj}t|j|ƒddƒ}tt|ƒj||Ž}t|j|ƒddƒ}||}||} xp|D]h} | tj j kr¯q‘ny*tj dt | ƒddtj j ƒWq‘tjtjfk røq‘Xq‘Wxp| D]h} | tj j kr"qny*tj dt | ƒddtj j ƒWqtjtjfk rkqXqW|S(NiRt dnsrecord_addu _kerberost txtrecordt dnsrecord_del(tobjtget_dntbackendtsetR4tsuperR%texecuteRRRtCommandtunicodetrealmRt EmptyModlisttNotFoundR8( R9R>R?R;R:t domains_oldtresultt domains_newt domains_addedtdomains_deletedR((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyRKs8         ( RRRRRt takes_optionsRRBRK(((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyR%\s    )trealmdomains_showcBseZedƒZRS(s"Display the list of realm domains.(RRRR(((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyRW½sN(tipalibRRRRRtipalib.plugins.baseldapRRRtipalib.plugins.dnsRt ipalib.utilR t ipapython.dnR tipapython.ipautilR RRRtregisterR%RW(((s9/home/mkosek/freeipa-clean/ipalib/plugins/realmdomains.pyts   ! ^ freeipa-3.3.4/ipalib/plugins/role.pyc0000664000175000017500000001362312271707517017117 0ustar mkosekmkosekó ­8 Rc@sºddlTddlmZmZmZmZddlmZddlmZedƒZ de fd„ƒYZ ej e ƒde fd „ƒYZej eƒd efd „ƒYZej eƒd efd „ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdS(iÿÿÿÿ(t*(tapitStrt_tngettext(tCommand(t privileges\ Roles A role is used for fine-grained delegation. A permission grants the ability to perform given low-level tasks (add a user, modify a group, etc.). A privilege combines one or more permissions into a higher-level abstraction such as useradmin. A useradmin would be able to add, delete and modify users. Privileges are assigned to Roles. Users, groups, hosts and hostgroups may be members of a Role. Roles can not contain other roles. EXAMPLES: Add a new role: ipa role-add --desc="Junior-level admin" junioradmin Add some privileges to this role: ipa role-add-privilege --privileges=addusers junioradmin ipa role-add-privilege --privileges=change_password junioradmin ipa role-add-privilege --privileges=add_user_to_default_group junioradmin Add a group of users to this role: ipa group-add --desc="User admins" useradmins ipa role-add-member --groups=useradmins junioradmin Display information about a role: ipa role-show junioradmin The result of this is that any users in the group 'junioradmin' can add users, reset passwords or add a user to the default IPA user group. trolec BsõeZdZejjZedƒZedƒZ ddgZ ddddd d gZ id d d dgd6dgd6Z idgd6Z eZedƒZedƒZeddddedƒdeƒeddddedƒdedƒƒfZRS(s Role object. Rtrolest groupofnamest nestedgrouptcnt descriptiontmembertmemberoftmemberindirecttmemberofindirecttusertgroupthostt hostgroupRtRolestRoletcli_nametnametlabels Role namet primary_keytdesct Descriptiontdocs A description of this role-group(t__name__t __module__t__doc__Rtenvtcontainer_rolegroupt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestattribute_memberstreverse_memberstTruetrdn_is_primary_keyRtlabel_singularRt takes_params(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR=s.              trole_addcBs eZedƒZedƒZRS(sAdd a new role.sAdded role "%(value)s"(RRRR t msg_summary(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR.ds trole_delcBs eZedƒZedƒZRS(sDelete a role.sDeleted role "%(value)s"(RRRR R/(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR0ls trole_modcBs eZedƒZedƒZRS(sModify a role.sModified role "%(value)s"(RRRR R/(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR1ts t role_findcBs&eZedƒZedddƒZRS(sSearch for roles.s%(count)d role matcheds%(count)d roles matchedi(RRRR RR/(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR2|s t role_showcBseZedƒZRS(s!Display information about a role.(RRRR (((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR3†strole_add_membercBseZedƒZRS(sAdd members to a role.(RRRR (((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR4Œstrole_remove_membercBseZedƒZRS(sRemove members from a role.(RRRR (((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR5’strole_add_privilegec BszeZedƒZdZdZdZdZej dƒej dde ded ƒƒej d de ded ƒƒfZ RS( sAdd privileges to a role.R3tprivilege_add_memberRRtresulttfailedttypeRsMembers that could not be addedt completedsNumber of privileges added(RRRR t show_commandtmember_commandt reverse_attrt member_attrtoutputtEntrytOutputtdicttintt has_output(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyR6˜s     trole_remove_privilegec BszeZedƒZdZdZdZdZej dƒej dde ded ƒƒej d de ded ƒƒfZ RS( sRemove privileges from a role.R3tprivilege_remove_memberRRR8R9R:RsMembers that could not be addedR;sNumber of privileges removed(RRRR R<R=R>R?R@RARBRCRDRE(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyRF¯s     N(tipalib.plugins.baseldaptipalibRRRRRtipalib.pluginsRR t LDAPObjectRtregistert LDAPCreateR.t LDAPDeleteR0t LDAPUpdateR1t LDAPSearchR2t LDAPRetrieveR3t LDAPAddMemberR4tLDAPRemoveMemberR5tLDAPAddReverseMemberR6tLDAPRemoveReverseMemberRF(((s1/home/mkosek/freeipa-clean/ipalib/plugins/role.pyts2 "! $         freeipa-3.3.4/ipalib/plugins/hbacsvc.py0000664000175000017500000000632612202434255017414 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib import api from ipalib import Str from ipalib.plugins.baseldap import LDAPObject, LDAPCreate, LDAPDelete from ipalib.plugins.baseldap import LDAPUpdate, LDAPSearch, LDAPRetrieve from ipalib import _, ngettext __doc__ = _(""" HBAC Services The PAM services that HBAC can control access to. The name used here must match the service name that PAM is evaluating. EXAMPLES: Add a new HBAC service: ipa hbacsvc-add tftp Modify an existing HBAC service: ipa hbacsvc-mod --desc="TFTP service" tftp Search for HBAC services. This example will return two results, the FTP service and the newly-added tftp service: ipa hbacsvc-find ftp Delete an HBAC service: ipa hbacsvc-del tftp """) topic = ('hbac', _('Host based access control commands')) class hbacsvc(LDAPObject): """ HBAC Service object. """ container_dn = api.env.container_hbacservice object_name = _('HBAC service') object_name_plural = _('HBAC services') object_class = [ 'ipaobject', 'ipahbacservice' ] default_attributes = ['cn', 'description', 'memberof'] uuid_attribute = 'ipauniqueid' attribute_members = { 'memberof': ['hbacsvcgroup'], } label = _('HBAC Services') label_singular = _('HBAC Service') takes_params = ( Str('cn', cli_name='service', label=_('Service name'), doc=_('HBAC service'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description?', cli_name='desc', label=_('Description'), doc=_('HBAC service description'), ), ) api.register(hbacsvc) class hbacsvc_add(LDAPCreate): __doc__ = _('Add a new HBAC service.') msg_summary = _('Added HBAC service "%(value)s"') api.register(hbacsvc_add) class hbacsvc_del(LDAPDelete): __doc__ = _('Delete an existing HBAC service.') msg_summary = _('Deleted HBAC service "%(value)s"') api.register(hbacsvc_del) class hbacsvc_mod(LDAPUpdate): __doc__ = _('Modify an HBAC service.') msg_summary = _('Modified HBAC service "%(value)s"') api.register(hbacsvc_mod) class hbacsvc_find(LDAPSearch): __doc__ = _('Search for HBAC services.') msg_summary = ngettext( '%(count)d HBAC service matched', '%(count)d HBAC services matched', 0 ) api.register(hbacsvc_find) class hbacsvc_show(LDAPRetrieve): __doc__ = _('Display information about an HBAC service.') api.register(hbacsvc_show) freeipa-3.3.4/ipalib/plugins/aci.py0000664000175000017500000010257412271663206016547 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # Copyright (C) 2009 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 . """ Directory Server Access Control Instructions (ACIs) ACIs are used to allow or deny access to information. This module is currently designed to allow, not deny, access. The aci commands are designed to grant permissions that allow updating existing entries or adding or deleting new ones. The goal of the ACIs that ship with IPA is to provide a set of low-level permissions that grant access to special groups called taskgroups. These low-level permissions can be combined into roles that grant broader access. These roles are another type of group, roles. For example, if you have taskgroups that allow adding and modifying users you could create a role, useradmin. You would assign users to the useradmin role to allow them to do the operations defined by the taskgroups. You can create ACIs that delegate permission so users in group A can write attributes on group B. The type option is a map that applies to all entries in the users, groups or host location. It is primarily designed to be used when granting add permissions (to write new entries). An ACI consists of three parts: 1. target 2. permissions 3. bind rules The target is a set of rules that define which LDAP objects are being targeted. This can include a list of attributes, an area of that LDAP tree or an LDAP filter. The targets include: - attrs: list of attributes affected - type: an object type (user, group, host, service, etc) - memberof: members of a group - targetgroup: grant access to modify a specific group. This is primarily designed to enable users to add or remove members of a specific group. - filter: A legal LDAP filter used to narrow the scope of the target. - subtree: Used to apply a rule across an entire set of objects. For example, to allow adding users you need to grant "add" permission to the subtree ldap://uid=*,cn=users,cn=accounts,dc=example,dc=com. The subtree option is a fail-safe for objects that may not be covered by the type option. The permissions define what the ACI is allowed to do, and are one or more of: 1. write - write one or more attributes 2. read - read one or more attributes 3. add - add a new entry to the tree 4. delete - delete an existing entry 5. all - all permissions are granted Note the distinction between attributes and entries. The permissions are independent, so being able to add a user does not mean that the user will be editable. The bind rule defines who this ACI grants permissions to. The LDAP server allows this to be any valid LDAP entry but we encourage the use of taskgroups so that the rights can be easily shared through roles. For a more thorough description of access controls see http://www.redhat.com/docs/manuals/dir-server/ag/8.0/Managing_Access_Control.html EXAMPLES: NOTE: ACIs are now added via the permission plugin. These examples are to demonstrate how the various options work but this is done via the permission command-line now (see last example). Add an ACI so that the group "secretaries" can update the address on any user: ipa group-add --desc="Office secretaries" secretaries ipa aci-add --attrs=streetAddress --memberof=ipausers --group=secretaries --permissions=write --prefix=none "Secretaries write addresses" Show the new ACI: ipa aci-show --prefix=none "Secretaries write addresses" Add an ACI that allows members of the "addusers" permission to add new users: ipa aci-add --type=user --permission=addusers --permissions=add --prefix=none "Add new users" Add an ACI that allows members of the editors manage members of the admins group: ipa aci-add --permissions=write --attrs=member --targetgroup=admins --group=editors --prefix=none "Editors manage admins" Add an ACI that allows members of the admins group to manage the street and zip code of those in the editors group: ipa aci-add --permissions=write --memberof=editors --group=admins --attrs=street --attrs=postalcode --prefix=none "admins edit the address of editors" Add an ACI that allows the admins group manage the street and zipcode of those who work for the boss: ipa aci-add --permissions=write --group=admins --attrs=street --attrs=postalcode --filter="(manager=uid=boss,cn=users,cn=accounts,dc=example,dc=com)" --prefix=none "Edit the address of those who work for the boss" Add an entirely new kind of record to IPA that isn't covered by any of the --type options, creating a permission: ipa permission-add --permissions=add --subtree="cn=*,cn=orange,cn=accounts,dc=example,dc=com" --desc="Add Orange Entries" add_orange The show command shows the raw 389-ds ACI. IMPORTANT: When modifying the target attributes of an existing ACI you must include all existing attributes as well. When doing an aci-mod the targetattr REPLACES the current attributes, it does not add to them. """ from copy import deepcopy from ipalib import api, crud, errors from ipalib import Object, Command from ipalib import Flag, Int, Str, StrEnum from ipalib.aci import ACI from ipalib import output from ipalib import _, ngettext from ipalib.plugins.baseldap import gen_pkey_only_option from ipapython.ipa_log_manager import * from ipapython.dn import DN ACI_NAME_PREFIX_SEP = ":" _type_map = { 'user': 'ldap:///' + str(DN(('uid', '*'), api.env.container_user, api.env.basedn)), 'group': 'ldap:///' + str(DN(('cn', '*'), api.env.container_group, api.env.basedn)), 'host': 'ldap:///' + str(DN(('fqdn', '*'), api.env.container_host, api.env.basedn)), 'hostgroup': 'ldap:///' + str(DN(('cn', '*'), api.env.container_hostgroup, api.env.basedn)), 'service': 'ldap:///' + str(DN(('krbprincipalname', '*'), api.env.container_service, api.env.basedn)), 'netgroup': 'ldap:///' + str(DN(('ipauniqueid', '*'), api.env.container_netgroup, api.env.basedn)), 'dnsrecord': 'ldap:///' + str(DN(('idnsname', '*'), api.env.container_dns, api.env.basedn)), } _valid_permissions_values = [ u'read', u'write', u'add', u'delete', u'all' ] _valid_prefix_values = ( u'permission', u'delegation', u'selfservice', u'none' ) class ListOfACI(output.Output): type = (list, tuple) doc = _('A list of ACI values') def validate(self, cmd, entries): assert isinstance(entries, self.type) for (i, entry) in enumerate(entries): if not isinstance(entry, unicode): raise TypeError(output.emsg % (cmd.name, self.__class__.__name__, self.name, i, unicode, type(entry), entry) ) aci_output = ( output.Output('result', unicode, 'A string representing the ACI'), output.value, output.summary, ) def _make_aci_name(aciprefix, aciname): """ Given a name and a prefix construct an ACI name. """ if aciprefix == u"none": return aciname return aciprefix + ACI_NAME_PREFIX_SEP + aciname def _parse_aci_name(aciname): """ Parse the raw ACI name and return a tuple containing the ACI prefix and the actual ACI name. """ aciparts = aciname.partition(ACI_NAME_PREFIX_SEP) if not aciparts[2]: # no prefix/name separator found return (u"none",aciparts[0]) return (aciparts[0], aciparts[2]) def _group_from_memberof(memberof): """ Pull the group name out of a memberOf filter """ st = memberof.find('memberOf=') if st == -1: # We have a raw group name, use that return api.Object['group'].get_dn(memberof) en = memberof.find(')', st) return memberof[st+9:en] def _make_aci(ldap, current, aciname, kw): """ Given a name and a set of keywords construct an ACI. """ # Do some quick and dirty validation. checked_args=['type','filter','subtree','targetgroup','attrs','memberof'] valid={} for arg in checked_args: if arg in kw: valid[arg]=kw[arg] is not None else: valid[arg]=False if valid['type'] + valid['filter'] + valid['subtree'] + valid['targetgroup'] > 1: raise errors.ValidationError(name='target', error=_('type, filter, subtree and targetgroup are mutually exclusive')) if 'aciprefix' not in kw: raise errors.ValidationError(name='aciprefix', error=_('ACI prefix is required')) if sum(valid.itervalues()) == 0: raise errors.ValidationError(name='target', error=_('at least one of: type, filter, subtree, targetgroup, attrs or memberof are required')) if valid['filter'] + valid['memberof'] > 1: raise errors.ValidationError(name='target', error=_('filter and memberof are mutually exclusive')) group = 'group' in kw permission = 'permission' in kw selfaci = 'selfaci' in kw and kw['selfaci'] == True if group + permission + selfaci > 1: raise errors.ValidationError(name='target', error=_('group, permission and self are mutually exclusive')) elif group + permission + selfaci == 0: raise errors.ValidationError(name='target', error=_('One of group, permission or self is required')) # Grab the dn of the group we're granting access to. This group may be a # permission or a user group. entry_attrs = [] if permission: # This will raise NotFound if the permission doesn't exist try: entry_attrs = api.Command['permission_show'](kw['permission'])['result'] except errors.NotFound, e: if 'test' in kw and not kw.get('test'): raise e else: entry_attrs = { 'dn': DN(('cn', kw['permission']), api.env.container_permission, api.env.basedn), } elif group: # Not so friendly with groups. This will raise try: group_dn = api.Object['group'].get_dn_if_exists(kw['group']) entry_attrs = {'dn': group_dn} except errors.NotFound: raise errors.NotFound(reason=_("Group '%s' does not exist") % kw['group']) try: a = ACI(current) a.name = _make_aci_name(kw['aciprefix'], aciname) a.permissions = kw['permissions'] if 'selfaci' in kw and kw['selfaci']: a.set_bindrule('userdn = "ldap:///self"') else: dn = entry_attrs['dn'] a.set_bindrule('groupdn = "ldap:///%s"' % dn) if valid['attrs']: a.set_target_attr(kw['attrs']) if valid['memberof']: try: api.Object['group'].get_dn_if_exists(kw['memberof']) except errors.NotFound: api.Object['group'].handle_not_found(kw['memberof']) groupdn = _group_from_memberof(kw['memberof']) a.set_target_filter('memberOf=%s' % groupdn) if valid['filter']: # Test the filter by performing a simple search on it. The # filter is considered valid if either it returns some entries # or it returns no entries, otherwise we let whatever exception # happened be raised. if kw['filter'] in ('', None, u''): raise errors.BadSearchFilter(info=_('empty filter')) try: entries = ldap.find_entries(filter=kw['filter']) except errors.NotFound: pass a.set_target_filter(kw['filter']) if valid['type']: target = _type_map[kw['type']] a.set_target(target) if valid['targetgroup']: # Purposely no try here so we'll raise a NotFound group_dn = api.Object['group'].get_dn_if_exists(kw['targetgroup']) target = 'ldap:///%s' % group_dn a.set_target(target) if valid['subtree']: # See if the subtree is a full URI target = kw['subtree'] if not target.startswith('ldap:///'): target = 'ldap:///%s' % target a.set_target(target) except SyntaxError, e: raise errors.ValidationError(name='target', error=_('Syntax Error: %(error)s') % dict(error=str(e))) return a def _aci_to_kw(ldap, a, test=False, pkey_only=False): """Convert an ACI into its equivalent keywords. This is used for the modify operation so we can merge the incoming kw and existing ACI and pass the result to _make_aci(). """ kw = {} kw['aciprefix'], kw['aciname'] = _parse_aci_name(a.name) if pkey_only: return kw kw['permissions'] = tuple(a.permissions) if 'targetattr' in a.target: kw['attrs'] = list(a.target['targetattr']['expression']) for i in xrange(len(kw['attrs'])): kw['attrs'][i] = unicode(kw['attrs'][i]) kw['attrs'] = tuple(kw['attrs']) if 'targetfilter' in a.target: target = a.target['targetfilter']['expression'] if target.startswith('(memberOf=') or target.startswith('memberOf='): (junk, memberof) = target.split('memberOf=', 1) memberof = DN(memberof) kw['memberof'] = memberof['cn'] else: kw['filter'] = unicode(target) if 'target' in a.target: target = a.target['target']['expression'] found = False for k in _type_map.keys(): if _type_map[k] == target: kw['type'] = unicode(k) found = True break; if not found: if target.startswith('('): kw['filter'] = unicode(target) else: # See if the target is a group. If so we set the # targetgroup attr, otherwise we consider it a subtree try: targetdn = DN(target.replace('ldap:///','')) except ValueError as e: raise errors.ValidationError(name='subtree', error=_("invalid DN (%s)") % e.message) if targetdn.endswith(DN(api.env.container_group, api.env.basedn)): kw['targetgroup'] = targetdn[0]['cn'] else: kw['subtree'] = unicode(target) groupdn = a.bindrule['expression'] groupdn = groupdn.replace('ldap:///','') if groupdn == 'self': kw['selfaci'] = True elif groupdn == 'anyone': pass else: groupdn = DN(groupdn) if len(groupdn) and groupdn[0].attr == 'cn': dn = DN() entry_attrs = {} try: (dn, entry_attrs) = ldap.get_entry(groupdn, ['cn']) except errors.NotFound, e: # FIXME, use real name here if test: dn = DN(('cn', 'test'), api.env.container_permission, api.env.basedn) entry_attrs = {'cn': [u'test']} if api.env.container_permission in dn: kw['permission'] = entry_attrs['cn'][0] else: if 'cn' in entry_attrs: kw['group'] = entry_attrs['cn'][0] return kw def _convert_strings_to_acis(acistrs): acis = [] for a in acistrs: try: acis.append(ACI(a)) except SyntaxError, e: root_logger.warning("Failed to parse: %s" % a) return acis def _find_aci_by_name(acis, aciprefix, aciname): name = _make_aci_name(aciprefix, aciname).lower() for a in acis: if a.name.lower() == name: return a raise errors.NotFound(reason=_('ACI with name "%s" not found') % aciname) def validate_permissions(ugettext, perm): perm = perm.strip().lower() if perm not in _valid_permissions_values: return '"%s" is not a valid permission' % perm def _normalize_permissions(perm): valid_permissions = [] perm = perm.strip().lower() if perm not in valid_permissions: valid_permissions.append(perm) return ','.join(valid_permissions) _prefix_option = StrEnum('aciprefix', cli_name='prefix', label=_('ACI prefix'), doc=_('Prefix used to distinguish ACI types ' \ '(permission, delegation, selfservice, none)'), values=_valid_prefix_values, ) class aci(Object): """ ACI object. """ NO_CLI = True label = _('ACIs') takes_params = ( Str('aciname', cli_name='name', label=_('ACI name'), primary_key=True, flags=('virtual_attribute',), ), Str('permission?', cli_name='permission', label=_('Permission'), doc=_('Permission ACI grants access to'), flags=('virtual_attribute',), ), Str('group?', cli_name='group', label=_('User group'), doc=_('User group ACI grants access to'), flags=('virtual_attribute',), ), Str('permissions+', validate_permissions, cli_name='permissions', label=_('Permissions'), doc=_('Permissions to grant' \ '(read, write, add, delete, all)'), csv=True, normalizer=_normalize_permissions, flags=('virtual_attribute',), ), Str('attrs*', cli_name='attrs', label=_('Attributes to which the permission applies'), doc=_('Attributes'), csv=True, flags=('virtual_attribute',), ), StrEnum('type?', cli_name='type', label=_('Type'), doc=_('type of IPA object (user, group, host, hostgroup, service, netgroup)'), values=(u'user', u'group', u'host', u'service', u'hostgroup', u'netgroup', u'dnsrecord'), flags=('virtual_attribute',), ), Str('memberof?', cli_name='memberof', label=_('Member of'), # FIXME: Does this label make sense? doc=_('Member of a group'), flags=('virtual_attribute',), ), Str('filter?', cli_name='filter', label=_('Filter'), doc=_('Legal LDAP filter (e.g. ou=Engineering)'), flags=('virtual_attribute',), ), Str('subtree?', cli_name='subtree', label=_('Subtree'), doc=_('Subtree to apply ACI to'), flags=('virtual_attribute',), ), Str('targetgroup?', cli_name='targetgroup', label=_('Target group'), doc=_('Group to apply ACI to'), flags=('virtual_attribute',), ), Flag('selfaci?', cli_name='self', label=_('Target your own entry (self)'), doc=_('Apply ACI to your own entry (self)'), flags=('virtual_attribute',), ), ) api.register(aci) class aci_add(crud.Create): """ Create new ACI. """ NO_CLI = True msg_summary = _('Created ACI "%(value)s"') takes_options = ( _prefix_option, Flag('test?', doc=_('Test the ACI syntax but don\'t write anything'), default=False, ), ) def execute(self, aciname, **kw): """ Execute the aci-create operation. Returns the entry as it will be created in LDAP. :param aciname: The name of the ACI being added. :param kw: Keyword arguments for the other LDAP attributes. """ assert 'aciname' not in kw ldap = self.api.Backend.ldap2 newaci = _make_aci(ldap, None, aciname, kw) (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry_attrs.get('aci', [])) for a in acis: # FIXME: add check for permission_group = permission_group if a.isequal(newaci) or newaci.name == a.name: raise errors.DuplicateEntry() newaci_str = unicode(newaci) entry_attrs['aci'].append(newaci_str) if not kw.get('test', False): ldap.update_entry(dn, entry_attrs) if kw.get('raw', False): result = dict(aci=unicode(newaci_str)) else: result = _aci_to_kw(ldap, newaci, kw.get('test', False)) return dict( result=result, value=aciname, ) api.register(aci_add) class aci_del(crud.Delete): """ Delete ACI. """ NO_CLI = True has_output = output.standard_boolean msg_summary = _('Deleted ACI "%(value)s"') takes_options = (_prefix_option,) def execute(self, aciname, aciprefix, **options): """ Execute the aci-delete operation. :param aciname: The name of the ACI being deleted. :param aciprefix: The ACI prefix. """ ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acistrs = entry_attrs.get('aci', []) acis = _convert_strings_to_acis(acistrs) aci = _find_aci_by_name(acis, aciprefix, aciname) for a in acistrs: candidate = ACI(a) if aci.isequal(candidate): acistrs.remove(a) break entry_attrs['aci'] = acistrs ldap.update_entry(dn, entry_attrs) return dict( result=True, value=aciname, ) api.register(aci_del) class aci_mod(crud.Update): """ Modify ACI. """ NO_CLI = True has_output_params = ( Str('aci', label=_('ACI'), ), ) takes_options = (_prefix_option,) internal_options = ['rename'] msg_summary = _('Modified ACI "%(value)s"') def execute(self, aciname, **kw): aciprefix = kw['aciprefix'] ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry_attrs.get('aci', [])) aci = _find_aci_by_name(acis, aciprefix, aciname) # The strategy here is to convert the ACI we're updating back into # a series of keywords. Then we replace any keywords that have been # updated and convert that back into an ACI and write it out. oldkw = _aci_to_kw(ldap, aci) newkw = deepcopy(oldkw) if newkw.get('selfaci', False): # selfaci is set in aci_to_kw to True only if the target is self kw['selfaci'] = True newkw.update(kw) for acikw in (oldkw, newkw): acikw.pop('aciname', None) # _make_aci is what is run in aci_add and validates the input. # Do this before we delete the existing ACI. newaci = _make_aci(ldap, None, aciname, newkw) if aci.isequal(newaci): raise errors.EmptyModlist() self.api.Command['aci_del'](aciname, aciprefix=aciprefix) try: result = self.api.Command['aci_add'](aciname, **newkw)['result'] except Exception, e: # ACI could not be added, try to restore the old deleted ACI and # report the ADD error back to user try: self.api.Command['aci_add'](aciname, **oldkw) except Exception: pass raise e if kw.get('raw', False): result = dict(aci=unicode(newaci)) else: result = _aci_to_kw(ldap, newaci) return dict( result=result, value=aciname, ) api.register(aci_mod) class aci_find(crud.Search): """ Search for ACIs. Returns a list of ACIs EXAMPLES: To find all ACIs that apply directly to members of the group ipausers: ipa aci-find --memberof=ipausers To find all ACIs that grant add access: ipa aci-find --permissions=add Note that the find command only looks for the given text in the set of ACIs, it does not evaluate the ACIs to see if something would apply. For example, searching on memberof=ipausers will find all ACIs that have ipausers as a memberof. There may be other ACIs that apply to members of that group indirectly. """ NO_CLI = True msg_summary = ngettext('%(count)d ACI matched', '%(count)d ACIs matched', 0) takes_options = (_prefix_option.clone_rename("aciprefix?", required=False), gen_pkey_only_option("name"),) def execute(self, term, **kw): ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry_attrs.get('aci', [])) results = [] if term: term = term.lower() for a in acis: if a.name.lower().find(term) != -1 and a not in results: results.append(a) acis = list(results) else: results = list(acis) if kw.get('aciname'): for a in acis: prefix, name = _parse_aci_name(a.name) if name != kw['aciname']: results.remove(a) acis = list(results) if kw.get('aciprefix'): for a in acis: prefix, name = _parse_aci_name(a.name) if prefix != kw['aciprefix']: results.remove(a) acis = list(results) if kw.get('attrs'): for a in acis: if not 'targetattr' in a.target: results.remove(a) continue alist1 = sorted( [t.lower() for t in a.target['targetattr']['expression']] ) alist2 = sorted([t.lower() for t in kw['attrs']]) if len(set(alist1) & set(alist2)) != len(alist2): results.remove(a) acis = list(results) if kw.get('permission'): try: self.api.Command['permission_show']( kw['permission'] ) except errors.NotFound: pass else: for a in acis: if a.bindrule['expression'] != ('ldap:///%s' % dn): results.remove(a) acis = list(results) if kw.get('permissions'): for a in acis: alist1 = sorted(a.permissions) alist2 = sorted(kw['permissions']) if len(set(alist1) & set(alist2)) != len(alist2): results.remove(a) acis = list(results) if kw.get('memberof'): try: dn = _group_from_memberof(kw['memberof']) except errors.NotFound: pass else: memberof_filter = '(memberOf=%s)' % dn for a in acis: if 'targetfilter' in a.target: targetfilter = a.target['targetfilter']['expression'] if targetfilter != memberof_filter: results.remove(a) else: results.remove(a) if kw.get('type'): for a in acis: if 'target' in a.target: target = a.target['target']['expression'] else: results.remove(a) continue found = False for k in _type_map.keys(): if _type_map[k] == target and kw['type'] == k: found = True break; if not found: try: results.remove(a) except ValueError: pass if kw.get('selfaci', False) is True: for a in acis: if a.bindrule['expression'] != u'ldap:///self': try: results.remove(a) except ValueError: pass if kw.get('group'): for a in acis: groupdn = a.bindrule['expression'] groupdn = DN(groupdn.replace('ldap:///','')) try: cn = groupdn[0]['cn'] except (IndexError, KeyError): cn = None if cn is None or cn != kw['group']: try: results.remove(a) except ValueError: pass if kw.get('targetgroup'): for a in acis: found = False if 'target' in a.target: target = a.target['target']['expression'] targetdn = DN(target.replace('ldap:///','')) group_container_dn = DN(api.env.container_group, api.env.basedn) if targetdn.endswith(group_container_dn): try: cn = targetdn[0]['cn'] except (IndexError, KeyError): cn = None if cn == kw['targetgroup']: found = True if not found: try: results.remove(a) except ValueError: pass if kw.get('filter'): if not kw['filter'].startswith('('): kw['filter'] = unicode('('+kw['filter']+')') for a in acis: if 'targetfilter' not in a.target or\ not a.target['targetfilter']['expression'] or\ a.target['targetfilter']['expression'] != kw['filter']: results.remove(a) if kw.get('subtree'): for a in acis: if 'target' in a.target: target = a.target['target']['expression'] else: results.remove(a) continue if kw['subtree'].lower() != target.lower(): try: results.remove(a) except ValueError: pass acis = [] for result in results: if kw.get('raw', False): aci = dict(aci=unicode(result)) else: aci = _aci_to_kw(ldap, result, pkey_only=kw.get('pkey_only', False)) acis.append(aci) return dict( result=acis, count=len(acis), truncated=False, ) api.register(aci_find) class aci_show(crud.Retrieve): """ Display a single ACI given an ACI name. """ NO_CLI = True has_output_params = ( Str('aci', label=_('ACI'), ), ) takes_options = (_prefix_option,) def execute(self, aciname, **kw): """ Execute the aci-show operation. Returns the entry :param uid: The login name of the user to retrieve. :param kw: unused """ ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry_attrs.get('aci', [])) aci = _find_aci_by_name(acis, kw['aciprefix'], aciname) if kw.get('raw', False): result = dict(aci=unicode(aci)) else: result = _aci_to_kw(ldap, aci) return dict( result=result, value=aciname, ) api.register(aci_show) class aci_rename(crud.Update): """ Rename an ACI. """ NO_CLI = True has_output_params = ( Str('aci', label=_('ACI'), ), ) takes_options = ( _prefix_option, Str('newname', doc=_('New ACI name'), ), ) msg_summary = _('Renamed ACI to "%(value)s"') def execute(self, aciname, **kw): ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.get_entry(self.api.env.basedn, ['aci']) acis = _convert_strings_to_acis(entry_attrs.get('aci', [])) aci = _find_aci_by_name(acis, kw['aciprefix'], aciname) for a in acis: prefix, name = _parse_aci_name(a.name) if _make_aci_name(prefix, kw['newname']) == a.name: raise errors.DuplicateEntry() # The strategy here is to convert the ACI we're updating back into # a series of keywords. Then we replace any keywords that have been # updated and convert that back into an ACI and write it out. newkw = _aci_to_kw(ldap, aci) if 'selfaci' in newkw and newkw['selfaci'] == True: # selfaci is set in aci_to_kw to True only if the target is self kw['selfaci'] = True if 'aciname' in newkw: del newkw['aciname'] # _make_aci is what is run in aci_add and validates the input. # Do this before we delete the existing ACI. newaci = _make_aci(ldap, None, kw['newname'], newkw) self.api.Command['aci_del'](aciname, aciprefix=kw['aciprefix']) result = self.api.Command['aci_add'](kw['newname'], **newkw)['result'] if kw.get('raw', False): result = dict(aci=unicode(newaci)) else: result = _aci_to_kw(ldap, newaci) return dict( result=result, value=kw['newname'], ) api.register(aci_rename) freeipa-3.3.4/ipalib/plugins/delegation.pyc0000664000175000017500000001653112271707517020272 0ustar mkosekmkosekó †fçRc@s¦ddlmZmZmZddlmZmZddlmZddlmZmZm Z ddlm Z ddlm Z m Z ddl mZedƒZd Zed d ed ƒƒfZd e fd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdejfd„ƒYZejeƒdS(iÿÿÿÿ(tapit_tngettext(tFlagtStr(tcontext(Rtcrudterrors(toutput(tObjecttCommand(tgen_pkey_only_optionsÕ Group to Group Delegation A permission enables fine-grained delegation of permissions. Access Control Rules, or instructions (ACIs), grant permission to permissions to perform given tasks such as adding a user, modifying a group, etc. Group to Group Delegations grants the members of one group to update a set of attributes of members of another group. EXAMPLES: Add a delegation rule to allow managers to edit employee's addresses: ipa delegation-add --attrs=street --group=managers --membergroup=employees "managers edit employees' street" When managing the list of attributes you need to include all attributes in the list, including existing ones. Add postalCode to the list: ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --membergroup=employees "managers edit employees' street" Display our updated rule: ipa delegation-show "managers edit employees' street" Delete a rule: ipa delegation-del "managers edit employees' street" u delegationtacitlabeltACIt delegationcBs:eZdZeZedƒZedƒZedƒZedƒZ e dddded ƒd ed ƒd e ƒe d dd dedƒd edƒde ƒe ddddedƒd edƒde dd„ƒe ddddedƒd edƒƒe ddddedƒd edƒƒfZ d„Z d„ZRS( s Delegation object. Rt delegationst Delegationst Delegationtacinametcli_nametnameR sDelegation nametdoct primary_keys permissions*t permissionst Permissionss5Permissions to grant (read, write). Default is write.tcsvsattrs+tattrst Attributess*Attributes to which the delegation appliest normalizercCs |jƒS(N(tlower(tvalue((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyt\stmemberoft membergroupsMember user groups!User group to apply delegation totgroups User groupsUser group ACI grants access tocsVd }t‡fd†|Dƒƒ}ˆjj|d psRtmethods(slabelslabel_singulars takes_paramssbindablesnames object_namesobject_name_plural(tdictRRR-(R,tjson_friendly_attributest json_dicttm((R,s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyt__json__js cCs#y |d=Wntk rnXdS(Nt aciprefix(tKeyError(R,tresult((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pytpostprocess_resultws  (t__name__t __module__t__doc__tFalseR&RR'R(R R$RtTrueR%R2R6(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyR?s@                    tdelegation_addcBs/eZedƒZedƒZeZd„ZRS(sAdd a new delegation.sAdded delegation "%(value)s"cKs`d|krd|dRR R?R6R.R;(R,RR@R5((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRAœs  ( R7R8RR9Rtstandard_booleant has_outputRBRA(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRE–s   tdelegation_modcBs/eZedƒZedƒZeZd„ZRS(sModify a delegation.sModified delegation "%(value)s"cKsGt|dRR R?R6R.(R,RR@R5((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRA®s  (R7R8RR9RBRCRDRA(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRI¨s  tdelegation_findcBsDeZedƒZedddƒZedƒfZeZ d„Z RS(sSearch for delegations.s%(count)d delegation matcheds%(count)d delegations matchediRcKsdt|dRR R?R6R.tlenR:(R,ttermR@tresultsR ((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRAÅs   ( R7R8RR9RRBR t takes_optionsRCRDRA(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRK»s  tdelegation_showcBs#eZedƒZeZd„ZRS(s'Display information about a delegation.cKsCtjd|dt|d}|jj|ƒtd|d|ƒS(Ntaci_showR3R5R(RR R>R?R6R.(R,RR@R5((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRAÚs  (R7R8RR9RCRDRA(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyRSÕs N(tipalibRRRRRtipalib.requestRRRRR R tipalib.plugins.baseldapR R9R>RCRtregistertCreateR<tDeleteREtUpdateRItSearchRKtRetrieveRS(((s7/home/mkosek/freeipa-clean/ipalib/plugins/delegation.pyts.  ?      freeipa-3.3.4/ipalib/plugins/xmlclient.pyc0000664000175000017500000000062012271707517020146 0ustar mkosekmkosekó MmâRc@s[dZddlmZdejkrWejjekrWddlmZejeƒndS(s XML-RPC client plugin. iÿÿÿÿ(tapit in_server(t xmlclientN( t__doc__tipalibRtenvRtFalset ipalib.rpcRtregister(((s6/home/mkosek/freeipa-clean/ipalib/plugins/xmlclient.pyts!freeipa-3.3.4/ipalib/plugins/ping.pyc0000664000175000017500000000404112271707517017105 0ustar mkosekmkosekó †fçRc@sddlmZddlmZddlmZddlmZmZddlmZmZedƒZ defd„ƒYZ ej e ƒd S( iÿÿÿÿ(tapi(tCommand(toutput(t_tngettext(tVERSIONt API_VERSIONs­ Ping the remote IPA server to ensure it is running. The ping command sends an echo request to an IPA server. The server returns its version information. This is used by an IPA client to confirm that the server is available and accepting requests. The server from xmlrpc_uri in /etc/ipa/default.conf is contacted first. If it does not respond then the client will contact any servers defined by ldap SRV records in DNS. EXAMPLES: Ping an IPA server: ipa ping ------------------------------------------ IPA server version 2.1.9. API version 2.20 ------------------------------------------ Ping an IPA server verbosely: ipa -v ping ipa: INFO: trying https://ipa.example.com/ipa/xml ipa: INFO: Forwarding 'ping' to server 'https://ipa.example.com/ipa/xml' ----------------------------------------------------- IPA server version 2.1.9. API version 2.20 ----------------------------------------------------- tpingcBs)eZedƒZejfZd„ZRS(sPing a remote server.cKstddttfƒS(s A possible enhancement would be to take an argument and echo it back but a fixed value works for now. tsummaryu%IPA server version %s. API version %s(tdictRR(tselftoptions((s1/home/mkosek/freeipa-clean/ipalib/plugins/ping.pytexecute=s(t__name__t __module__Rt__doc__RRt has_outputR (((s1/home/mkosek/freeipa-clean/ipalib/plugins/ping.pyR6s  N( tipalibRRRRRtipapython.versionRRRRtregister(((s1/home/mkosek/freeipa-clean/ipalib/plugins/ping.pyts freeipa-3.3.4/ipalib/plugins/privilege.pyc0000664000175000017500000001325412271707517020144 0ustar mkosekmkosekó MmâRc@s”ddlTddlmZmZmZedƒZdefd„ƒYZejeƒde fd„ƒYZ eje ƒde fd „ƒYZ eje ƒd e fd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdS(iÿÿÿÿ(t*(tapit_tngettexts¹ Privileges A privilege combines permissions into a logical task. A permission provides the rights to do a single task. There are some IPA operations that require multiple permissions to succeed. A privilege is where permissions are combined in order to perform a specific task. For example, adding a user requires the following permissions: * Creating a new user entry * Resetting a user password * Adding the new user to the default IPA users group Combining these three low-level tasks into a higher level task in the form of a privilege named "Add User" makes it easier to manage Roles. A privilege may not contain other privileges. See role and permission for additional information. t privilegec BsæeZdZejjZedƒZedƒZ ddgZ ddddgZ id gd6d gd6Z id gd6Z eZed ƒZed ƒZedd ddedƒdeƒedd ddedƒdedƒƒfZRS(s Privilege object. Rt privilegest nestedgroupt groupofnamestcnt descriptiontmembertmemberoftrolet permissiont Privilegest Privilegetcli_nametnametlabelsPrivilege namet primary_keytdesct DescriptiontdocsPrivilege description(t__name__t __module__t__doc__Rtenvtcontainer_privileget container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestattribute_memberstreverse_memberstTruetrdn_is_primary_keyRtlabel_singulartStrt takes_params(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR,s,             t privilege_addcBs eZedƒZedƒZRS(sAdd a new privilege.sAdded privilege "%(value)s"(RRRRt msg_summary(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR(Qs t privilege_delcBs eZedƒZedƒZRS(sDelete a privilege.sDeleted privilege "%(value)s"(RRRRR)(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR*Ys t privilege_modcBs eZedƒZedƒZRS(sModify a privilege.sModified privilege "%(value)s"(RRRRR)(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR+as tprivilege_findcBs&eZedƒZedddƒZRS(sSearch for privileges.s%(count)d privilege matcheds%(count)d privileges matchedi(RRRRRR)(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR,is tprivilege_showcBseZedƒZRS(s&Display information about a privilege.(RRRR(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR-sstprivilege_add_membercBseZedƒZeZRS(sAdd members to a privilege.(RRRRR#tNO_CLI(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR.ys tprivilege_remove_membercBseZdZeZRS(s) Remove members from a privilege (RRRR#R/(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR0stprivilege_add_permissionc BszeZedƒZdZdZdZdZej dƒej dde ded ƒƒej d de ded ƒƒfZ RS( sAdd permissions to a privilege.R-tpermission_add_memberR RtresulttfailedttypeRsMembers that could not be addedt completedsNumber of permissions added(RRRRt show_commandtmember_commandt reverse_attrt member_attrtoutputtEntrytOutputtdicttintt has_output(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyR1Šs     tprivilege_remove_permissionc Bs€eZedƒZdZdZdZdZdZe j dƒe j dd e d ed ƒƒe j d d e d ed ƒƒfZRS(s$Remove permissions from a privilege.R-tpermission_remove_memberR Rs%i permission removed.s%i permissions removed.R3R4R5RsMembers that could not be addedR6sNumber of permissions removed(s%i permission removed.s%i permissions removed.(RRRRR7R8R9R:tpermission_count_outR;R<R=R>R?R@(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyRA¡s     N(tipalib.plugins.baseldaptipalibRRRRt LDAPObjectRtregistert LDAPCreateR(t LDAPDeleteR*t LDAPUpdateR+t LDAPSearchR,t LDAPRetrieveR-t LDAPAddMemberR.tLDAPRemoveMemberR0tLDAPAddReverseMemberR1tLDAPRemoveReverseMemberRA(((s6/home/mkosek/freeipa-clean/ipalib/plugins/privilege.pyts.  "         freeipa-3.3.4/ipalib/plugins/hbactest.py0000664000175000017500000005054312271663206017606 0ustar mkosekmkosek# Authors: # Alexander Bokovoy # # Copyright (C) 2011 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 . from ipalib import api, errors, output, util from ipalib import Command, Str, Flag, Int, DeprecatedParam from types import NoneType from ipalib.cli import to_cli from ipalib import _, ngettext from ipapython.dn import DN if api.env.in_server and api.env.context in ['lite', 'server']: try: import ipaserver.dcerpc _dcerpc_bindings_installed = True except ImportError: _dcerpc_bindings_installed = False import pyhbac __doc__ = _(""" Simulate use of Host-based access controls HBAC rules control who can access what services on what hosts. You can use HBAC to control which users or groups can access a service, or group of services, on a target host. Since applying HBAC rules implies use of a production environment, this plugin aims to provide simulation of HBAC rules evaluation without having access to the production environment. Test user coming to a service on a named host against existing enabled rules. ipa hbactest --user= --host= --service= [--rules=rules-list] [--nodetail] [--enabled] [--disabled] [--sizelimit= ] --user, --host, and --service are mandatory, others are optional. If --rules is specified simulate enabling of the specified rules and test the login of the user using only these rules. If --enabled is specified, all enabled HBAC rules will be added to simulation If --disabled is specified, all disabled HBAC rules will be added to simulation If --nodetail is specified, do not return information about rules matched/not matched. If both --rules and --enabled are specified, apply simulation to --rules _and_ all IPA enabled rules. If no --rules specified, simulation is run against all IPA enabled rules. By default there is a IPA-wide limit to number of entries fetched, you can change it with --sizelimit option. EXAMPLES: 1. Use all enabled HBAC rules in IPA database to simulate: $ ipa hbactest --user=a1a --host=bar --service=sshd -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Matched rules: allow_all 2. Disable detailed summary of how rules were applied: $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail -------------------- Access granted: True -------------------- 3. Test explicitly specified HBAC rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \\ --rules=myrule --rules=my-second-rule --------------------- Access granted: False --------------------- Not matched rules: my-second-rule Not matched rules: myrule 4. Use all enabled HBAC rules in IPA database + explicitly specified rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \\ --rules=myrule --rules=my-second-rule --enabled -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Matched rules: allow_all 5. Test all disabled HBAC rules in IPA database: $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled --------------------- Access granted: False --------------------- Not matched rules: new-rule 6. Test all disabled HBAC rules in IPA database + explicitly specified rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \\ --rules=myrule --rules=my-second-rule --disabled --------------------- Access granted: False --------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule 7. Test all (enabled and disabled) HBAC rules in IPA database: $ ipa hbactest --user=a1a --host=bar --service=sshd \\ --enabled --disabled -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Not matched rules: new-rule Matched rules: allow_all HBACTEST AND TRUSTED DOMAINS When an external trusted domain is configured in IPA, HBAC rules are also applied on users accessing IPA resources from the trusted domain. Trusted domain users and groups (and their SIDs) can be then assigned to external groups which can be members of POSIX groups in IPA which can be used in HBAC rules and thus allowing access to resources protected by the HBAC system. hbactest plugin is capable of testing access for both local IPA users and users from the trusted domains, either by a fully qualified user name or by user SID. Such user names need to have a trusted domain specified as a short name (DOMAIN\Administrator) or with a user principal name (UPN), Administrator@ad.test. Please note that hbactest executed with a trusted domain user as --user parameter can be only run by members of "trust admins" group. EXAMPLES: 1. Test if a user from a trusted domain specified by its shortname matches any rule: $ ipa hbactest --user 'DOMAIN\Administrator' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 2. Test if a user from a trusted domain specified by its domain name matches any rule: $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 3. Test if a user from a trusted domain specified by its SID matches any rule: $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\ --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 4. Test if other user from a trusted domain specified by its SID matches any rule: $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \\ --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Not matched rules: can_login 5. Test if other user from a trusted domain specified by its shortname matches any rule: $ ipa hbactest --user 'DOMAIN\Otheruser' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Not matched rules: can_login """) def convert_to_ipa_rule(rule): # convert a dict with a rule to an pyhbac rule ipa_rule = pyhbac.HbacRule(rule['cn'][0]) ipa_rule.enabled = rule['ipaenabledflag'][0] # Following code attempts to process rule systematically structure = \ (('user', 'memberuser', 'user', 'group', ipa_rule.users), ('host', 'memberhost', 'host', 'hostgroup', ipa_rule.targethosts), ('sourcehost', 'sourcehost', 'host', 'hostgroup', ipa_rule.srchosts), ('service', 'memberservice', 'hbacsvc', 'hbacsvcgroup', ipa_rule.services), ) for element in structure: category = '%scategory' % (element[0]) if (category in rule and rule[category][0] == u'all') or (element[0] == 'sourcehost'): # rule applies to all elements # sourcehost is always set to 'all' element[4].category = set([pyhbac.HBAC_CATEGORY_ALL]) else: # rule is about specific entities # Check if there are explicitly listed entities attr_name = '%s_%s' % (element[1], element[2]) if attr_name in rule: element[4].names = rule[attr_name] # Now add groups of entities if they are there attr_name = '%s_%s' % (element[1], element[3]) if attr_name in rule: element[4].groups = rule[attr_name] if 'externalhost' in rule: ipa_rule.srchosts.names.extend(rule['externalhost']) #pylint: disable=E1101 return ipa_rule class hbactest(Command): __doc__ = _('Simulate use of Host-based access controls') has_output = ( output.summary, output.Output('warning', (list, tuple, NoneType), _('Warning')), output.Output('matched', (list, tuple, NoneType), _('Matched rules')), output.Output('notmatched', (list, tuple, NoneType), _('Not matched rules')), output.Output('error', (list, tuple, NoneType), _('Non-existent or invalid rules')), output.Output('value', bool, _('Result of simulation'), ['no_display']), ) takes_options = ( Str('user', cli_name='user', label=_('User name'), primary_key=True, ), DeprecatedParam('sourcehost?'), Str('targethost', cli_name='host', label=_('Target host'), ), Str('service', cli_name='service', label=_('Service'), ), Str('rules*', cli_name='rules', label=_('Rules to test. If not specified, --enabled is assumed'), csv=True, ), Flag('nodetail?', cli_name='nodetail', label=_('Hide details which rules are matched, not matched, or invalid'), ), Flag('enabled?', cli_name='enabled', label=_('Include all enabled IPA rules into test [default]'), ), Flag('disabled?', cli_name='disabled', label=_('Include all disabled IPA rules into test'), ), Int('sizelimit?', label=_('Size Limit'), doc=_('Maximum number of rules to process when no --rules is specified'), flags=['no_display'], minvalue=0, autofill=False, ), ) def canonicalize(self, host): """ Canonicalize the host name -- add default IPA domain if that is missing """ if host.find('.') == -1: return u'%s.%s' % (host, self.env.domain) return host def execute(self, *args, **options): # First receive all needed information: # 1. HBAC rules (whether enabled or disabled) # 2. Required options are (user, target host, service) # 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output rules = [] # Use all enabled IPA rules by default all_enabled = True all_disabled = False # We need a local copy of test rules in order find incorrect ones testrules = {} if 'rules' in options: testrules = list(options['rules']) # When explicit rules are provided, disable assumptions all_enabled = False all_disabled = False sizelimit = None if 'sizelimit' in options: sizelimit = int(options['sizelimit']) # Check if --disabled is specified, include all disabled IPA rules if options['disabled']: all_disabled = True all_enabled = False # Finally, if enabled is specified implicitly, override above decisions if options['enabled']: all_enabled = True hbacset = [] if len(testrules) == 0: hbacset = self.api.Command.hbacrule_find(sizelimit=sizelimit)['result'] else: for rule in testrules: try: hbacset.append(self.api.Command.hbacrule_show(rule)['result']) except: pass # We have some rules, import them # --enabled will import all enabled rules (default) # --disabled will import all disabled rules # --rules will implicitly add the rules from a rule list for rule in hbacset: ipa_rule = convert_to_ipa_rule(rule) if ipa_rule.name in testrules: ipa_rule.enabled = True rules.append(ipa_rule) testrules.remove(ipa_rule.name) elif all_enabled and ipa_rule.enabled: # Option --enabled forces to include all enabled IPA rules into test rules.append(ipa_rule) elif all_disabled and not ipa_rule.enabled: # Option --disabled forces to include all disabled IPA rules into test ipa_rule.enabled = True rules.append(ipa_rule) # Check if there are unresolved rules left if len(testrules) > 0: # Error, unresolved rules are left in --rules return {'summary' : unicode(_(u'Unresolved rules in --rules')), 'error': testrules, 'matched': None, 'notmatched': None, 'warning' : None, 'value' : False} # Rules are converted to pyhbac format, build request and then test it request = pyhbac.HbacRequest() if options['user'] != u'all': # check first if this is not a trusted domain user if _dcerpc_bindings_installed: is_valid_sid = ipaserver.dcerpc.is_sid_valid(options['user']) else: is_valid_sid = False components = util.normalize_name(options['user']) if is_valid_sid or 'domain' in components or 'flatname' in components: # this is a trusted domain user if not _dcerpc_bindings_installed: raise errors.NotFound(reason=_( 'Cannot perform external member validation without ' 'Samba 4 support installed. Make sure you have installed ' 'server-trust-ad sub-package of IPA on the server')) domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound(reason=_( 'Cannot search in trusted domains without own domain configured. ' 'Make sure you have run ipa-adtrust-install on the IPA server first')) user_sid, group_sids = domain_validator.get_trusted_domain_user_and_groups(options['user']) request.user.name = user_sid # Now search for all external groups that have this user or # any of its groups in its external members. Found entires # memberOf links will be then used to gather all groups where # this group is assigned, including the nested ones filter_sids = "(&(objectclass=ipaexternalgroup)(|(ipaExternalMember=%s)))" \ % ")(ipaExternalMember=".join(group_sids + [user_sid]) ldap = self.api.Backend.ldap2 group_container = DN(api.env.container_group, api.env.basedn) try: entries, truncated = ldap.find_entries(filter_sids, ['memberof'], group_container) except errors.NotFound: request.user.groups = [] else: groups = [] for dn, entry in entries: memberof_dns = entry.get('memberof', []) for memberof_dn in memberof_dns: if memberof_dn.endswith(group_container): groups.append(memberof_dn[0][0].value) request.user.groups = sorted(set(groups)) else: # try searching for a local user try: request.user.name = options['user'] search_result = self.api.Command.user_show(request.user.name)['result'] groups = search_result['memberof_group'] if 'memberofindirect_group' in search_result: groups += search_result['memberofindirect_group'] request.user.groups = sorted(set(groups)) except: pass if options['service'] != u'all': try: request.service.name = options['service'] service_result = self.api.Command.hbacsvc_show(request.service.name)['result'] if 'memberof_hbacsvcgroup' in service_result: request.service.groups = service_result['memberof_hbacsvcgroup'] except: pass if options['targethost'] != u'all': try: request.targethost.name = self.canonicalize(options['targethost']) tgthost_result = self.api.Command.host_show(request.targethost.name)['result'] groups = tgthost_result['memberof_hostgroup'] if 'memberofindirect_hostgroup' in tgthost_result: groups += tgthost_result['memberofindirect_hostgroup'] request.targethost.groups = sorted(set(groups)) except: pass matched_rules = [] notmatched_rules = [] error_rules = [] warning_rules = [] result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None} if not options['nodetail']: # Validate runs rules one-by-one and reports failed ones for ipa_rule in rules: try: res = request.evaluate([ipa_rule]) if res == pyhbac.HBAC_EVAL_ALLOW: matched_rules.append(ipa_rule.name) if res == pyhbac.HBAC_EVAL_DENY: notmatched_rules.append(ipa_rule.name) except pyhbac.HbacError as (code, rule_name): if code == pyhbac.HBAC_EVAL_ERROR: error_rules.append(rule_name) self.log.info('Native IPA HBAC rule "%s" parsing error: %s' % \ (rule_name, pyhbac.hbac_result_string(code))) except (TypeError, IOError) as (info): self.log.error('Native IPA HBAC module error: %s' % (info)) access_granted = len(matched_rules) > 0 else: res = request.evaluate(rules) access_granted = (res == pyhbac.HBAC_EVAL_ALLOW) result['summary'] = _('Access granted: %s') % (access_granted) if len(matched_rules) > 0: result['matched'] = matched_rules if len(notmatched_rules) > 0: result['notmatched'] = notmatched_rules if len(error_rules) > 0: result['error'] = error_rules if len(warning_rules) > 0: result['warning'] = warning_rules result['value'] = access_granted return result def output_for_cli(self, textui, output, *args, **options): """ Command.output_for_cli() uses --all option to decide whether to print detailed output. We use --detail to allow that, thus we need to redefine output_for_cli(). """ # Note that we don't actually use --detail below to see if details need # to be printed as our execute() method will return None for corresponding # entries and None entries will be skipped. for o in self.output: outp = self.output[o] if 'no_display' in outp.flags: continue result = output[o] if isinstance(result, (list, tuple)): textui.print_attribute(unicode(outp.doc), result, '%s: %s', 1, True) elif isinstance(result, (unicode, bool)): if o == 'summary': textui.print_summary(result) else: textui.print_indented(result) # Propagate integer value for result. It will give proper command line result for scripts return int(not output['value']) api.register(hbactest) freeipa-3.3.4/ipalib/plugins/pkinit.pyc0000664000175000017500000000534712271707517017460 0ustar mkosekmkosekó ­8 Rc@sÁddlmZmZddlmZmZddlmZmZddlmZddlm Z edƒZ defd„ƒYZ ej e ƒd „Z d efd „ƒYZej eƒd S( iÿÿÿÿ(tapiterrors(tInttStr(tObjecttCommand(t_(tDNsŽ Kerberos pkinit options Enable or disable anonymous pkinit using the principal WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with pkinit support. EXAMPLES: Enable anonymous pkinit: ipa pkinit-anonymous enable Disable anonymous pkinit: ipa pkinit-anonymous disable For more information on anonymous pkinit see: http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit tpkinitcBs&eZdZedƒZedƒZRS(s PKINIT Options RtPKINIT(t__name__t __module__t__doc__Rt object_nametlabel(((s3/home/mkosek/freeipa-clean/ipalib/plugins/pkinit.pyR.s cCsM|jƒ}|dkrI|dkrItjdddtdƒ|ƒ‚ndS(s& Accepts only Enable/Disable. tenabletdisabletnametactionterrorsUnknown command %sN(tlowerRtValidationErrorR(tugettextRta((s3/home/mkosek/freeipa-clean/ipalib/plugins/pkinit.pyt valid_arg8s   tpkinit_anonymouscBsleZedƒZdejjZedefdejjfdejj ƒZ e de ƒfZ d„ZRS(s#Enable or Disable Anonymous PKINIT.sWELLKNOWN/ANONYMOUS@%stkrbprincipalnametcntkerberosRcKsé|jjj}t}d}|j|jdgƒ\}}d|kr\|ddjƒ}n|jƒdkrŒ|dkr¼t}d}q¼n0|jƒdkr¼|dkr¼t}d}q¼n|rÜ|j |i|d6ƒnt dtƒS(Nt nsaccountlockiRttrueRtTRUEtresult( RtBackendtldap2tFalsetNonet get_entryt default_dnRtTruet update_entrytdict(tselfRtoptionstldaptset_locktlocktdnt entry_attrs((s3/home/mkosek/freeipa-clean/ipalib/plugins/pkinit.pytexecuteMs"     (scnskerberos(R R RR Rtenvtrealmt princ_nameRtbasednR&RRt takes_argsR1(((s3/home/mkosek/freeipa-clean/ipalib/plugins/pkinit.pyRCs  -N(tipalibRRRRRRRt ipapython.dnRR RtregisterRR(((s3/home/mkosek/freeipa-clean/ipalib/plugins/pkinit.pyts   "freeipa-3.3.4/ipalib/plugins/automount.pyc0000664000175000017500000006624112271707517020215 0ustar mkosekmkosekó †fçRc@sRddlZddlmZmZddlmZmZddlmZmZmZddl Tddlm Z m Z e dƒZ dZ d2Zd3Zd efd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZ eje ƒde!fd„ƒYZ"eje"ƒd efd!„ƒYZ#eje#ƒd"efd#„ƒYZ$eje$ƒd$efd%„ƒYZ%eje%ƒd&efd'„ƒYZ&eje&ƒd(efd)„ƒYZ'eje'ƒd*efd+„ƒYZ(eje(ƒd,e!fd-„ƒYZ)eje)ƒd.efd/„ƒYZ*eje*ƒd0efd1„ƒYZ+eje+ƒdS(4iÿÿÿÿN(tapiterrors(tObjecttCommand(tFlagtStrtIA5Str(t*(t_tngettexts6 Automount Stores automount(8) configuration for autofs(8) in IPA. The base of an automount configuration is the configuration file auto.master. This is also the base location in IPA. Multiple auto.master configurations can be stored in separate locations. A location is implementation-specific with the default being a location named 'default'. For example, you can have locations by geographic region, by floor, by type, etc. Automount has three basic object types: locations, maps and keys. A location defines a set of maps anchored in auto.master. This allows you to store multiple automount configurations. A location in itself isn't very interesting, it is just a point to start a new automount map. A map is roughly equivalent to a discrete automount file and provides storage for keys. A key is a mount point associated with a map. When a new location is created, two maps are automatically created for it: auto.master and auto.direct. auto.master is the root map for all automount maps for the location. auto.direct is the default map for direct mounts and is mounted on /-. An automount map may contain a submount key. This key defines a mount location within the map that references another map. This can be done either using automountmap-add-indirect --parentmap or manually with automountkey-add and setting info to "-type=autofs :". EXAMPLES: Locations: Create a named location, "Baltimore": ipa automountlocation-add baltimore Display the new location: ipa automountlocation-show baltimore Find available locations: ipa automountlocation-find Remove a named automount location: ipa automountlocation-del baltimore Show what the automount maps would look like if they were in the filesystem: ipa automountlocation-tofiles baltimore Import an existing configuration into a location: ipa automountlocation-import baltimore /etc/auto.master The import will fail if any duplicate entries are found. For continuous operation where errors are ignored, use the --continue option. Maps: Create a new map, "auto.share": ipa automountmap-add baltimore auto.share Display the new map: ipa automountmap-show baltimore auto.share Find maps in the location baltimore: ipa automountmap-find baltimore Create an indirect map with auto.share as a submount: ipa automountmap-add-indirect baltimore --parentmap=auto.share --mount=sub auto.man This is equivalent to: ipa automountmap-add-indirect baltimore --mount=/man auto.man ipa automountkey-add baltimore auto.man --key=sub --info="-fstype=autofs ldap:auto.share" Remove the auto.share map: ipa automountmap-del baltimore auto.share Keys: Create a new key for the auto.share map in location baltimore. This ties the map we previously created to auto.master: ipa automountkey-add baltimore auto.master --key=/share --info=auto.share Create a new key for our auto.share map, an NFS mount for man pages: ipa automountkey-add baltimore auto.share --key=man --info="-ro,soft,rsize=8192,wsize=8192 ipa.example.com:/shared/man" Find all keys for the auto.share map: ipa automountkey-find baltimore auto.share Find all direct automount keys: ipa automountkey-find baltimore --key=/- Remove the man key from the auto.share map: ipa automountkey-del baltimore auto.share --key=man u/-u auto.directtautomountlocationc BseZdZejjZedƒZedƒZ dgZ dgZ edƒZ edƒZ edddd ed ƒd ed ƒd eƒfZRS(s0 Location container for automount maps. sautomount locationsautomount locationst nscontainertcnsAutomount LocationssAutomount Locationtcli_nametlocationtlabeltLocationtdocsAutomount location name.t primary_key(t__name__t __module__t__doc__Rtenvtcontainer_automountt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributesRtlabel_singularRtTruet takes_params(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR Ès          tautomountlocation_addcBs)eZedƒZedƒZd„ZRS(s Create a new automount location.s$Added automount location "%(value)s"cOsUt|tƒst‚|jjd|ddƒ|jjd|dddtƒ|S(Ntautomountmap_addiÿÿÿÿu auto.mastertautomountmap_add_indirectu auto.directtkey(t isinstancetDNtAssertionErrorRRtDIRECT_MAP_KEY(tselftldaptdnt entry_attrstkeystoptions((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyt post_callbackås  (RRRRt msg_summaryR.(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR às  tautomountlocation_delcBs eZedƒZedƒZRS(sDelete an automount location.s&Deleted automount location "%(value)s"(RRRRR/(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR0ös tautomountlocation_showcBseZedƒZRS(sDisplay an automount location.(RRRR(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR1þstautomountlocation_findcBs&eZedƒZedddƒZRS(s!Search for an automount location.s$%(count)d automount location matcheds%%(count)d automount locations matchedi(RRRRR R/(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR2s tautomountlocation_tofilescBs&eZedƒZd„Zd„ZRS(s1Generate automount files for a specific location.c Os¾|jj}|jjd|dƒ}g}|jjd|ddƒ}|d}|d}i}dg} xq|D]i} | dd} | j| ƒ| jdƒ} |jjd|d| dƒ}|d}|d|| RNt num_parentsRtnametKeyErrort ValueErrorRRR‰tget_dntmake_dn_from_attrRwRxt get_entryRR]R%RRRŽt find_entriestSCOPE_ONELEVELRRBtLimitsExceeded(R(R,tkwargsR)tpkeyt parent_keyst parent_dnR*R+tsfilterRŽt attrs_listtentriesR5((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyR¢¬sF          (cGsm|d}|j|jƒd}|jj|j|jƒdƒ}tjd|ji|d6|d6ƒ‚dS(NiÿÿÿÿiiRVR#RF(R@t rdn_separatorRsRR]tobject_not_found_msg(R(R,R©R#RF((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pythandle_not_foundãs  "  cGs–|d}|j|jƒd}|jj|j|jƒdƒ}|rrtjd|ji|d6|d6ƒ‚n tjd|ji|d6ƒ‚dS(NiÿÿÿÿiiRlR#RF(R@R¯RsRRutalready_exists_msgtkey_already_exists_msg(R(R,R©R#RF((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pythandle_duplicate_entryís "    cCs0|tkr(|r(|jj||fƒS|SdS(N(R'R¯Rs(R(R#RF((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pytget_pkþscKsîd}|jdƒ}|dkr%dS|jj||d|ƒd}t|ƒdkrê|tkrÈ|jdƒ}|jj|||d}t|ƒdkrÁ|j|||j||ƒƒqÈdSn|j|||j||ƒƒndS(NRJR6iR7(RARwtmethodstfindRNR'R´Rµ(R(RR`tkeykwRFR#R®((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pytcheck_key_uniquenesss  "(s req_updateN( RRRRR‰RRRRRRRRRtrdn_is_primary_keyR¯RRRxRRžRRR²R³R°R¢R±R´RARµR¹(((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyRJƒsD                   7  RkcBsGeZedƒZedƒZddgZd„Zd„Zd„ZRS(sCreate a new automount key.sAdded automount key "%(value)s"R…RcOsWt|tƒst‚|jddƒ|jddƒ|jj|d|d||S(NRR…iþÿÿÿiÿÿÿÿ(R$R%R&tpopRAR=R¹(R(R)R*R+R,R-((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pyt pre_callbacks ccs#x|jjƒD] }|VqWdS(N(R=tget_ancestor_primary_keys(R(R#((s6/home/mkosek/freeipa-clean/ipalib/plugins/automount.pytget_args%scOsu|d}|jddƒ}|jj||ƒ||jjjsd  a F     ] ¾       ‘  3 ' 8  freeipa-3.3.4/ipalib/plugins/migration.py0000664000175000017500000011213012271663206017771 0ustar mkosekmkosek# Authors: # Pavel Zuna # # Copyright (C) 2009 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 . import re from ipalib import api, errors, output from ipalib import Command, Password, Str, Flag, StrEnum, DNParam from ipalib.cli import to_cli from ipalib.plugins.user import NO_UPG_MAGIC if api.env.in_server and api.env.context in ['lite', 'server']: try: from ipaserver.plugins.ldap2 import ldap2 except StandardError, e: raise e from ipalib import _ from ipapython.dn import DN import datetime __doc__ = _(""" Migration to IPA Migrate users and groups from an LDAP server to IPA. This performs an LDAP query against the remote server searching for users and groups in a container. In order to migrate passwords you need to bind as a user that can read the userPassword attribute on the remote server. This is generally restricted to high-level admins such as cn=Directory Manager in 389-ds (this is the default bind user). The default user container is ou=People. The default group container is ou=Groups. Users and groups that already exist on the IPA server are skipped. Two LDAP schemas define how group members are stored: RFC2307 and RFC2307bis. RFC2307bis uses member and uniquemember to specify group members, RFC2307 uses memberUid. The default schema is RFC2307bis. The schema compat feature allows IPA to reformat data for systems that do not support RFC2307bis. It is recommended that this feature is disabled during migration to reduce system overhead. It can be re-enabled after migration. To migrate with it enabled use the "--with-compat" option. Migrated users do not have Kerberos credentials, they have only their LDAP password. To complete the migration process, users need to go to http://ipa.example.com/ipa/migration and authenticate using their LDAP password in order to generate their Kerberos credentials. Migration is disabled by default. Use the command ipa config-mod to enable it: ipa config-mod --enable-migration=TRUE If a base DN is not provided with --basedn then IPA will use either the value of defaultNamingContext if it is set or the first value in namingContexts set in the root of the remote LDAP server. Users are added as members to the default user group. This can be a time-intensive task so during migration this is done in a batch mode for every 100 users. As a result there will be a window in which users will be added to IPA but will not be members of the default user group. EXAMPLES: The simplest migration, accepting all defaults: ipa migrate-ds ldap://ds.example.com:389 Specify the user and group container. This can be used to migrate user and group data from an IPA v1 server: ipa migrate-ds --user-container='cn=users,cn=accounts' \\ --group-container='cn=groups,cn=accounts' \\ ldap://ds.example.com:389 Since IPA v2 server already contain predefined groups that may collide with groups in migrated (IPA v1) server (for example admins, ipausers), users having colliding group as their primary group may happen to belong to an unknown group on new IPA v2 server. Use --group-overwrite-gid option to overwrite GID of already existing groups to prevent this issue: ipa migrate-ds --group-overwrite-gid \\ --user-container='cn=users,cn=accounts' \\ --group-container='cn=groups,cn=accounts' \\ ldap://ds.example.com:389 Migrated users or groups may have object class and accompanied attributes unknown to the IPA v2 server. These object classes and attributes may be left out of the migration process: ipa migrate-ds --user-container='cn=users,cn=accounts' \\ --group-container='cn=groups,cn=accounts' \\ --user-ignore-objectclass=radiusprofile \\ --user-ignore-attribute=radiusgroupname \\ ldap://ds.example.com:389 LOGGING Migration will log warnings and errors to the Apache error log. This file should be evaluated post-migration to correct or investigate any issues that were discovered. For every 100 users migrated an info-level message will be displayed to give the current progress and duration to make it possible to track the progress of migration. If the log level is debug, either by setting debug = True in /etc/ipa/default.conf or /etc/ipa/server.conf, then an entry will be printed for each user added plus a summary when the default user group is updated. """) # USER MIGRATION CALLBACKS AND VARS _krb_err_msg = _('Kerberos principal %s already exists. Use \'ipa user-mod\' to set it manually.') _krb_failed_msg = _('Unable to determine if Kerberos principal %s already exists. Use \'ipa user-mod\' to set it manually.') _grp_err_msg = _('Failed to add user to the default group. Use \'ipa group-add-member\' to add manually.') _ref_err_msg = _('Migration of LDAP search reference is not supported.') _dn_err_msg = _('Malformed DN') _supported_schemas = (u'RFC2307bis', u'RFC2307') _compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config')) def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs): assert isinstance(dn, DN) attr_blacklist = ['krbprincipalkey','memberofindirect','memberindirect'] attr_blacklist.extend(kwargs.get('attr_blacklist', [])) ds_ldap = ctx['ds_ldap'] has_upg = ctx['has_upg'] search_bases = kwargs.get('search_bases', None) valid_gids = kwargs['valid_gids'] invalid_gids = kwargs['invalid_gids'] if 'gidnumber' not in entry_attrs: raise errors.NotFound(reason=_('%(user)s is not a POSIX user') % dict(user=pkey)) else: # See if the gidNumber at least points to a valid group on the remote # server. if entry_attrs['gidnumber'][0] in invalid_gids: api.log.warn('GID number %s of migrated user %s does not point to a known group.' \ % (entry_attrs['gidnumber'][0], pkey)) elif entry_attrs['gidnumber'][0] not in valid_gids: try: (remote_dn, remote_entry) = ds_ldap.find_entry_by_attr( 'gidnumber', entry_attrs['gidnumber'][0], 'posixgroup', [''], search_bases['group'] ) valid_gids.append(entry_attrs['gidnumber'][0]) except errors.NotFound: api.log.warn('GID number %s of migrated user %s does not point to a known group.' \ % (entry_attrs['gidnumber'][0], pkey)) invalid_gids.append(entry_attrs['gidnumber'][0]) except errors.SingleMatchExpected, e: # GID number matched more groups, this should not happen api.log.warn('GID number %s of migrated user %s should match 1 group, but it matched %d groups' \ % (entry_attrs['gidnumber'][0], pkey, e.found)) except errors.LimitsExceeded, e: api.log.warn('Search limit exceeded searching for GID %s' % entry_attrs['gidnumber'][0]) # We don't want to create a UPG so set the magic value in description # to let the DS plugin know. entry_attrs.setdefault('description', []) entry_attrs['description'].append(NO_UPG_MAGIC) # fill in required attributes by IPA entry_attrs['ipauniqueid'] = 'autogenerate' if 'homedirectory' not in entry_attrs: homes_root = config.get('ipahomesrootdir', ('/home', ))[0] home_dir = '%s/%s' % (homes_root, pkey) home_dir = home_dir.replace('//', '/').rstrip('/') entry_attrs['homedirectory'] = home_dir if 'loginshell' not in entry_attrs: default_shell = config.get('ipadefaultloginshell', ['/bin/sh'])[0] entry_attrs.setdefault('loginshell', default_shell) # do not migrate all attributes for attr in entry_attrs.keys(): if attr in attr_blacklist: del entry_attrs[attr] # do not migrate all object classes if 'objectclass' in entry_attrs: for object_class in kwargs.get('oc_blacklist', []): try: entry_attrs['objectclass'].remove(object_class) except ValueError: # object class not present pass # generate a principal name and check if it isn't already taken principal = u'%s@%s' % (pkey, api.env.realm) try: ldap.find_entry_by_attr( 'krbprincipalname', principal, 'krbprincipalaux', [''], DN(api.env.container_user, api.env.basedn) ) except errors.NotFound: entry_attrs['krbprincipalname'] = principal except errors.LimitsExceeded: failed[pkey] = unicode(_krb_failed_msg % principal) else: failed[pkey] = unicode(_krb_err_msg % principal) # Fix any attributes with DN syntax that point to entries in the old # tree for attr in entry_attrs.keys(): if ldap.has_dn_syntax(attr): for ind, value in enumerate(entry_attrs[attr]): if not isinstance(value, DN): # value is not DN instance, the automatic encoding may have # failed due to missing schema or the remote attribute type OID was # not detected as DN type. Try to work this around api.log.debug('%s: value %s of type %s in attribute %s is not a DN' ', convert it', pkey, value, type(value), attr) try: value = DN(value) except ValueError, e: api.log.warn('%s: skipping normalization of value %s of type %s ' 'in attribute %s which could not be converted to DN: %s', pkey, value, type(value), attr, e) continue try: (remote_dn, remote_entry) = ds_ldap.get_entry(value, [api.Object.user.primary_key.name, api.Object.group.primary_key.name]) except errors.NotFound: api.log.warn('%s: attribute %s refers to non-existent entry %s' % (pkey, attr, value)) continue if value.endswith(search_bases['user']): primary_key = api.Object.user.primary_key.name container = api.env.container_user elif value.endswith(search_bases['group']): primary_key = api.Object.group.primary_key.name container = api.env.container_group else: api.log.warn('%s: value %s in attribute %s does not belong into any known container' % (pkey, value, attr)) continue if not remote_entry.get(primary_key): api.log.warn('%s: there is no primary key %s to migrate for %s' % (pkey, primary_key, attr)) continue api.log.debug('converting DN value %s for %s in %s' % (value, attr, dn)) rdnval = remote_entry[primary_key][0].lower() entry_attrs[attr][ind] = DN((primary_key, rdnval), container, api.env.basedn) return dn def _post_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx): assert isinstance(dn, DN) _update_default_group(ldap, pkey, config, ctx, False) if 'description' in entry_attrs and NO_UPG_MAGIC in entry_attrs['description']: entry_attrs['description'].remove(NO_UPG_MAGIC) update_attrs = dict(description = entry_attrs['description']) try: ldap.update_entry(dn, update_attrs) except (errors.EmptyModlist, errors.NotFound): pass def _update_default_group(ldap, pkey, config, ctx, force): migrate_cnt = ctx['migrate_cnt'] group_dn = ctx['def_group_dn'] # Purposely let this fire when migrate_cnt == 0 so on re-running migration # it can catch any users migrated but not added to the default group. if force or migrate_cnt % 100 == 0: s = datetime.datetime.now() searchfilter = "(&(objectclass=posixAccount)(!(memberof=%s)))" % group_dn try: (result, truncated) = ldap.find_entries(searchfilter, [''], api.env.container_user, scope=ldap.SCOPE_SUBTREE, time_limit = -1) except errors.NotFound: return new_members = [] (group_dn, group_entry_attrs) = ldap.get_entry(group_dn, ['member']) for m in result: if m[0] not in group_entry_attrs.get('member', []): new_members.append(m[0]) if len(new_members) > 0: members = group_entry_attrs.get('member', []) members.extend(new_members) group_entry_attrs['member'] = members try: ldap.update_entry(group_dn, group_entry_attrs) except errors.EmptyModlist: pass e = datetime.datetime.now() d = e - s mode = " (forced)" if force else "" api.log.debug('Adding %d users to group%s duration %s' % (len(new_members), mode, d)) # GROUP MIGRATION CALLBACKS AND VARS def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs): def convert_members_rfc2307bis(member_attr, search_bases, overwrite=False): """ Convert DNs in member attributes to work in IPA. """ new_members = [] entry_attrs.setdefault(member_attr, []) for m in entry_attrs[member_attr]: try: m = DN(m) except ValueError, e: # This should be impossible unless the remote server # doesn't enforce syntax checking. api.log.error('Malformed DN %s: %s' % (m, e)) continue try: rdnval = m[0].value except IndexError: api.log.error('Malformed DN %s has no RDN?' % m) continue if m.endswith(search_bases['user']): api.log.info('migrating %s user %s' % (member_attr, m)) m = DN((api.Object.user.primary_key.name, rdnval), api.env.container_user, api.env.basedn) elif m.endswith(search_bases['group']): api.log.info('migrating %s group %s' % (member_attr, m)) m = DN((api.Object.group.primary_key.name, rdnval), api.env.container_group, api.env.basedn) else: api.log.error('entry %s does not belong into any known container' % m) continue new_members.append(m) del entry_attrs[member_attr] if overwrite: entry_attrs['member'] = [] entry_attrs['member'] += new_members def convert_members_rfc2307(member_attr): """ Convert usernames in member attributes to work in IPA. """ new_members = [] entry_attrs.setdefault(member_attr, []) for m in entry_attrs[member_attr]: memberdn = DN((api.Object.user.primary_key.name, m), api.env.container_user, api.env.basedn) new_members.append(memberdn) entry_attrs['member'] = new_members assert isinstance(dn, DN) attr_blacklist = ['memberofindirect','memberindirect'] attr_blacklist.extend(kwargs.get('attr_blacklist', [])) schema = kwargs.get('schema', None) entry_attrs['ipauniqueid'] = 'autogenerate' if schema == 'RFC2307bis': search_bases = kwargs.get('search_bases', None) if not search_bases: raise ValueError('Search bases not specified') convert_members_rfc2307bis('member', search_bases, overwrite=True) convert_members_rfc2307bis('uniquemember', search_bases) elif schema == 'RFC2307': convert_members_rfc2307('memberuid') else: raise ValueError('Schema %s not supported' % schema) # do not migrate all attributes for attr in entry_attrs.keys(): if attr in attr_blacklist: del entry_attrs[attr] # do not migrate all object classes if 'objectclass' in entry_attrs: for object_class in kwargs.get('oc_blacklist', []): try: entry_attrs['objectclass'].remove(object_class) except ValueError: # object class not present pass return dn def _group_exc_callback(ldap, dn, entry_attrs, exc, options): assert isinstance(dn, DN) if isinstance(exc, errors.DuplicateEntry): if options.get('groupoverwritegid', False) and \ entry_attrs.get('gidnumber') is not None: try: new_entry_attrs = {'gidnumber':entry_attrs['gidnumber']} ldap.update_entry(dn, new_entry_attrs) except errors.EmptyModlist: # no change to the GID pass # mark as success return elif not options.get('groupoverwritegid', False) and \ entry_attrs.get('gidnumber') is not None: msg = unicode(exc) # add information about possibility to overwrite GID msg = msg + unicode(_('. Check GID of the existing group. ' \ 'Use --group-overwrite-gid option to overwrite the GID')) raise errors.DuplicateEntry(message=msg) raise exc # DS MIGRATION PLUGIN def construct_filter(template, oc_list): oc_subfilter = ''.join([ '(objectclass=%s)' % oc for oc in oc_list]) return template % oc_subfilter def validate_ldapuri(ugettext, ldapuri): m = re.match('^ldaps?://[-\w\.]+(:\d+)?$', ldapuri) if not m: err_msg = _('Invalid LDAP URI.') raise errors.ValidationError(name='ldap_uri', error=err_msg) class migrate_ds(Command): __doc__ = _('Migrate users and groups from DS to IPA.') migrate_objects = { # OBJECT_NAME: (search_filter, pre_callback, post_callback) # # OBJECT_NAME - is the name of an LDAPObject subclass # search_filter - is the filter to retrieve objects from DS # pre_callback - is called for each object just after it was # retrieved from DS and before being added to IPA # post_callback - is called for each object after it was added to IPA # exc_callback - is called when adding entry to IPA raises an exception # # {pre, post}_callback parameters: # ldap - ldap2 instance connected to IPA # pkey - primary key value of the object (uid for users, etc.) # dn - dn of the object as it (will be/is) stored in IPA # entry_attrs - attributes of the object # failed - a list of so-far failed objects # config - IPA config entry attributes # ctx - object context, used to pass data between callbacks # # If pre_callback return value evaluates to False, migration # of the current object is aborted. 'user': { 'filter_template' : '(&(|%s)(uid=*))', 'oc_option' : 'userobjectclass', 'oc_blacklist_option' : 'userignoreobjectclass', 'attr_blacklist_option' : 'userignoreattribute', 'pre_callback' : _pre_migrate_user, 'post_callback' : _post_migrate_user, 'exc_callback' : None }, 'group': { 'filter_template' : '(&(|%s)(cn=*))', 'oc_option' : 'groupobjectclass', 'oc_blacklist_option' : 'groupignoreobjectclass', 'attr_blacklist_option' : 'groupignoreattribute', 'pre_callback' : _pre_migrate_group, 'post_callback' : None, 'exc_callback' : _group_exc_callback, }, } migrate_order = ('user', 'group') takes_args = ( Str('ldapuri', validate_ldapuri, cli_name='ldap_uri', label=_('LDAP URI'), doc=_('LDAP URI of DS server to migrate from'), ), Password('bindpw', cli_name='password', label=_('Password'), confirm=False, doc=_('bind password'), ), ) takes_options = ( DNParam('binddn?', cli_name='bind_dn', label=_('Bind DN'), default=DN(('cn', 'directory manager')), autofill=True, ), DNParam('usercontainer', cli_name='user_container', label=_('User container'), doc=_('DN of container for users in DS relative to base DN'), default=DN(('ou', 'people')), autofill=True, ), DNParam('groupcontainer', cli_name='group_container', label=_('Group container'), doc=_('DN of container for groups in DS relative to base DN'), default=DN(('ou', 'groups')), autofill=True, ), Str('userobjectclass+', cli_name='user_objectclass', label=_('User object class'), doc=_('Objectclasses used to search for user entries in DS'), csv=True, default=(u'person',), autofill=True, ), Str('groupobjectclass+', cli_name='group_objectclass', label=_('Group object class'), doc=_('Objectclasses used to search for group entries in DS'), csv=True, default=(u'groupOfUniqueNames', u'groupOfNames'), autofill=True, ), Str('userignoreobjectclass*', cli_name='user_ignore_objectclass', label=_('Ignore user object class'), doc=_('Objectclasses to be ignored for user entries in DS'), csv=True, default=tuple(), autofill=True, ), Str('userignoreattribute*', cli_name='user_ignore_attribute', label=_('Ignore user attribute'), doc=_('Attributes to be ignored for user entries in DS'), csv=True, default=tuple(), autofill=True, ), Str('groupignoreobjectclass*', cli_name='group_ignore_objectclass', label=_('Ignore group object class'), doc=_('Objectclasses to be ignored for group entries in DS'), csv=True, default=tuple(), autofill=True, ), Str('groupignoreattribute*', cli_name='group_ignore_attribute', label=_('Ignore group attribute'), doc=_('Attributes to be ignored for group entries in DS'), csv=True, default=tuple(), autofill=True, ), Flag('groupoverwritegid', cli_name='group_overwrite_gid', label=_('Overwrite GID'), doc=_('When migrating a group already existing in IPA domain overwrite the '\ 'group GID and report as success'), ), StrEnum('schema?', cli_name='schema', label=_('LDAP schema'), doc=_('The schema used on the LDAP server. Supported values are RFC2307 and RFC2307bis. The default is RFC2307bis'), values=_supported_schemas, default=_supported_schemas[0], autofill=True, ), Flag('continue?', label=_('Continue'), doc=_('Continuous operation mode. Errors are reported but the process continues'), default=False, ), DNParam('basedn?', cli_name='base_dn', label=_('Base DN'), doc=_('Base DN on remote LDAP server'), ), Flag('compat?', cli_name='with_compat', label=_('Ignore compat plugin'), doc=_('Allows migration despite the usage of compat plugin'), default=False, ), ) has_output = ( output.Output('result', type=dict, doc=_('Lists of objects migrated; categorized by type.'), ), output.Output('failed', type=dict, doc=_('Lists of objects that could not be migrated; categorized by type.'), ), output.Output('enabled', type=bool, doc=_('False if migration mode was disabled.'), ), output.Output('compat', type=bool, doc=_('False if migration fails because the compatibility plug-in is enabled.'), ), ) exclude_doc = _('%s to exclude from migration') truncated_err_msg = _('''\ search results for objects to be migrated have been truncated by the server; migration process might be incomplete\n''') migration_disabled_msg = _('''\ Migration mode is disabled. Use \'ipa config-mod\' to enable it.''') pwd_migration_msg = _('''\ Passwords have been migrated in pre-hashed format. IPA is unable to generate Kerberos keys unless provided with clear text passwords. All migrated users need to login at https://your.domain/ipa/migration/ before they can use their Kerberos accounts.''') def get_options(self): """ Call get_options of the baseclass and add "exclude" options for each type of object being migrated. """ for option in super(migrate_ds, self).get_options(): yield option for ldap_obj_name in self.migrate_objects: ldap_obj = self.api.Object[ldap_obj_name] name = 'exclude_%ss' % to_cli(ldap_obj_name) doc = self.exclude_doc % ldap_obj.object_name_plural yield Str( '%s*' % name, cli_name=name, doc=doc, csv=True, default=tuple(), autofill=True ) def normalize_options(self, options): """ Convert all "exclude" option values to lower-case. Also, empty List parameters are converted to None, but the migration plugin doesn't like that - convert back to empty lists. """ for p in self.params(): if p.csv: if options[p.name]: options[p.name] = tuple( v.lower() for v in options[p.name] ) else: options[p.name] = tuple() def _get_search_bases(self, options, ds_base_dn, migrate_order): search_bases = dict() for ldap_obj_name in migrate_order: container = options.get('%scontainer' % to_cli(ldap_obj_name)) if container: # Don't append base dn if user already appended it in the container dn if container.endswith(ds_base_dn): search_base = container else: search_base = DN(container, ds_base_dn) else: search_base = ds_base_dn search_bases[ldap_obj_name] = search_base return search_bases def migrate(self, ldap, config, ds_ldap, ds_base_dn, options): """ Migrate objects from DS to LDAP. """ assert isinstance(ds_base_dn, DN) migrated = {} # {'OBJ': ['PKEY1', 'PKEY2', ...], ...} failed = {} # {'OBJ': {'PKEY1': 'Failed 'cos blabla', ...}, ...} search_bases = self._get_search_bases(options, ds_base_dn, self.migrate_order) migration_start = datetime.datetime.now() for ldap_obj_name in self.migrate_order: ldap_obj = self.api.Object[ldap_obj_name] template = self.migrate_objects[ldap_obj_name]['filter_template'] oc_list = options[to_cli(self.migrate_objects[ldap_obj_name]['oc_option'])] search_filter = construct_filter(template, oc_list) exclude = options['exclude_%ss' % to_cli(ldap_obj_name)] context = dict(ds_ldap = ds_ldap) migrated[ldap_obj_name] = [] failed[ldap_obj_name] = {} try: entries, truncated = ds_ldap.find_entries( search_filter, ['*'], search_bases[ldap_obj_name], ds_ldap.SCOPE_ONELEVEL, time_limit=0, size_limit=-1, search_refs=True # migrated DS may contain search references ) except errors.NotFound: if not options.get('continue',False): raise errors.NotFound( reason=_('%(container)s LDAP search did not return any result ' '(search base: %(search_base)s, ' 'objectclass: %(objectclass)s)') % {'container': ldap_obj_name, 'search_base': search_bases[ldap_obj_name], 'objectclass': ', '.join(oc_list)} ) else: truncated = False entries = [] if truncated: self.log.error( '%s: %s' % ( ldap_obj.name, self.truncated_err_msg ) ) blacklists = {} for blacklist in ('oc_blacklist', 'attr_blacklist'): blacklist_option = self.migrate_objects[ldap_obj_name][blacklist+'_option'] if blacklist_option is not None: blacklists[blacklist] = options.get(blacklist_option, tuple()) else: blacklists[blacklist] = tuple() # get default primary group for new users if 'def_group_dn' not in context: def_group = config.get('ipadefaultprimarygroup') context['def_group_dn'] = api.Object.group.get_dn(def_group) try: (g_dn, g_attrs) = ldap.get_entry(context['def_group_dn'], ['gidnumber', 'cn']) except errors.NotFound: error_msg = _('Default group for new users not found') raise errors.NotFound(reason=error_msg) if 'gidnumber' in g_attrs: context['def_group_gid'] = g_attrs['gidnumber'][0] context['has_upg'] = ldap.has_upg() valid_gids = [] invalid_gids = [] migrate_cnt = 0 context['migrate_cnt'] = 0 for (dn, entry_attrs) in entries: context['migrate_cnt'] = migrate_cnt s = datetime.datetime.now() if dn is None: # LDAP search reference failed[ldap_obj_name][entry_attrs[0]] = unicode(_ref_err_msg) continue try: dn = DN(dn) except ValueError: failed[ldap_obj_name][dn] = unicode(_dn_err_msg) continue ava = dn[0][0] if ava.attr == ldap_obj.primary_key.name: # In case if pkey attribute is in the migrated object DN # and the original LDAP is multivalued, make sure that # we pick the correct value (the unique one stored in DN) pkey = ava.value.lower() else: pkey = entry_attrs[ldap_obj.primary_key.name][0].lower() if pkey in exclude: continue dn = ldap_obj.get_dn(pkey) assert isinstance(dn, DN) entry_attrs['objectclass'] = list( set( config.get( ldap_obj.object_class_config, ldap_obj.object_class ) + [o.lower() for o in entry_attrs['objectclass']] ) ) entry_attrs[ldap_obj.primary_key.name][0] = entry_attrs[ldap_obj.primary_key.name][0].lower() callback = self.migrate_objects[ldap_obj_name]['pre_callback'] if callable(callback): try: dn = callback( ldap, pkey, dn, entry_attrs, failed[ldap_obj_name], config, context, schema = options['schema'], search_bases = search_bases, valid_gids = valid_gids, invalid_gids = invalid_gids, **blacklists ) assert isinstance(dn, DN) if not dn: continue except errors.NotFound, e: failed[ldap_obj_name][pkey] = unicode(e.reason) continue try: ldap.add_entry(dn, entry_attrs) except errors.ExecutionError, e: callback = self.migrate_objects[ldap_obj_name]['exc_callback'] if callable(callback): try: callback(ldap, dn, entry_attrs, e, options) except errors.ExecutionError, e: failed[ldap_obj_name][pkey] = unicode(e) continue else: failed[ldap_obj_name][pkey] = unicode(e) continue migrated[ldap_obj_name].append(pkey) callback = self.migrate_objects[ldap_obj_name]['post_callback'] if callable(callback): callback( ldap, pkey, dn, entry_attrs, failed[ldap_obj_name], config, context, ) e = datetime.datetime.now() d = e - s total_dur = e - migration_start migrate_cnt += 1 if migrate_cnt > 0 and migrate_cnt % 100 == 0: api.log.info("%d %ss migrated. %s elapsed." % (migrate_cnt, ldap_obj_name, total_dur)) api.log.debug("%d %ss migrated, duration: %s (total %s)" % (migrate_cnt, ldap_obj_name, d, total_dur)) _update_default_group(ldap, pkey, config, context, True) return (migrated, failed) def execute(self, ldapuri, bindpw, **options): ldap = self.api.Backend.ldap2 self.normalize_options(options) config = ldap.get_ipa_config()[1] ds_base_dn = options.get('basedn') if ds_base_dn is not None: assert isinstance(ds_base_dn, DN) # check if migration mode is enabled if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE': return dict(result={}, failed={}, enabled=False, compat=True) # connect to DS ds_ldap = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='') ds_ldap.connect(bind_dn=options['binddn'], bind_pw=bindpw) #check whether the compat plugin is enabled if not options.get('compat'): try: (dn,check_compat) = ldap.get_entry(_compat_dn) assert isinstance(dn, DN) if check_compat is not None and \ check_compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'on': return dict(result={}, failed={}, enabled=True, compat=False) except errors.NotFound: pass if not ds_base_dn: # retrieve base DN from remote LDAP server entries, truncated = ds_ldap.find_entries( '', ['namingcontexts', 'defaultnamingcontext'], DN(''), ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0, ) if 'defaultnamingcontext' in entries[0][1]: ds_base_dn = DN(entries[0][1]['defaultnamingcontext'][0]) assert isinstance(ds_base_dn, DN) else: try: ds_base_dn = DN(entries[0][1]['namingcontexts'][0]) assert isinstance(ds_base_dn, DN) except (IndexError, KeyError), e: raise StandardError(str(e)) # migrate! (migrated, failed) = self.migrate( ldap, config, ds_ldap, ds_base_dn, options ) return dict(result=migrated, failed=failed, enabled=True, compat=True) def output_for_cli(self, textui, result, ldapuri, bindpw, **options): textui.print_name(self.name) if not result['enabled']: textui.print_plain(self.migration_disabled_msg) return 1 if not result['compat']: textui.print_plain("The compat plug-in is enabled. This can increase the memory requirements during migration. Disable the compat plug-in with \'ipa-compat-manage disable\' or re-run this script with \'--with-compat\' option.") return 1 textui.print_plain('Migrated:') textui.print_entry1( result['result'], attr_order=self.migrate_order, one_value_per_line=False ) for ldap_obj_name in self.migrate_order: textui.print_plain('Failed %s:' % ldap_obj_name) textui.print_entry1( result['failed'][ldap_obj_name], attr_order=self.migrate_order, one_value_per_line=True, ) textui.print_plain('-' * len(self.name)) textui.print_plain(unicode(self.pwd_migration_msg)) api.register(migrate_ds) freeipa-3.3.4/ipalib/plugins/hostgroup.pyc0000664000175000017500000001767412271707517020222 0ustar mkosekmkosekó †fçRc@s€ddlTddlmZmZmZmZmZddlmZm Z ddl m Z edƒZ de fd„ƒYZejeƒdefd „ƒYZejeƒd efd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdS(iÿÿÿÿ(t*(tapitIntt_tngettextterrors(tNETGROUP_PATTERNtNETGROUP_PATTERN_ERRMSG(tDNsñ Groups of hosts. Manage groups of hosts. This is useful for applying access control to a number of hosts by using Host-based Access Control. EXAMPLES: Add a new host group: ipa hostgroup-add --desc="Baltimore hosts" baltimore Add another new host group: ipa hostgroup-add --desc="Maryland hosts" maryland Add members to the hostgroup (using Bash brace expansion): ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore Add a hostgroup as a member of another hostgroup: ipa hostgroup-add-member --hostgroups=baltimore maryland Remove a host from the hostgroup: ipa hostgroup-remove-member --hosts=box2 baltimore Display a host group: ipa hostgroup-show baltimore Delete a hostgroup: ipa hostgroup-del baltimore t hostgroupcBs/eZdZejjZedƒZedƒZ ddgZ ddddd d gZ d Z id d gd6d dddgd6d d gd 6d ddgd 6Z edƒZedƒZeddededddedƒdedƒdedd„ƒeddddedƒded ƒƒfZd!„ZRS("s Hostgroup object. s host groups host groupst ipaobjectt ipahostgrouptcnt descriptiontmembertmemberoftmemberindirecttmemberofindirectt ipauniqueidthostR tnetgroupthbacruletsudorules Host Groupss Host Grouptpatterntpattern_errmsgtcli_namethostgroup_nametlabels Host-grouptdocsName of host-groupt primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pytVstdesct Descriptions A description of this host-groupcCs·t|ƒ}x¤t|jdgƒƒD]Š}t|ƒ}|d|dkrQq%n|jidd6ƒ}y |j||j|dgƒWntjk rq%X|dj|ƒq%WdS(sh We don't want to show managed netgroups so remove them from the memberOf list. RR tmepmanagedentryt objectclasstN( Rtlisttgett make_filtert get_entriest SCOPE_BASERtNotFoundtremove(tselftldaptdnt entry_attrsthgdnRtngdntfilter((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pytsuppress_netgroup_memberof_s   (t__name__t __module__t__doc__Rtenvtcontainer_hostgroupt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributetattribute_membersRtlabel_singulartStrRRtTruet takes_paramsR5(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyR 8s8                t hostgroup_addcBs2eZedƒZedƒZd„Zd„ZRS(sAdd a new hostgroup.sAdded hostgroup "%(value)s"cOsµt|tƒst‚y,tjdj|dƒ|jj|ŒWntj k rWnXyBtjdj|dƒtj dt t dƒ|dƒƒ‚Wntj k r°nX|S(NR iÿÿÿÿRtmessageuYnetgroup with name "%s" already exists. Hostgroups and netgroups share a common namespace( t isinstanceRtAssertionErrorRtObjecttget_dn_if_existstobjthandle_duplicate_entryRR,tDuplicateEntrytunicodeR(R.R/R0R1t attrs_listtkeystoptions((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyt pre_callbackzscOsQt|tƒst‚t||ddƒ}t||ƒ|jj|||ƒ|S(NR%tmepOriginEntry(RHRRItwait_for_valuetentry_from_entryRLR5(R.R/R0R1RQRRtnewentry((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyt post_callbacks  (R6R7RR8t msg_summaryRSRX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRFus   t hostgroup_delcBs eZedƒZedƒZRS(sDelete a hostgroup.sDeleted hostgroup "%(value)s"(R6R7RR8RY(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRZžs t hostgroup_modcBs)eZedƒZedƒZd„ZRS(sModify a hostgroup.sModified hostgroup "%(value)s"cOs/t|tƒst‚|jj|||ƒ|S(N(RHRRIRLR5(R.R/R0R1RQRR((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRX«s(R6R7RR8RYRX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyR[¦s  thostgroup_findcBs;eZedƒZddgZedddƒZd„ZRS(sSearch for hostgroups.RRs%(count)d hostgroup matcheds%(count)d hostgroups matchedic OsM|jdtƒr|Sx0|D](}|\}}|jj|||ƒqW|S(Nt pkey_only(R(tFalseRLR5( R.R/tentriest truncatedtargsRRtentryR0R1((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRX»s   (R6R7RR8tmember_attributesRRYRX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyR\³s   thostgroup_showcBseZedƒZd„ZRS(s&Display information about a hostgroup.cOs/t|tƒst‚|jj|||ƒ|S(N(RHRRIRLR5(R.R/R0R1RQRR((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRXÉs(R6R7RR8RX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRdÆs thostgroup_add_membercBseZedƒZd„ZRS(sAdd members to a hostgroup.cOs5t|tƒst‚|jj|||ƒ||fS(N(RHRRIRLR5(R.R/t completedtfailedR0R1RQRR((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRXÔs(R6R7RR8RX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyReÑs thostgroup_remove_membercBseZedƒZd„ZRS(s Remove members from a hostgroup.cOs5t|tƒst‚|jj|||ƒ||fS(N(RHRRIRLR5(R.R/RfRgR0R1RQRR((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRXßs(R6R7RR8RX(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyRhÜs N(tipalib.plugins.baseldaptipalibRRRRRtipalib.plugins.netgroupRRt ipapython.dnRR8t LDAPObjectR tregistert LDAPCreateRFt LDAPDeleteRZt LDAPUpdateR[t LDAPSearchR\t LDAPRetrieveRdt LDAPAddMemberRetLDAPRemoveMemberRh(((s6/home/mkosek/freeipa-clean/ipalib/plugins/hostgroup.pyts* ( : &      freeipa-3.3.4/ipalib/plugins/pwpolicy.pyc0000664000175000017500000004277712271707517020040 0ustar mkosekmkosekó †fçRc@smddlmZddlmZmZmZddlTddlmZddlmZddl m Z ddl m Z ddl mZed ƒZd efd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdZe defdejjfd&ejj ƒZ!defd„ƒYZ"eje"ƒdefd„ƒYZ#eje#ƒdefd„ƒYZ$eje$ƒdefd „ƒYZ%eje%ƒd!efd"„ƒYZ&eje&ƒd#efd$„ƒYZ'eje'ƒd%S('iÿÿÿÿ(tapi(tInttStrtDNParam(t*(t_(tcontext(trun(tDN(tversions™ Password policy A password policy sets limitations on IPA passwords, including maximum lifetime, minimum lifetime, the number of passwords to save in history, the number of character classes required (for stronger passwords) and the minimum password length. By default there is a single, global policy for all users. You can also create a password policy to apply to a group. Each user is only subject to one password policy, either the group policy or the global policy. A group policy stands alone; it is not a super-set of the global policy plus custom settings. Each group password policy requires a unique priority setting. If a user is in multiple groups that have password policies, this priority determines which password policy is applied. A lower value indicates a higher priority policy. Group password policies are automatically removed when the groups they are associated with are removed. EXAMPLES: Modify the global policy: ipa pwpolicy-mod --minlength=10 Add a new group password policy: ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --minlength=8 --priority=10 localadmins Display the global password policy: ipa pwpolicy-show Display a group password policy: ipa pwpolicy-show localadmins Display the policy that would be applied to a given user: ipa pwpolicy-show --user=tuser1 Modify a group password policy: ipa pwpolicy-mod --minclasses=2 localadmins tcosentrycBs•eZdZeZedejjƒZ ddddgZ dddgZ e dd eƒe dƒedd d ƒfZed ƒZd „Zd„ZRS(sG Class of Service object used for linking policies with groups tcnt costemplatesttopt costemplatetextensibleobjectt krbcontainert cosprioritytkrbpwdpolicyreferencet primary_keytminvalueisDpriority must be a unique value (%(prio)d already used by %(gname)s)cOsD|jjjj|dƒ}|jjd|t|jtjj ƒƒS(NiÿÿÿÿR ( RtObjecttgrouptget_dntbackendtmake_dn_from_attrRt container_dntenvtbasedn(tselftkeystoptionstgroup_dn((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyR]s cOs©|jdƒdk r¥|jjd|dƒd}t|ƒdkr¥|jjjjt |dddƒƒ}t j ddd|j i|dd6|d 6ƒ‚q¥ndS( NRtresultiR tnametpriorityterrortpriotgname( tgettNonetmethodstfindtlenRRRtget_primary_key_from_dnRterrorstValidationErrortpriority_not_unique_msg(RRRtentriest group_name((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pytcheck_priority_uniquenesscs     (scnR (t__name__t __module__t__doc__tTruetNO_CLIRRRtcontainer_accountsRt object_classtdefault_attributesRRRt takes_paramsRR/RR2(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyR Is   t cosentry_addcBseZeZd„ZRS(c Os•t|tƒst‚|jjjj|dƒ}|j|dgƒ}td„|dƒ} d| krwt j ƒ‚n|j j ||Ž|d=|S(Niÿÿÿÿt objectclasscSs |jƒS(N(tlower(tx((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyt~stmepmanagedentryR ( t isinstanceRtAssertionErrorRRRRt get_entrytmapR-tManagedPolicyErrortobjR2( Rtldaptdnt entry_attrst attrs_listRRR R!toc((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyt pre_callbackys (R3R4R6R7RM(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyR<vst cosentry_delcBseZeZRS((R3R4R6R7(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyRNˆst cosentry_modcBseZeZd„ZRS(c OsŠt|tƒst‚|jdƒ}|dk r†|jjj|dƒd}t|ddƒ} | |kr†|j j ||Žq†n|S(NRiÿÿÿÿR!i( RBRRCR'R(RtCommandt cosentry_showtintRGR2( RRHRIRJRKRRtnew_cospriorityt cos_entrytold_cospriority((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyRM‘s  (R3R4R6R7RM(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyROŽsRQcBseZeZRS((R3R4R6R7(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyRQ st cosentry_findcBseZeZRS((R3R4R6R7(((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyRV¦st global_policyR tkerberostpwpolicycBs1eZdZedejjfdOƒZedƒZ edƒZ dddgZ ddd d d d d dddg Z dZ eZdPZeddgdeƒ\ZZZedkr÷ejƒdZejeƒZeje ƒZeekr÷eZq÷nereddddedƒdedƒddƒeddd ded!ƒded"ƒddƒed#dd$ded%ƒded&ƒddƒfZned'ƒZed(ƒZed)dd*ded+ƒded,ƒd-eƒed.dd/ded0ƒded1ƒddd2d3ƒed4dd5ded6ƒded7ƒddƒed8dd9ded:ƒded;ƒddƒed<dd=ded>ƒded?ƒddd2d@ƒedAddBdedCƒdedDƒddƒedddEdedFƒdedGƒdddHdQƒfeZ dJ„Z!dK„Z"dL„Z#edM„Z$edN„Z%RS(Rs Password Policy object R RXspassword policyspassword policiesR t nscontainert krbpwdpolicyRt krbmaxpwdlifet krbminpwdlifetkrbpwdhistorylengthtkrbpwdmindiffcharstkrbpwdminlengthtkrbpwdmaxfailuretkrbpwdfailurecountintervaltkrbpwdlockoutdurations1.8tklists-Vt raiseonerriiÿÿÿÿskrbpwdmaxfailure?tcli_nametmaxfailtlabels Max failurestdocs#Consecutive failures before lockoutRskrbpwdfailurecountinterval?t failintervalsFailure reset intervals8Period after which failure count will be reset (seconds)skrbpwdlockoutduration?t lockouttimesLockout durations.Period for which lockout is enforced (seconds)sPassword PoliciessPassword Policyscn?RtGroups)Manage password policy for specific groupRskrbmaxpwdlife?tmaxlifesMax lifetime (days)s#Maximum password lifetime (in days)tmaxvaluei Nskrbminpwdlife?tminlifesMin lifetime (hours)s$Minimum password lifetime (in hours)skrbpwdhistorylength?thistorys History sizesPassword history sizeskrbpwdmindiffchars?t minclassessCharacter classess#Minimum number of character classesiskrbpwdminlength?t minlengths Min lengthsMinimum length of passwordR#tPrioritys:Priority of the policy (higher number means lower prioritytflagstvirtual_attributecOsF|ddk rB|jj|jj|dt|jtjj ƒƒSt S(Niÿÿÿÿ( R(RRRR"RRRRRtglobal_policy_dn(RRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/pwpolicy.pyRs  cKsƒ|jdtƒsd|krGtt|ddƒdƒ|ddsF ) *      -¢   )  /freeipa-3.3.4/ipalib/plugins/trust.py0000664000175000017500000014624412271663206017176 0ustar mkosekmkosek# Authors: # Alexander Bokovoy # Martin Kosek # # Copyright (C) 2011 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 . from ipalib.plugins.baseldap import * from ipalib.plugins.dns import dns_container_exists from ipapython.ipautil import realm_to_suffix from ipalib import api, Str, StrEnum, Password, Bool, _, ngettext from ipalib import Command from ipalib import errors from ldap import SCOPE_SUBTREE from time import sleep try: import pysss_murmur #pylint: disable=F0401 _murmur_installed = True except Exception, e: _murmur_installed = False try: import pysss_nss_idmap #pylint: disable=F0401 _nss_idmap_installed = True except Exception, e: _nss_idmap_installed = False if api.env.in_server and api.env.context in ['lite', 'server']: try: import ipaserver.dcerpc #pylint: disable=F0401 _bindings_installed = True except ImportError: _bindings_installed = False __doc__ = _(""" Cross-realm trusts Manage trust relationship between IPA and Active Directory domains. In order to allow users from a remote domain to access resources in IPA domain, trust relationship needs to be established. Currently IPA supports only trusts between IPA and Active Directory domains under control of Windows Server 2008 or later, with functional level 2008 or later. Please note that DNS on both IPA and Active Directory domain sides should be configured properly to discover each other. Trust relationship relies on ability to discover special resources in the other domain via DNS records. Examples: 1. Establish cross-realm trust with Active Directory using AD administrator credentials: ipa trust-add --type=ad --admin --password 2. List all existing trust relationships: ipa trust-find 3. Show details of the specific trust relationship: ipa trust-show 4. Delete existing trust relationship: ipa trust-del Once trust relationship is established, remote users will need to be mapped to local POSIX groups in order to actually use IPA resources. The mapping should be done via use of external membership of non-POSIX group and then this group should be included into one of local POSIX groups. Example: 1. Create group for the trusted domain admins' mapping and their local POSIX group: ipa group-add --desc=' admins external map' ad_admins_external --external ipa group-add --desc=' admins' ad_admins 2. Add security identifier of Domain Admins of the to the ad_admins_external group: ipa group-add-member ad_admins_external --external 'AD\\Domain Admins' 3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group: ipa group-add-member ad_admins --groups ad_admins_external 4. List members of external members of ad_admins_external group to see their SIDs: ipa group-show ad_admins_external GLOBAL TRUST CONFIGURATION When IPA AD trust subpackage is installed and ipa-adtrust-install is run, a local domain configuration (SID, GUID, NetBIOS name) is generated. These identifiers are then used when communicating with a trusted domain of the particular type. 1. Show global trust configuration for Active Directory type of trusts: ipa trustconfig-show --type ad 2. Modify global configuration for all trusts of Active Directory type and set a different fallback primary group (fallback primary group GID is used as a primary user GID if user authenticating to IPA domain does not have any other primary GID already set): ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group" 3. Change primary fallback group back to default hidden group (any group with posixGroup object class is allowed): ipa trustconfig-mod --type ad --fallback-primary-group "Default SMB Group" """) trust_output_params = ( Str('trustdirection', label=_('Trust direction')), Str('trusttype', label=_('Trust type')), Str('truststatus', label=_('Trust status')), ) _trust_type_dict = {1 : _('Non-Active Directory domain'), 2 : _('Active Directory domain'), 3 : _('RFC4120-compliant Kerberos realm')} _trust_direction_dict = {1 : _('Trusting forest'), 2 : _('Trusted forest'), 3 : _('Two-way trust')} _trust_status_dict = {True : _('Established and verified'), False : _('Waiting for confirmation by remote side')} _trust_type_dict_unknown = _('Unknown') _trust_type_option = StrEnum('trust_type', cli_name='type', label=_('Trust type (ad for Active Directory, default)'), values=(u'ad',), default=u'ad', autofill=True, ) DEFAULT_RANGE_SIZE = 200000 def trust_type_string(level): """ Returns a string representing a type of the trust. The original field is an enum: LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001, LSA_TRUST_TYPE_UPLEVEL = 0x00000002, LSA_TRUST_TYPE_MIT = 0x00000003 """ string = _trust_type_dict.get(int(level), _trust_type_dict_unknown) return unicode(string) def trust_direction_string(level): """ Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use LSA_TRUST_DIRECTION_INBOUND = 0x00000001, LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002 """ string = _trust_direction_dict.get(int(level), _trust_type_dict_unknown) return unicode(string) def trust_status_string(level): string = _trust_status_dict.get(level, _trust_type_dict_unknown) return unicode(string) def make_trust_dn(env, trust_type, dn): assert isinstance(dn, DN) if trust_type: container_dn = DN(('cn', trust_type), env.container_trusts, env.basedn) return DN(dn, container_dn) return dn def add_range(self, range_name, dom_sid, *keys, **options): """ First, we try to derive the parameters of the ID range based on the information contained in the Active Directory. If that was not successful, we go for our usual defaults (random base, range size 200 000, ipa-ad-trust range type). Any of these can be overriden by passing appropriate CLI options to the trust-add command. """ range_size = None range_type = None base_id = None # First, get information about ID space from AD # However, we skip this step if other than ipa-ad-trust-posix # range type is enforced if options.get('range_type', None) in (None, u'ipa-ad-trust-posix'): # Get the base dn domain = keys[-1] basedn = realm_to_suffix(domain) # Search for information contained in # CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System info_filter = '(objectClass=msSFU30DomainInfo)' info_dn = DN('CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System')\ + basedn # Get the domain validator domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound( reason=_('Cannot search in trusted domains without own ' 'domain configured. Make sure you have run ' 'ipa-adtrust-install on the IPA server first')) # KDC might not get refreshed data at the first time, # retry several times for retry in range(10): info_list = domain_validator.search_in_dc(domain, info_filter, None, SCOPE_SUBTREE, basedn=info_dn, quiet=True) if info_list: info = info_list[0] break else: sleep(2) required_msSFU_attrs = ['msSFU30MaxUidNumber', 'msSFU30OrderNumber'] if not info_list: # We were unable to gain UNIX specific info from the AD self.log.debug("Unable to gain POSIX info from the AD") else: if all(attr in info for attr in required_msSFU_attrs): self.log.debug("Able to gain POSIX info from the AD") range_type = u'ipa-ad-trust-posix' max_uid = info.get('msSFU30MaxUidNumber') max_gid = info.get('msSFU30MaxGidNumber', None) max_id = int(max(max_uid, max_gid)[0]) base_id = int(info.get('msSFU30OrderNumber')[0]) range_size = (1 + (max_id - base_id) / DEFAULT_RANGE_SIZE)\ * DEFAULT_RANGE_SIZE # Second, options given via the CLI options take precedence to discovery if options.get('range_type', None): range_type = options.get('range_type', None) elif not range_type: range_type = u'ipa-ad-trust' if options.get('range_size', None): range_size = options.get('range_size', None) elif not range_size: range_size = DEFAULT_RANGE_SIZE if options.get('base_id', None): base_id = options.get('base_id', None) elif not base_id: # Generate random base_id if not discovered nor given via CLI base_id = DEFAULT_RANGE_SIZE + ( pysss_murmur.murmurhash3( dom_sid, len(dom_sid), 0xdeadbeefL ) % 10000 ) * DEFAULT_RANGE_SIZE # Finally, add new ID range self.api.Command['idrange_add'](range_name, ipabaseid=base_id, ipaidrangesize=range_size, ipabaserid=0, iparangetype=range_type, ipanttrusteddomainsid=dom_sid) # Return the values that were generated inside this function return range_type, range_size, base_id class trust(LDAPObject): """ Trust object. """ trust_types = ('ad', 'ipa') container_dn = api.env.container_trusts object_name = _('trust') object_name_plural = _('trusts') object_class = ['ipaNTTrustedDomain'] default_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', 'ipanttrusttype', 'ipanttrustattributes', 'ipanttrustdirection', 'ipanttrustpartner', 'ipantauthtrustoutgoing', 'ipanttrustauthincoming', 'ipanttrustforesttrustinfo', 'ipanttrustposixoffset', 'ipantsupportedencryptiontypes' ] search_display_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', 'ipanttrusttype', 'ipantsidblacklistincoming', 'ipantsidblacklistoutgoing' ] label = _('Trusts') label_singular = _('Trust') takes_params = ( Str('cn', cli_name='realm', label=_('Realm name'), primary_key=True, ), Str('ipantflatname', cli_name='flat_name', label=_('Domain NetBIOS name'), flags=['no_create', 'no_update']), Str('ipanttrusteddomainsid', cli_name='sid', label=_('Domain Security Identifier'), flags=['no_create', 'no_update']), Str('ipantsidblacklistincoming*', csv=True, cli_name='sid_blacklist_incoming', label=_('SID blacklist incoming'), flags=['no_create']), Str('ipantsidblacklistoutgoing*', csv=True, cli_name='sid_blacklist_outgoing', label=_('SID blacklist outgoing'), flags=['no_create']), ) def validate_sid_blacklists(self, entry_attrs): if not _bindings_installed: # SID validator is not available, return # Even if invalid SID gets in the trust entry, it won't crash # the validation process as it is translated to SID S-0-0 return for attr in ('ipantsidblacklistincoming', 'ipantsidblacklistoutgoing'): values = entry_attrs.get(attr) if not values: continue for value in values: if not ipaserver.dcerpc.is_sid_valid(value): raise errors.ValidationError(name=attr, error=_("invalid SID: %(value)s") % dict(value=value)) def get_dn(self, *keys, **kwargs): sdn = map(lambda x: ('cn', x), keys) sdn.reverse() trust_type = kwargs.get('trust_type') if trust_type is None: ldap = self.backend filter = ldap.make_filter({'objectclass': ['ipaNTTrustedDomain'], 'cn': [keys[-1]] }, rules=ldap.MATCH_ALL) filter = ldap.combine_filters((filter, "ipaNTSIDBlacklistIncoming=*"), rules=ldap.MATCH_ALL) result = ldap.get_entries(DN(self.container_dn, self.env.basedn), ldap.SCOPE_SUBTREE, filter, ['']) if len(result) > 1: raise errors.OnlyOneValueAllowed(attr='trust domain') return result[0].dn dn=make_trust_dn(self.env, trust_type, DN(*sdn)) return dn class trust_add(LDAPCreate): __doc__ = _(''' Add new trust to use. This command establishes trust relationship to another domain which becomes 'trusted'. As result, users of the trusted domain may access resources of this domain. Only trusts to Active Directory domains are supported right now. The command can be safely run multiple times against the same domain, this will cause change to trust relationship credentials on both sides. ''') range_types = { u'ipa-ad-trust': unicode(_('Active Directory domain range')), u'ipa-ad-trust-posix': unicode(_('Active Directory trust range with ' 'POSIX attributes')), } takes_options = LDAPCreate.takes_options + ( _trust_type_option, Str('realm_admin?', cli_name='admin', label=_("Active Directory domain administrator"), ), Password('realm_passwd?', cli_name='password', label=_("Active directory domain administrator's password"), confirm=False, ), Str('realm_server?', cli_name='server', label=_('Domain controller for the Active Directory domain (optional)'), ), Password('trust_secret?', cli_name='trust_secret', label=_('Shared secret for the trust'), confirm=False, ), Int('base_id?', cli_name='base_id', label=_('First Posix ID of the range reserved for the trusted domain'), ), Int('range_size?', cli_name='range_size', label=_('Size of the ID range reserved for the trusted domain'), ), StrEnum('range_type?', label=_('Range type'), cli_name='range_type', doc=(_('Type of trusted domain ID range, one of {vals}' .format(vals=', '.join(range_types.keys())))), values=tuple(range_types.keys()), ), ) msg_summary = _('Added Active Directory trust for realm "%(value)s"') has_output_params = LDAPCreate.has_output_params + trust_output_params def execute(self, *keys, **options): full_join = self.validate_options(*keys, **options) old_range, range_name, dom_sid = self.validate_range(*keys, **options) result = self.execute_ad(full_join, *keys, **options) if not old_range: # Store the created range type, since for POSIX trusts no # ranges for the subdomains should be added, POSIX attributes # provide a global mapping across all subdomains (created_range_type, _, _) = add_range(self, range_name, dom_sid, *keys, **options) else: created_range_type = old_range['result']['iparangetype'][0] trust_filter = "cn=%s" % result['value'] ldap = self.obj.backend (trusts, truncated) = ldap.find_entries( base_dn=DN(api.env.container_trusts, api.env.basedn), filter=trust_filter) result['result'] = entry_to_dict(trusts[0][1], **options) # For AD trusts with algorithmic mapping, we need to add a separate # range for each subdomain. if (options.get('trust_type') == u'ad' and created_range_type != u'ipa-ad-trust-posix'): domains = fetch_domains_from_trust(self, self.trustinstance, result['result'], **options) if domains and len(domains) > 0: for dom in domains: range_name = dom['cn'][0].upper() + '_id_range' dom_sid = dom['ipanttrusteddomainsid'][0] # Enforce the same range type as the range for the root # level domain. # This will skip the detection of the POSIX attributes if # they are not available, since it has been already # detected when creating the range for the root level domain passed_options = options passed_options.update(range_type=created_range_type) # Do not pass the base id to the subdomains since it would # clash with the root level domain if 'base_id' in passed_options: del passed_options['base_id'] # Try to add the range for each subdomain try: add_range(self, range_name, dom_sid, *keys, **passed_options) except errors.DuplicateEntry: pass # Format the output into human-readable values result['result']['trusttype'] = [trust_type_string( result['result']['ipanttrusttype'][0])] result['result']['trustdirection'] = [trust_direction_string( result['result']['ipanttrustdirection'][0])] result['result']['truststatus'] = [trust_status_string( result['verified'])] del result['verified'] return result def validate_options(self, *keys, **options): if not _bindings_installed: raise errors.NotFound( name=_('AD Trust setup'), reason=_( 'Cannot perform join operation without Samba 4 support ' 'installed. Make sure you have installed server-trust-ad ' 'sub-package of IPA' ) ) if not _murmur_installed and 'base_id' not in options: raise errors.ValidationError( name=_('missing base_id'), error=_( 'pysss_murmur is not available on the server ' 'and no base-id is given.' ) ) if 'trust_type' not in options: raise errors.RequirementError(name=_('trust type')) if options['trust_type'] != u'ad': raise errors.ValidationError( name=_('trust type'), error=_('only "ad" is supported') ) # If domain name and realm does not match, IPA server is not be able # to establish trust with Active Directory. realm_not_matching_domain = (api.env.domain.upper() != api.env.realm) if options['trust_type'] == u'ad' and realm_not_matching_domain: raise errors.ValidationError( name=_('Realm-domain mismatch'), error=_('To establish trust with Active Directory, the ' 'domain name and the realm name of the IPA server ' 'must match') ) self.trustinstance = ipaserver.dcerpc.TrustDomainJoins(self.api) if not self.trustinstance.configured: raise errors.NotFound( name=_('AD Trust setup'), reason=_( 'Cannot perform join operation without own domain ' 'configured. Make sure you have run ipa-adtrust-install ' 'on the IPA server first' ) ) self.realm_server = options.get('realm_server') self.realm_admin = options.get('realm_admin') self.realm_passwd = options.get('realm_passwd') if self.realm_admin: names = self.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' ) ) self.realm_admin = names[0] if not self.realm_passwd: raise errors.ValidationError( name=_('AD Trust setup'), error=_('Realm administrator password should be specified') ) return True return False def validate_range(self, *keys, **options): # If a range for this trusted domain already exists, # '--base-id' or '--range-size' options should not be specified range_name = keys[-1].upper() + '_id_range' range_type = options.get('range_type') try: old_range = api.Command['idrange_show'](range_name, raw=True) except errors.NotFound: old_range = None if options.get('trust_type') == u'ad': if range_type and range_type not in (u'ipa-ad-trust', u'ipa-ad-trust-posix'): raise errors.ValidationError( name=_('id range type'), error=_( 'Only the ipa-ad-trust and ipa-ad-trust-posix are ' 'allowed values for --range-type when adding an AD ' 'trust.' )) base_id = options.get('base_id') range_size = options.get('range_size') if old_range and (base_id or range_size): raise errors.ValidationError( name=_('id range'), error=_( 'An id range already exists for this trust. ' 'You should either delete the old range, or ' 'exclude --base-id/--range-size options from the command.' ) ) # If a range for this trusted domain already exists, # domain SID must also match self.trustinstance.populate_remote_domain( keys[-1], self.realm_server, self.realm_admin, self.realm_passwd ) dom_sid = self.trustinstance.remote_domain.info['sid'] if old_range: old_dom_sid = old_range['result']['ipanttrusteddomainsid'][0] old_range_type = old_range['result']['iparangetype'][0] if old_dom_sid != dom_sid: raise errors.ValidationError( name=_('range exists'), error=_( 'ID range with the same name but different domain SID ' 'already exists. The ID range for the new trusted ' 'domain must be created manually.' ) ) if range_type and range_type != old_range_type: raise errors.ValidationError(name=_('range type change'), error=_('ID range for the trusted domain already exists, ' 'but it has a different type. Please remove the ' 'old range manually, or do not enforce type ' 'via --range-type option.')) return old_range, range_name, dom_sid def execute_ad(self, full_join, *keys, **options): # Join domain using full credentials and with random trustdom # secret (will be generated by the join method) # First see if the trust is already in place # Force retrieval of the trust object by not passing trust_type try: dn = self.obj.get_dn(keys[-1]) except errors.NotFound: dn = None if dn: summary = _('Re-established trust to domain "%(value)s"') else: summary = self.msg_summary # 1. Full access to the remote domain. Use admin credentials and # generate random trustdom password to do work on both sides if full_join: try: result = self.trustinstance.join_ad_full_credentials( keys[-1], self.realm_server, self.realm_admin, self.realm_passwd ) except errors.NotFound: error_message=_("Unable to resolve domain controller for '%s' domain. ") % (keys[-1]) instructions=[] if dns_container_exists(self.obj.backend): try: dns_zone = api.Command.dnszone_show(keys[-1])['result'] if ('idnsforwardpolicy' in dns_zone) and dns_zone['idnsforwardpolicy'][0] == u'only': instructions.append(_("Forward policy is defined for it in IPA DNS, " "perhaps forwarder points to incorrect host?")) except (errors.NotFound, KeyError) as e: instructions.append(_("IPA manages DNS, please verify " "your DNS configuration and " "make sure that service records " "of the '%(domain)s' domain can " "be resolved. Examples how to " "configure DNS with CLI commands " "or the Web UI can be found in " "the documentation. " ) % dict(domain=keys[-1])) else: instructions.append(_("Since IPA does not manage DNS records, ensure DNS " "is configured to resolve '%(domain)s' domain from " "IPA hosts and back.") % dict(domain=keys[-1])) raise errors.NotFound(reason=error_message, instructions=instructions) if result is None: raise errors.ValidationError(name=_('AD Trust setup'), error=_('Unable to verify write permissions to the AD')) ret = dict( value=self.trustinstance.remote_domain.info['dns_domain'], verified=result['verified'] ) ret['summary'] = summary % ret return ret # 2. We don't have access to the remote domain and trustdom password # is provided. Do the work on our side and inform what to do on remote # side. if 'trust_secret' in options: result = self.trustinstance.join_ad_ipa_half( keys[-1], self.realm_server, options['trust_secret'] ) ret = dict( value=self.trustinstance.remote_domain.info['dns_domain'], verified=result['verified'] ) ret['summary'] = summary % ret return ret raise errors.ValidationError(name=_('AD Trust setup'), error=_('Not enough arguments specified to perform trust setup')) class trust_del(LDAPDelete): __doc__ = _('Delete a trust.') msg_summary = _('Deleted trust "%(value)s"') class trust_mod(LDAPUpdate): __doc__ = _(""" Modify a trust (for future use). Currently only the default option to modify the LDAP attributes is available. More specific options will be added in coming releases. """) msg_summary = _('Modified trust "%(value)s" ' '(change will be effective in 60 seconds)') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.validate_sid_blacklists(entry_attrs) return dn class trust_find(LDAPSearch): __doc__ = _('Search for trusts.') has_output_params = LDAPSearch.has_output_params + trust_output_params +\ (Str('ipanttrusttype'),) msg_summary = ngettext( '%(count)d trust matched', '%(count)d trusts matched', 0 ) # Since all trusts types are stored within separate containers under 'cn=trusts', # search needs to be done on a sub-tree scope def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): # list only trust, not trust domains trust_filter = '(ipaNTSIDBlacklistIncoming=*)' filter = ldap.combine_filters((filters, trust_filter), rules=ldap.MATCH_ALL) return (filter, base_dn, ldap.SCOPE_SUBTREE) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, attrs) = entry # Translate ipanttrusttype to trusttype if --raw not used if not options.get('raw', False): attrs['trusttype'] = trust_type_string(attrs['ipanttrusttype'][0]) del attrs['ipanttrusttype'] return truncated class trust_show(LDAPRetrieve): __doc__ = _('Display information about a trust.') has_output_params = LDAPRetrieve.has_output_params + trust_output_params +\ (Str('ipanttrusttype'), Str('ipanttrustdirection')) def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # Translate ipanttrusttype to trusttype # and ipanttrustdirection to trustdirection # if --raw not used if not options.get('raw', False): type_str = trust_type_string(entry_attrs['ipanttrusttype'][0]) dir_str = trust_direction_string(entry_attrs['ipanttrustdirection'] [0]) entry_attrs['trusttype'] = [type_str] entry_attrs['trustdirection'] = [dir_str] del entry_attrs['ipanttrusttype'] del entry_attrs['ipanttrustdirection'] return dn api.register(trust) api.register(trust_add) api.register(trust_mod) api.register(trust_del) api.register(trust_find) api.register(trust_show) _trustconfig_dn = { u'ad': DN(('cn', api.env.domain), api.env.container_cifsdomains, api.env.basedn), } class trustconfig(LDAPObject): """ Trusts global configuration object """ object_name = _('trust configuration') default_attributes = [ 'cn', 'ipantsecurityidentifier', 'ipantflatname', 'ipantdomainguid', 'ipantfallbackprimarygroup', ] label = _('Global Trust Configuration') label_singular = _('Global Trust Configuration') takes_params = ( Str('cn', label=_('Domain'), flags=['no_update'], ), Str('ipantsecurityidentifier', label=_('Security Identifier'), flags=['no_update'], ), Str('ipantflatname', label=_('NetBIOS name'), flags=['no_update'], ), Str('ipantdomainguid', label=_('Domain GUID'), flags=['no_update'], ), Str('ipantfallbackprimarygroup', cli_name='fallback_primary_group', label=_('Fallback primary group'), ), ) def get_dn(self, *keys, **kwargs): trust_type = kwargs.get('trust_type') if trust_type is None: raise errors.RequirementError(name='trust_type') try: return _trustconfig_dn[kwargs['trust_type']] except KeyError: raise errors.ValidationError(name='trust_type', error=_("unsupported trust type")) def _normalize_groupdn(self, entry_attrs): """ Checks that group with given name/DN exists and updates the entry_attrs """ if 'ipantfallbackprimarygroup' not in entry_attrs: return group = entry_attrs['ipantfallbackprimarygroup'] if isinstance(group, (list, tuple)): group = group[0] if group is None: return try: dn = DN(group) # group is in a form of a DN try: self.backend.get_entry(dn) except errors.NotFound: self.api.Object['group'].handle_not_found(group) # DN is valid, we can just return return except ValueError: # The search is performed for groups with "posixgroup" objectclass # and not "ipausergroup" so that it can also match groups like # "Default SMB Group" which does not have this objectclass. try: (dn, group_entry) = self.backend.find_entry_by_attr( self.api.Object['group'].primary_key.name, group, ['posixgroup'], [''], DN(api.env.container_group, api.env.basedn)) except errors.NotFound: self.api.Object['group'].handle_not_found(group) else: entry_attrs['ipantfallbackprimarygroup'] = [dn] def _convert_groupdn(self, entry_attrs, options): """ Convert an group dn into a name. As we use CN as user RDN, its value can be extracted from the DN without further LDAP queries. """ if options.get('raw', False): return try: groupdn = entry_attrs['ipantfallbackprimarygroup'][0] except (IndexError, KeyError): groupdn = None if groupdn is None: return assert isinstance(groupdn, DN) entry_attrs['ipantfallbackprimarygroup'] = [groupdn[0][0].value] api.register(trustconfig) class trustconfig_mod(LDAPUpdate): __doc__ = _('Modify global trust configuration.') takes_options = LDAPUpdate.takes_options + (_trust_type_option,) msg_summary = _('Modified "%(value)s" trust configuration') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): self.obj._normalize_groupdn(entry_attrs) return dn def execute(self, *keys, **options): result = super(trustconfig_mod, self).execute(*keys, **options) result['value'] = options['trust_type'] return result def post_callback(self, ldap, dn, entry_attrs, *keys, **options): self.obj._convert_groupdn(entry_attrs, options) return dn api.register(trustconfig_mod) class trustconfig_show(LDAPRetrieve): __doc__ = _('Show global trust configuration.') takes_options = LDAPRetrieve.takes_options + (_trust_type_option,) def execute(self, *keys, **options): result = super(trustconfig_show, self).execute(*keys, **options) result['value'] = options['trust_type'] return result def post_callback(self, ldap, dn, entry_attrs, *keys, **options): self.obj._convert_groupdn(entry_attrs, options) return dn api.register(trustconfig_show) if _nss_idmap_installed: _idmap_type_dict = { pysss_nss_idmap.ID_USER : 'user', pysss_nss_idmap.ID_GROUP : 'group', pysss_nss_idmap.ID_BOTH : 'both', } def idmap_type_string(level): string = _idmap_type_dict.get(int(level), 'unknown') return unicode(string) class trust_resolve(Command): NO_CLI = True __doc__ = _('Resolve security identifiers of users and groups in trusted domains') takes_options = ( Str('sids+', label = _('Security Identifiers (SIDs)'), csv = True, ), ) has_output_params = ( Str('name', label= _('Name')), Str('sid', label= _('SID')), ) has_output = ( output.ListOfEntries('result'), ) def execute(self, *keys, **options): result = list() if not _nss_idmap_installed: return dict(result=result) try: sids = map(lambda x: str(x), options['sids']) xlate = pysss_nss_idmap.getnamebysid(sids) for sid in xlate: entry = dict() entry['sid'] = [unicode(sid)] entry['name'] = [unicode(xlate[sid][pysss_nss_idmap.NAME_KEY])] entry['type'] = [idmap_type_string(xlate[sid][pysss_nss_idmap.TYPE_KEY])] result.append(entry) except ValueError, e: pass return dict(result=result) api.register(trust_resolve) class adtrust_is_enabled(Command): NO_CLI = True __doc__ = _('Determine whether ipa-adtrust-install has been run on this ' 'system') def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 adtrust_dn = DN( ('cn', 'ADTRUST'), ('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn ) try: ldap.get_entry(adtrust_dn) except errors.NotFound: return dict(result=False) return dict(result=True) api.register(adtrust_is_enabled) class compat_is_enabled(Command): NO_CLI = True __doc__ = _('Determine whether Schema Compatibility plugin is configured ' 'to serve trusted domain users and groups') def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 users_dn = DN( ('cn', 'users'), ('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config') ) groups_dn = DN( ('cn', 'groups'), ('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config') ) try: users_entry = ldap.get_entry(users_dn) except errors.NotFound: return dict(result=False) attr = users_entry.get('schema-compat-lookup-nsswitch') if not attr or 'user' not in attr: return dict(result=False) try: groups_entry = ldap.get_entry(groups_dn) except errors.NotFound: return dict(result=False) attr = groups_entry.get('schema-compat-lookup-nsswitch') if not attr or 'group' not in attr: return dict(result=False) return dict(result=True) api.register(compat_is_enabled) class sidgen_was_run(Command): """ This command tries to determine whether the sidgen task was run during ipa-adtrust-install. It does that by simply checking the "editors" group for the presence of the ipaNTSecurityIdentifier attribute - if the attribute is present, the sidgen task was run. Since this command relies on the existence of the "editors" group, it will fail loudly in case this group does not exist. """ NO_CLI = True __doc__ = _('Determine whether ipa-adtrust-install has been run with ' 'sidgen task') def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 editors_dn = DN( ('cn', 'editors'), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn ) try: editors_entry = ldap.get_entry(editors_dn) except errors.NotFound: raise errors.NotFound( name=_('sidgen_was_run'), reason=_( 'This command relies on the existence of the "editors" ' 'group, but this group was not found.' ) ) attr = editors_entry.get('ipaNTSecurityIdentifier') if not attr: return dict(result=False) return dict(result=True) api.register(sidgen_was_run) class trustdomain(LDAPObject): """ Object representing a domain of the AD trust. """ parent_object = 'trust' trust_type_idx = {'2':u'ad'} object_name = _('trust domain') object_name_plural = _('trust domains') object_class = ['ipaNTTrustedDomain'] default_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', 'ipanttrustpartner'] search_display_attributes = ['cn', 'ipantflatname', 'ipanttrusteddomainsid', ] label = _('Trusted domains') label_singular = _('Trusted domain') takes_params = ( Str('cn', label=_('Domain name'), cli_name='domain', primary_key=True ), Str('ipantflatname?', cli_name='flat_name', label=_('Domain NetBIOS name'), ), Str('ipanttrusteddomainsid?', cli_name='sid', label=_('Domain Security Identifier'), ), Str('ipanttrustpartner?', label=_('Trusted domain partner'), flags=['no_display', 'no_option'], ), ) # LDAPObject.get_dn() only passes all but last element of keys and no kwargs # to the parent object's get_dn() no matter what you pass to it. Make own get_dn() # as we really need all elements to construct proper dn. def get_dn(self, *keys, **kwargs): sdn = map(lambda x: ('cn', x), keys) sdn.reverse() trust_type = kwargs.get('trust_type') if not trust_type: trust_type=u'ad' dn=make_trust_dn(self.env, trust_type, DN(*sdn)) return dn api.register(trustdomain) class trustdomain_find(LDAPSearch): __doc__ = _('Search domains of the trust') has_output_params = LDAPSearch.has_output_params + ( Flag('domain_enabled', label= _('Domain enabled')), ) def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): return (filters, base_dn, ldap.SCOPE_SUBTREE) def post_callback(self, ldap, entries, truncated, *args, **options): trust_dn = self.obj.get_dn(args[0], trust_type=u'ad') trust_entry = ldap.get_entry(trust_dn) for entry in entries: sid = entry['ipanttrusteddomainsid'][0] if sid in trust_entry['ipantsidblacklistincoming']: entry['domain_enabled'] = [False] else: entry['domain_enabled'] = [True] return truncated api.register(trustdomain_find) class trustdomain_mod(LDAPUpdate): __doc__ = _('Modify trustdomain of the trust') NO_CLI = True takes_options = LDAPUpdate.takes_options + (_trust_type_option,) api.register(trustdomain_mod) class trustdomain_add(LDAPCreate): __doc__ = _('Allow access from the trusted domain') NO_CLI = True takes_options = LDAPCreate.takes_options + (_trust_type_option,) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): if 'ipanttrustpartner' in options: entry_attrs['ipanttrustpartner'] = [options['ipanttrustpartner']] return dn api.register(trustdomain_add) class trustdomain_del(LDAPDelete): __doc__ = _('Remove infromation about the domain associated with the trust.') msg_summary = _('Removed information about the trusted domain "%(value)s"') def execute(self, *keys, **options): # Note that pre-/post- callback handling for LDAPDelete is causing pre_callback # to always receive empty keys. We need to catch the case when root domain is being deleted for domain in keys[1]: if keys[0].lower() == domain: raise errors.ValidationError(name='domain', error=_("cannot delete root domain of the trust, use trust-del to delete the trust itself")) try: res = api.Command.trustdomain_enable(keys[0], domain) except errors.AlreadyActive: pass result = super(trustdomain_del, self).execute(*keys, **options) result['value'] = u','.join(keys[1]) return result api.register(trustdomain_del) def fetch_domains_from_trust(self, trustinstance, trust_entry, **options): trust_name = trust_entry['cn'][0] creds = None password = options.get('realm_passwd', None) if password: admin_name = options.get('realm_admin') sp = admin_name.split('\\') if len(sp) == 1: sp.insert(0, trustinstance.remote_domain.info['name']) creds = u"{name}%{password}".format(name="\\".join(sp), password=password) domains = ipaserver.dcerpc.fetch_domains(self.api, trustinstance.local_flatname, trust_name, creds=creds) result = [] if not domains: return result # trust range must exist by the time fetch_domains_from_trust is called range_name = trust_name.upper() + '_id_range' old_range = api.Command.idrange_show(range_name, raw=True)['result'] idrange_type = old_range['iparangetype'] for dom in domains: dom['trust_type'] = u'ad' try: name = dom['cn'] del dom['cn'] if 'all' in options: dom['all'] = options['all'] if 'raw' in options: dom['raw'] = options['raw'] res = self.api.Command.trustdomain_add(trust_name, name, **dom) result.append(res['result']) if idrange_type != u'ipa-ad-trust-posix': range_name = name.upper() + '_id_range' dom['range_type'] = u'ipa-ad-trust' add_range(self, range_name, dom['ipanttrusteddomainsid'], trust_name, name, **dom) except errors.DuplicateEntry: # Ignore updating duplicate entries pass return result class trust_fetch_domains(LDAPRetrieve): __doc__ = _('Refresh list of the domains associated with the trust') has_output = output.standard_list_of_entries def execute(self, *keys, **options): if not _bindings_installed: raise errors.NotFound( name=_('AD Trust setup'), reason=_( 'Cannot perform join operation without Samba 4 support ' 'installed. Make sure you have installed server-trust-ad ' 'sub-package of IPA' ) ) trust = self.api.Command.trust_show(keys[0], raw=True)['result'] trustinstance = ipaserver.dcerpc.TrustDomainJoins(self.api) if not trustinstance.configured: raise errors.NotFound( name=_('AD Trust setup'), reason=_( 'Cannot perform join operation without own domain ' 'configured. Make sure you have run ipa-adtrust-install ' 'on the IPA server first' ) ) domains = fetch_domains_from_trust(self, trustinstance, trust) result = dict() if len(domains) > 0: result['summary'] = unicode(_('List of trust domains successfully refreshed')) else: result['summary'] = unicode(_('No new trust domains were found')) result['result'] = domains result['count'] = len(domains) result['truncated'] = False return result api.register(trust_fetch_domains) class trustdomain_enable(LDAPQuery): __doc__ = _('Allow use of IPA resources by the domain of the trust') has_output = output.standard_value msg_summary = _('Enabled trust domain "%(value)s"') def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 if keys[0].lower() == keys[1].lower(): raise errors.ValidationError(name='domain', error=_("Root domain of the trust is always enabled for the existing trust")) try: trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad') trust_entry = ldap.get_entry(trust_dn) except errors.NotFound: self.api.Object[self.obj.parent_object].handle_not_found(keys[0]) dn = self.obj.get_dn(keys[0], keys[1], trust_type=u'ad') try: entry = ldap.get_entry(dn) sid = entry['ipanttrusteddomainsid'][0] if sid in trust_entry['ipantsidblacklistincoming']: trust_entry['ipantsidblacklistincoming'].remove(sid) ldap.update_entry(trust_entry) # Force MS-PAC cache re-initialization on KDC side domval = ipaserver.dcerpc.DomainValidator(api) (ccache_name, principal) = domval.kinit_as_http(keys[0]) else: raise errors.AlreadyActive() except errors.NotFound: self.obj.handle_not_found(*keys) return dict( result=True, value=keys[1], ) api.register(trustdomain_enable) class trustdomain_disable(LDAPQuery): __doc__ = _('Disable use of IPA resources by the domain of the trust') has_output = output.standard_value msg_summary = _('Disabled trust domain "%(value)s"') def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 if keys[0].lower() == keys[1].lower(): raise errors.ValidationError(name='domain', error=_("cannot disable root domain of the trust, use trust-del to delete the trust itself")) try: trust_dn = self.obj.get_dn(keys[0], trust_type=u'ad') trust_entry = ldap.get_entry(trust_dn) except errors.NotFound: self.api.Object[self.obj.parent_object].handle_not_found(keys[0]) dn = self.obj.get_dn(keys[0], keys[1], trust_type=u'ad') try: entry = ldap.get_entry(dn) sid = entry['ipanttrusteddomainsid'][0] if not (sid in trust_entry['ipantsidblacklistincoming']): trust_entry['ipantsidblacklistincoming'].append(sid) ldap.update_entry(trust_entry) # Force MS-PAC cache re-initialization on KDC side domval = ipaserver.dcerpc.DomainValidator(api) (ccache_name, principal) = domval.kinit_as_http(keys[0]) else: raise errors.AlreadyInactive() except errors.NotFound: self.obj.handle_not_found(*keys) return dict( result=True, value=keys[1], ) api.register(trustdomain_disable) freeipa-3.3.4/ipalib/plugins/hbacsvcgroup.pyc0000664000175000017500000001071012271707517020636 0ustar mkosekmkosekó †fçRc@spddlmZmZddlTddlmZmZedƒZdedƒfZdefd„ƒYZ ej e ƒd e fd „ƒYZ ej e ƒd e fd „ƒYZej eƒd efd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdS(iÿÿÿÿ(tapiterrors(t*(t_tngettextsã HBAC Service Groups HBAC service groups can contain any number of individual services, or "members". Every group must have a description. EXAMPLES: Add a new HBAC service group: ipa hbacsvcgroup-add --desc="login services" login Add members to an HBAC service group: ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login Display information about a named group: ipa hbacsvcgroup-show login Delete an HBAC service group: ipa hbacsvcgroup-del login thbacs"Host based access control commandst hbacsvcgroupc BsÒeZdZejjZedƒZedƒZ ddgZ dddgZ dZ id gd6Z ed ƒZed ƒZedd d dedƒdedd„ƒedd ddedƒdedƒƒfZRS(s$ HBAC service group object. sHBAC service groupsHBAC service groupst ipaobjecttipahbacservicegrouptcnt descriptiontmembert ipauniqueidthbacsvcsHBAC Service GroupssHBAC Service Grouptcli_nametnametlabelsService group namet primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pytEstdesct DescriptiontdocsHBAC service group description(t__name__t __module__t__doc__Rtenvtcontainer_hbacservicegroupt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributetattribute_membersRtlabel_singulartStrtTruet takes_params(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR/s(            thbacsvcgroup_addcBs eZedƒZedƒZRS(sAdd a new HBAC service group.s$Added HBAC service group "%(value)s"(RRRRt msg_summary(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR)Qs thbacsvcgroup_delcBs eZedƒZedƒZRS(sDelete an HBAC service group.s&Deleted HBAC service group "%(value)s"(RRRRR*(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR+Ys thbacsvcgroup_modcBs eZedƒZedƒZRS(sModify an HBAC service group.s'Modified HBAC service group "%(value)s"(RRRRR*(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR,as thbacsvcgroup_findcBs&eZedƒZedddƒZRS(s!Search for an HBAC service group.s$%(count)d HBAC service group matcheds%%(count)d HBAC service groups matchedi(RRRRRR*(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR-is thbacsvcgroup_showcBseZedƒZRS(s0Display information about an HBAC service group.(RRRR(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR.ssthbacsvcgroup_add_membercBseZedƒZRS(s%Add members to an HBAC service group.(RRRR(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR/ysthbacsvcgroup_remove_membercBseZedƒZRS(s*Remove members from an HBAC service group.(RRRR(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyR0sN(tipalibRRtipalib.plugins.baseldapRRRttopict LDAPObjectRtregistert LDAPCreateR)t LDAPDeleteR+t LDAPUpdateR,t LDAPSearchR-t LDAPRetrieveR.t LDAPAddMemberR/tLDAPRemoveMemberR0(((s9/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvcgroup.pyts*         freeipa-3.3.4/ipalib/plugins/ping.py0000664000175000017500000000437412271663206016747 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib import api from ipalib import Command from ipalib import output from ipalib import _, ngettext from ipapython.version import VERSION, API_VERSION __doc__ = _(""" Ping the remote IPA server to ensure it is running. The ping command sends an echo request to an IPA server. The server returns its version information. This is used by an IPA client to confirm that the server is available and accepting requests. The server from xmlrpc_uri in /etc/ipa/default.conf is contacted first. If it does not respond then the client will contact any servers defined by ldap SRV records in DNS. EXAMPLES: Ping an IPA server: ipa ping ------------------------------------------ IPA server version 2.1.9. API version 2.20 ------------------------------------------ Ping an IPA server verbosely: ipa -v ping ipa: INFO: trying https://ipa.example.com/ipa/xml ipa: INFO: Forwarding 'ping' to server 'https://ipa.example.com/ipa/xml' ----------------------------------------------------- IPA server version 2.1.9. API version 2.20 ----------------------------------------------------- """) class ping(Command): __doc__ = _('Ping a remote server.') has_output = ( output.summary, ) def execute(self, **options): """ A possible enhancement would be to take an argument and echo it back but a fixed value works for now. """ return dict(summary=u'IPA server version %s. API version %s' % (VERSION, API_VERSION)) api.register(ping) freeipa-3.3.4/ipalib/plugins/passwd.pyc0000664000175000017500000001002612271707517017451 0ustar mkosekmkosekó †fçRc@sàddlmZmZmZddlmZddlmZmZddlmZddlmZddl m Z m Z m Z ddl mZddlmZed ƒZd Zd „Zd efd „ƒYZejeƒdS(iÿÿÿÿ(tapiterrorstutil(tCommand(tStrtPassword(t_(toutput(tsplit_principaltvalidate_principaltnormalize_principal(tcontext(tDNsô Set a user's password If someone other than a user changes that user's password (e.g., Helpdesk resets it) then the password will need to be changed the first time it is used. This is so the end-user is the only one who knows the password. The IPA password policy controls how often a password may be changed, what strength requirements exist, and the length of the password history. EXAMPLES: To reset your own password: ipa passwd To change another user's password: ipa passwd tuser1 u"CHANGING_PASSWORD_FOR_ANOTHER_USERcCs*tjƒ}|t|ƒkr"dStSdS(sª If the user is changing their own password then return None so the current password is prompted for, otherwise return a fixed value to be ignored later. N(Rtget_current_principalR tNonet MAGIC_VALUE(t principaltcurrent_principal((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pytget_current_password4s tpasswdcBs¹eZedƒZededddedƒdededd „d d „ƒed ded ƒƒeddedƒdedd„deddƒfZ e j Z edƒZ d„ZRS(sSet a user's password.Rtcli_nametusertlabels User namet primary_keytautofillt default_fromcCs tjƒS(N(RR (((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pytIst normalizercCs t|ƒS(N(R (tvalue((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pyRJstpasswords New Passwordtcurrent_passwordsCurrent PasswordtconfirmcCs t|ƒS(N(R(R((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pyRRst sortorderiÿÿÿÿs Changed password for "%(value)s"cKsÙ|jjj}|jd|ddgttjjtjjƒƒ\}}|tt dƒkr”|t kr”|j j dƒt jdtdƒƒ‚n|t kr³|j||ƒn|j|||ƒtdtd |ƒS( se Execute the passwd operation. The dn should not be passed as a keyword argument as it is constructed by this method. Returns the entry :param principal: The login name or principal of the user :param password: the new password :param current_password: the existing password, if applicable tkrbprincipalnamet posixaccounttRs3User attempted to change password using magic valuetinfosInvalid credentialstresultR(RtBackendtldap2tfind_entry_by_attrR tenvtcontainer_usertbasedntgetattrR RtlogtwarnRtACIErrorRtmodify_passwordtdicttTrue(tselfRRRtoptionstldaptdnt entry_attrs((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pytexecute[s $  (t__name__t __module__Rt__doc__RR R2RtFalset takes_argsRtstandard_valuet has_outputt msg_summaryR8(((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pyR@s&             N(tipalibRRRRRRRRtipalib.plugins.userRR R tipalib.requestR t ipapython.dnR R;RRRtregister(((s3/home/mkosek/freeipa-clean/ipalib/plugins/passwd.pyts  ?freeipa-3.3.4/ipalib/plugins/netgroup.pyc0000664000175000017500000002323512271707517020021 0ustar mkosekmkosekó †fçRc@säddlmZmZddlmZmZddlTddlmZmZddlm Z edƒZ dZ dZ e Z e Zed d d ƒed d d ƒedd edƒƒedd dƒfZdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒd efd!„ƒYZ eje ƒd"S(#iÿÿÿÿ(tapiterrors(tStrtStrEnum(t*(t_tngettext(tis_allsæ Netgroups A netgroup is a group used for permission checking. It can contain both user and host values. EXAMPLES: Add a new netgroup: ipa netgroup-add --desc="NFS admins" admins Add members to the netgroup: ipa netgroup-add-member --users=tuser1 --users=tuser2 admins Remove a member from the netgroup: ipa netgroup-remove-member --users=tuser2 admins Display information about a netgroup: ipa netgroup-show admins Delete a netgroup: ipa netgroup-del admins s^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*$s.may only include letters, numbers, _, -, and .smemberuser_user?tlabels Member Usersmemberuser_group?s Member Groupsmemberhost_host?s Member Hostsmemberhost_hostgroup?sMember HostgrouptnetgroupcBseZdZejjZedƒZedƒZ dddgZ dddd d d d d dddg Z dZ dZ idgd 6dgd6dgd6ddgd 6ddgd 6Zid@d 6dAd6dCd6dDd 6dEd 6ZedƒZedƒZedd ed!ed"d#d$ed%ƒd&ed'd(„ƒedd"d)d$ed*ƒd+ed,ƒƒed-d ed!ed"d.d$ed/ƒƒed0d"d1d$d2d+ed2ƒd3d4d5gƒed6d"d7d$ed8ƒd+ed9ƒd:dFƒed<d"d=d$ed>ƒd+ed?ƒd:dGƒefZRS(Hs Netgroup object. R t netgroupst ipaobjecttipaassociationtipanisnetgrouptcnt descriptiontmemberoft externalhostt nisdomainnamet memberusert memberhosttmembertmemberindirectt usercategoryt hostcategoryt ipauniqueidtusertgroupthostt hostgrouptMemberttno_s Member Oftin_tnot_in_sIndirect Membert no_indirect_t NetgroupstNetgrouptpatterntpattern_errmsgtcli_nametnameRs Netgroup namet primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pytvstdesct DescriptiontdocsNetgroup descriptionsnisdomainname?t nisdomainsNIS domain names ipauniqueid?tuuids IPA unique IDtflagst no_createt no_updates usercategory?tusercats User categorys!User category the rule applies totvaluesualls hostcategory?thostcats Host categorys!Host category the rule applies to(sMemberRsno_(s Member Ofsin_snot_in_N(sIndirect MemberNs no_indirect_(sMemberRsno_(sMemberRsno_(uall(uall(t__name__t __module__t__doc__Rtenvtcontainer_netgroupt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributet rdn_attributetattribute_memberstNonet relationshipsRtlabel_singularRtNETGROUP_PATTERNtNETGROUP_PATTERN_ERRMSGtTruetNISDOMAIN_PATTERNtNISDOMAIN_PATTERN_ERRMSGRtexternal_host_paramt takes_params(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyR Lsp                             t netgroup_addcBsBeZedƒZejeZedƒZedƒZd„Z RS(sAdd a new netgroup.sAdded netgroup "%(value)s"uZhostgroup with name "%s" already exists. Hostgroups and netgroups share a common namespacec Os"t|tƒst‚|jd|jjjƒyƒ|jj|dƒ}|j |dgƒ\}} d| j dgƒkr t j dt |j|dƒƒ‚n|jj|ŒWnt jk rÇnXy?tjdj|dƒt j dt |j|dƒƒ‚Wnt jk rnX|S(NRiÿÿÿÿt objectclasstmepManagedEntrytmessageR(t isinstancetDNtAssertionErrort setdefaultRR=tdomaintobjtget_dnt get_entrytgetRtDuplicateEntrytunicodet msg_collisionthandle_duplicate_entrytNotFoundtObjecttget_dn_if_exists( tselftldaptdnt entry_attrst attrs_listtkeystoptionsttest_dnttest_dn_R ((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyt pre_callback¤s &'( R:R;RR<t LDAPCreatethas_output_paramst output_paramst msg_summaryR`Rn(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRQ›s     t netgroup_delcBs eZedƒZedƒZRS(sDelete a netgroup.sDeleted netgroup "%(value)s"(R:R;RR<Rr(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRsÀs t netgroup_modcBs6eZedƒZejeZedƒZd„ZRS(sModify a netgroup.sModified netgroup "%(value)s"cOsÈt|tƒst‚y|j||ƒ\}}Wn$tjk rW|jj|ŒnXt|dƒrŽd|krŽtj dt dƒƒ‚nt|dƒrÄd|krÄtj dt dƒƒ‚n|S(NRRtreasonsBuser category cannot be set to 'all' while there are allowed usersRRsBhost category cannot be set to 'all' while there are allowed hosts( RURVRWR\RRbRZthandle_not_foundRtMutuallyExclusiveErrorR(ReRfRgRhRiRjRk((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRnÎs( R:R;RR<t LDAPUpdateRpRqRrRn(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRtÈs   t netgroup_findc BsšeZedƒZddddgZejeZedddƒZ ej e dd d d d d gƒe ddddedƒdd„ƒfZ d„Z RS(sSearch for a netgroup.RRRRs%(count)d netgroup matcheds%(count)d netgroups matcheditprivatetexcludetwebuiR4t no_optiont no_outputtmanagedR(R1ssearch for managed groupst default_fromcCs|S(N((Rz((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyR.îsc Ost|tƒst‚i}dg|d<|dsM|j|d|jƒ} n|j|d|jƒ} |j| |fd|jƒ}|||fS(NRSRRRtrules(RURVRWt make_filtert MATCH_NONEt MATCH_ALLtcombine_filters( ReRftfilterRitbase_dntscopetargsRkt search_kwt local_filter((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRnòs  ( R:R;RR<tmember_attributest LDAPSearchRpRqRRrt takes_optionstFlagRn(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRyÝs      t netgroup_showcBs!eZedƒZejeZRS(s%Display information about a netgroup.(R:R;RR<t LDAPRetrieveRpRq(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRs tnetgroup_add_membercBsBeZedƒZdddgZejeZd„Zd„Z RS(sAdd members to a netgroup.RRRcOs+t|tƒst‚td||||ƒS(NR(RURVRWtadd_external_pre_callback(ReRfRgtfoundt not_foundRjRk((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyRnsc Os:t|tƒst‚tddd|||||||ƒ S(NRRR(RURVRWtadd_external_post_callback(ReRft completedtfailedRgRhRjRk((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyt post_callbacks( R:R;RR<RŒt LDAPAddMemberRpRqRnR™(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyR’ s    tnetgroup_remove_membercBs9eZedƒZdddgZejeZd„ZRS(sRemove members from a netgroup.RRRc Os:t|tƒst‚tddd|||||||ƒ S(NRRR(RURVRWtremove_external_post_callback(ReRfR—R˜RgRhRjRk((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyR™ s( R:R;RR<RŒtLDAPRemoveMemberRpRqR™(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pyR›s  N(!tipalibRRRRtipalib.plugins.baseldapRRtipalib.plugins.hbacruleRR<RJRKRMRNRqt LDAPObjectR tregisterRoRQt LDAPDeleteRsRxRtRRyR‘RRšR’RR›(((s5/home/mkosek/freeipa-clean/ipalib/plugins/netgroup.pytsD        L "   #    freeipa-3.3.4/ipalib/plugins/kerberos.py0000664000175000017500000000742412271663206017625 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Backend plugin for Kerberos. This wraps the python-kerberos and python-krbV bindings. """ import sys from ipalib import api from ipalib.backend import Backend import krbV ENCODING = 'UTF-8' class krb(Backend): """ Kerberos backend plugin. This wraps the `krbV` bindings (and will eventually wrap the `kerberos` bindings also). Importantly, this plugin does correct Unicode encoding/decoding of values going-to/coming-from the bindings. """ def __default_ccache(self): """ Return the ``krbV.CCache`` for the default credential cache. """ return krbV.default_context().default_ccache() def __default_principal(self): """ Return the ``krb5.Principal`` for the default credential cache. """ return self.__default_ccache().principal() def __get_ccache(self, ccname): """ Return the ``krbV.CCache`` for the ``ccname`` credential ccache. """ return krbV.CCache(ccname) def __get_principal(self, ccname): """ Return the ``krb5.Principal`` for the ``ccname`` credential ccache. """ return self.__get_ccache(ccname).principal() def default_ccname(self): """ Return the default ccache file name (schema+name). This will return something like 'FILE:/tmp/krb5cc_500'. This cannot return anything meaningful if used in the server as a request is processed. """ default_ccache = self.__default_ccache() ccname = "%(type)s:%(name)s" % dict(type=default_ccache.type, name=default_ccache.name) return ccname def default_principal(self): """ Return the principal name in default credential cache. This will return something like 'admin@EXAMPLE.COM'. If no credential cache exists for the invoking user, None is returned. This cannot return anything meaningful if used in the server as a request is processed. """ return self.__default_principal().name.decode(ENCODING) def default_realm(self): """ Return the realm from the default credential cache. This will return something like 'EXAMPLE.COM'. If no credential cache exists for the invoking user, None is returned. This cannot return anything meaningful if used in the server as a request is processed. """ return krbV.default_context().default_realm.decode(ENCODING) def get_principal(self, ccname): """ Return the principal from credential cache file at ``ccname``. This will return something like 'admin@EXAMPLE.COM'. """ return self.__get_principal(ccname).name.decode(ENCODING) def get_realm(self, ccname): """ Return the realm from credential cache file at ``ccname``. This will return something like 'EXAMPLE.COM'. """ return self.__get_principal(ccname).realm.decode(ENCODING) api.register(krb) freeipa-3.3.4/ipalib/plugins/sudorule.py0000664000175000017500000006427312271663206017660 0ustar mkosekmkosek# Authors: # Jr Aquino # # Copyright (C) 2010 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 . from ipalib import api, errors from ipalib import Str, StrEnum, Bool from ipalib.plugins.baseldap import * from ipalib.plugins.hbacrule import is_all from ipalib import _, ngettext __doc__ = _(""" Sudo Rules Sudo (su "do") allows a system administrator to delegate authority to give certain users (or groups of users) the ability to run some (or all) commands as root or another user while providing an audit trail of the commands and their arguments. FreeIPA provides a means to configure the various aspects of Sudo: Users: The user(s)/group(s) allowed to invoke Sudo. Hosts: The host(s)/hostgroup(s) which the user is allowed to to invoke Sudo. Allow Command: The specific command(s) permitted to be run via Sudo. Deny Command: The specific command(s) prohibited to be run via Sudo. RunAsUser: The user(s) or group(s) of users whose rights Sudo will be invoked with. RunAsGroup: The group(s) whose gid rights Sudo will be invoked with. Options: The various Sudoers Options that can modify Sudo's behavior. An order can be added to a sudorule to control the order in which they are evaluated (if the client supports it). This order is an integer and must be unique. FreeIPA provides a designated binddn to use with Sudo located at: uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com To enable the binddn run the following command to set the password: LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W \ -h ipa.example.com -ZZ -D "cn=Directory Manager" \ uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com EXAMPLES: Create a new rule: ipa sudorule-add readfiles Add sudo command object and add it as allowed command in the rule: ipa sudocmd-add /usr/bin/less ipa sudorule-add-allow-command readfiles --sudocmds /usr/bin/less Add a host to the rule: ipa sudorule-add-host readfiles --hosts server.example.com Add a user to the rule: ipa sudorule-add-user readfiles --users jsmith Add a special Sudo rule for default Sudo server configuration: ipa sudorule-add defaults Set a default Sudo option: ipa sudorule-add-option defaults --sudooption '!authenticate' """) topic = ('sudo', _('Commands for controlling sudo configuration')) def deprecated(attribute): raise errors.ValidationError(name=attribute, error=_('this option has been deprecated.')) def validate_externaluser(ugettext, value): deprecated('externaluser') def validate_runasextuser(ugettext, value): deprecated('runasexternaluser') def validate_runasextgroup(ugettext, value): deprecated('runasexternalgroup') class sudorule(LDAPObject): """ Sudo Rule object. """ container_dn = api.env.container_sudorule object_name = _('sudo rule') object_name_plural = _('sudo rules') object_class = ['ipaassociation', 'ipasudorule'] default_attributes = [ 'cn', 'ipaenabledflag', 'externaluser', 'description', 'usercategory', 'hostcategory', 'cmdcategory', 'memberuser', 'memberhost', 'memberallowcmd', 'memberdenycmd', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasgroup', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', 'sudoorder', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'memberallowcmd': ['sudocmd', 'sudocmdgroup'], 'memberdenycmd': ['sudocmd', 'sudocmdgroup'], 'ipasudorunas': ['user', 'group'], 'ipasudorunasgroup': ['group'], } label = _('Sudo Rules') label_singular = _('Sudo Rule') takes_params = ( Str('cn', cli_name='sudorule_name', label=_('Rule name'), primary_key=True, ), Str('description?', cli_name='desc', label=_('Description'), ), Bool('ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), StrEnum('usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum('hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), StrEnum('cmdcategory?', cli_name='cmdcat', label=_('Command category'), doc=_('Command category the rule applies to'), values=(u'all', ), ), StrEnum('ipasudorunasusercategory?', cli_name='runasusercat', label=_('RunAs User category'), doc=_('RunAs User category the rule applies to'), values=(u'all', ), ), StrEnum('ipasudorunasgroupcategory?', cli_name='runasgroupcat', label=_('RunAs Group category'), doc=_('RunAs Group category the rule applies to'), values=(u'all', ), ), Int('sudoorder?', cli_name='order', label=_('Sudo order'), doc=_('integer to order the Sudo rules'), default=0, minvalue=0, ), Str('memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberallowcmd_sudocmd?', label=_('Sudo Allow Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberdenycmd_sudocmd?', label=_('Sudo Deny Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberallowcmd_sudocmdgroup?', label=_('Sudo Allow Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberdenycmd_sudocmdgroup?', label=_('Sudo Deny Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('ipasudorunas_user?', label=_('RunAs Users'), doc=_('Run as a user'), flags=['no_create', 'no_update', 'no_search'], ), Str('ipasudorunas_group?', label=_('Groups of RunAs Users'), doc=_('Run as any user within a specified group'), flags=['no_create', 'no_update', 'no_search'], ), Str('externaluser?', validate_externaluser, cli_name='externaluser', label=_('External User'), doc=_('External User the rule applies to (sudorule-find only)'), ), Str('ipasudorunasextuser?', validate_runasextuser, cli_name='runasexternaluser', label=_('RunAs External User'), doc=_('External User the commands can run as (sudorule-find only)'), ), Str('ipasudorunasextgroup?', validate_runasextgroup, cli_name='runasexternalgroup', label=_('RunAs External Group'), doc=_('External Group the commands can run as (sudorule-find only)'), ), Str('ipasudoopt?', label=_('Sudo Option'), flags=['no_create', 'no_update', 'no_search'], ), Str('ipasudorunasgroup_group?', label=_('RunAs Groups'), doc=_('Run with the gid of a specified POSIX group'), flags=['no_create', 'no_update', 'no_search'], ), external_host_param, ) order_not_unique_msg = _( 'order must be a unique value (%(order)d already used by %(rule)s)' ) def check_order_uniqueness(self, *keys, **options): if 'sudoorder' in options: entries = self.methods.find( sudoorder=options['sudoorder'] )['result'] if len(entries) > 0: rule_name = entries[0]['cn'][0] raise errors.ValidationError( name='order', error=self.order_not_unique_msg % { 'order': options['sudoorder'], 'rule': rule_name, } ) api.register(sudorule) class sudorule_add(LDAPCreate): __doc__ = _('Create new Sudo Rule.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.check_order_uniqueness(*keys, **options) # Sudo Rules are enabled by default entry_attrs['ipaenabledflag'] = 'TRUE' return dn msg_summary = _('Added Sudo Rule "%(value)s"') api.register(sudorule_add) class sudorule_del(LDAPDelete): __doc__ = _('Delete Sudo Rule.') msg_summary = _('Deleted Sudo Rule "%(value)s"') api.register(sudorule_del) class sudorule_mod(LDAPUpdate): __doc__ = _('Modify Sudo Rule.') msg_summary = _('Modified Sudo Rule "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if 'sudoorder' in options: new_order = options.get('sudoorder') old_entry = self.api.Command.sudorule_show(keys[-1])['result'] if 'sudoorder' in old_entry: old_order = int(old_entry['sudoorder'][0]) if old_order != new_order: self.obj.check_order_uniqueness(*keys, **options) else: self.obj.check_order_uniqueness(*keys, **options) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(options, 'usercategory') and 'memberuser' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_("user category cannot be set to 'all' while there are allowed users")) if is_all(options, 'hostcategory') and 'memberhost' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_("host category cannot be set to 'all' while there are allowed hosts")) if is_all(options, 'cmdcategory') and ('memberallowcmd' or 'memberdenywcmd') in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_("command category cannot be set to 'all' while there are allow or deny commands")) if is_all(options, 'ipasudorunasusercategory') and 'ipasudorunas' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_("user runAs category cannot be set to 'all' while there are users")) if is_all(options, 'ipasudorunasgroupcategory') and 'ipasudorunasgroup' in _entry_attrs: raise errors.MutuallyExclusiveError(reason=_("group runAs category cannot be set to 'all' while there are groups")) return dn api.register(sudorule_mod) class sudorule_find(LDAPSearch): __doc__ = _('Search for Sudo Rule.') msg_summary = ngettext( '%(count)d Sudo Rule matched', '%(count)d Sudo Rules matched', 0 ) api.register(sudorule_find) class sudorule_show(LDAPRetrieve): __doc__ = _('Display Sudo Rule.') api.register(sudorule_show) class sudorule_enable(LDAPQuery): __doc__ = _('Enable a Sudo Rule.') def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'TRUE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) return dict(result=True) def output_for_cli(self, textui, result, cn, **options): textui.print_dashed(_('Enabled Sudo Rule "%s"') % cn) api.register(sudorule_enable) class sudorule_disable(LDAPQuery): __doc__ = _('Disable a Sudo Rule.') def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'FALSE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) return dict(result=True) def output_for_cli(self, textui, result, cn, **options): textui.print_dashed(_('Disabled Sudo Rule "%s"') % cn) api.register(sudorule_disable) class sudorule_add_allow_command(LDAPAddMember): __doc__ = _('Add commands and sudo command groups affected by Sudo Rule.') member_attributes = ['memberallowcmd'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'cmdcategory'): raise errors.MutuallyExclusiveError(reason=_("commands cannot be added when command category='all'")) return dn api.register(sudorule_add_allow_command) class sudorule_remove_allow_command(LDAPRemoveMember): __doc__ = _('Remove commands and sudo command groups affected by Sudo Rule.') member_attributes = ['memberallowcmd'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(sudorule_remove_allow_command) class sudorule_add_deny_command(LDAPAddMember): __doc__ = _('Add commands and sudo command groups affected by Sudo Rule.') member_attributes = ['memberdenycmd'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'cmdcategory'): raise errors.MutuallyExclusiveError(reason=_("commands cannot be added when command category='all'")) return dn api.register(sudorule_add_deny_command) class sudorule_remove_deny_command(LDAPRemoveMember): __doc__ = _('Remove commands and sudo command groups affected by Sudo Rule.') member_attributes = ['memberdenycmd'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(sudorule_remove_deny_command) class sudorule_add_user(LDAPAddMember): __doc__ = _('Add users and groups affected by Sudo Rule.') member_attributes = ['memberuser'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'usercategory'): raise errors.MutuallyExclusiveError(reason=_("users cannot be added when user category='all'")) return add_external_pre_callback('user', ldap, dn, keys, options) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return add_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_add_user) class sudorule_remove_user(LDAPRemoveMember): __doc__ = _('Remove users and groups affected by Sudo Rule.') member_attributes = ['memberuser'] member_count_out = ('%i object removed.', '%i objects removed.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return remove_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_remove_user) class sudorule_add_host(LDAPAddMember): __doc__ = _('Add hosts and hostgroups affected by Sudo Rule.') member_attributes = ['memberhost'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'hostcategory'): raise errors.MutuallyExclusiveError(reason=_("hosts cannot be added when host category='all'")) return add_external_pre_callback('host', ldap, dn, keys, options) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_add_host) class sudorule_remove_host(LDAPRemoveMember): __doc__ = _('Remove hosts and hostgroups affected by Sudo Rule.') member_attributes = ['memberhost'] member_count_out = ('%i object removed.', '%i objects removed.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_remove_host) class sudorule_add_runasuser(LDAPAddMember): __doc__ = _('Add users and groups for Sudo to execute as.') member_attributes = ['ipasudorunas'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) def check_validity(runas): v = unicode(runas) if v.upper() == u'ALL': return False return True try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'ipasudorunasusercategory') or \ is_all(_entry_attrs, 'ipasudorunasgroupcategory'): raise errors.MutuallyExclusiveError(reason=_("users cannot be added when runAs user or runAs group category='all'")) if 'user' in options: for name in options['user']: if not check_validity(name): raise errors.ValidationError(name='runas-user', error=unicode(_("RunAsUser does not accept '%(name)s' as a user name")) % dict(name=name)) if 'group' in options: for name in options['group']: if not check_validity(name): raise errors.ValidationError(name='runas-user', error=unicode(_("RunAsUser does not accept '%(name)s' as a group name")) % dict(name=name)) return add_external_pre_callback('user', ldap, dn, keys, options) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return add_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_add_runasuser) class sudorule_remove_runasuser(LDAPRemoveMember): __doc__ = _('Remove users and groups for Sudo to execute as.') member_attributes = ['ipasudorunas'] member_count_out = ('%i object removed.', '%i objects removed.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return remove_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_remove_runasuser) class sudorule_add_runasgroup(LDAPAddMember): __doc__ = _('Add group for Sudo to execute as.') member_attributes = ['ipasudorunasgroup'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) def check_validity(runas): v = unicode(runas) if v.upper() == u'ALL': return False return True try: (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(_entry_attrs, 'ipasudorunasusercategory') or \ is_all(_entry_attrs, 'ipasudorunasgroupcategory'): raise errors.MutuallyExclusiveError(reason=_("users cannot be added when runAs user or runAs group category='all'")) if 'group' in options: for name in options['group']: if not check_validity(name): raise errors.ValidationError(name='runas-group', error=unicode(_("RunAsGroup does not accept '%(name)s' as a group name")) % dict(name=name)) return add_external_pre_callback('group', ldap, dn, keys, options) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return add_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_add_runasgroup) class sudorule_remove_runasgroup(LDAPRemoveMember): __doc__ = _('Remove group for Sudo to execute as.') member_attributes = ['ipasudorunasgroup'] member_count_out = ('%i object removed.', '%i objects removed.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return remove_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(sudorule_remove_runasgroup) class sudorule_add_option(LDAPQuery): __doc__ = _('Add an option to the Sudo Rule.') has_output = output.standard_entry takes_options = ( Str('ipasudoopt', cli_name='sudooption', label=_('Sudo Option'), ), ) def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if not options['ipasudoopt'].strip(): raise errors.EmptyModlist() (dn, entry_attrs) = ldap.get_entry(dn, ['ipasudoopt']) try: if options['ipasudoopt'] not in entry_attrs['ipasudoopt']: entry_attrs.setdefault('ipasudoopt', []).append( options['ipasudoopt']) else: raise errors.DuplicateEntry except KeyError: entry_attrs.setdefault('ipasudoopt', []).append( options['ipasudoopt']) try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) attrs_list = self.obj.default_attributes (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) entry_attrs = entry_to_dict(entry_attrs, **options) return dict(result=entry_attrs, value=cn) def output_for_cli(self, textui, result, cn, **options): textui.print_dashed(_('Added option "%(option)s" to Sudo Rule "%(rule)s"') % \ dict(option=options['ipasudoopt'], rule=cn)) super(sudorule_add_option, self).output_for_cli(textui, result, cn, **options) api.register(sudorule_add_option) class sudorule_remove_option(LDAPQuery): __doc__ = _('Remove an option from Sudo Rule.') has_output = output.standard_entry takes_options = ( Str('ipasudoopt', cli_name='sudooption', label=_('Sudo Option'), ), ) def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) if not options['ipasudoopt'].strip(): raise errors.EmptyModlist() (dn, entry_attrs) = ldap.get_entry(dn, ['ipasudoopt']) try: if options['ipasudoopt'] in entry_attrs['ipasudoopt']: entry_attrs.setdefault('ipasudoopt', []).remove( options['ipasudoopt']) ldap.update_entry(dn, entry_attrs) else: raise errors.AttrValueNotFound( attr='ipasudoopt', value=options['ipasudoopt'] ) except ValueError, e: pass except KeyError: raise errors.AttrValueNotFound( attr='ipasudoopt', value=options['ipasudoopt'] ) except errors.NotFound: self.obj.handle_not_found(cn) attrs_list = self.obj.default_attributes (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) entry_attrs = entry_to_dict(entry_attrs, **options) return dict(result=entry_attrs, value=cn) def output_for_cli(self, textui, result, cn, **options): textui.print_dashed(_('Removed option "%(option)s" from Sudo Rule "%(rule)s"') % \ dict(option=options['ipasudoopt'], rule=cn)) super(sudorule_remove_option, self).output_for_cli(textui, result, cn, **options) api.register(sudorule_remove_option) freeipa-3.3.4/ipalib/plugins/baseldap.py0000664000175000017500000023244112271663206017563 0ustar mkosekmkosek# Authors: # Pavel Zuna # # Copyright (C) 2009 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 . """ Base classes for LDAP plugins. """ import re import time from copy import deepcopy import base64 from ipalib import api, crud, errors from ipalib import Method, Object, Command from ipalib import Flag, Int, Str from ipalib.cli import to_cli from ipalib import output from ipalib.text import _ from ipalib.util import json_serialize, validate_hostname from ipapython.dn import DN, RDN DNA_MAGIC = -1 global_output_params = ( Flag('has_password', label=_('Password'), ), Str('member', label=_('Failed members'), ), Str('member_user?', label=_('Member users'), ), Str('member_group?', label=_('Member groups'), ), Str('memberof_group?', label=_('Member of groups'), ), Str('member_host?', label=_('Member hosts'), ), Str('member_hostgroup?', label=_('Member host-groups'), ), Str('memberof_hostgroup?', label=_('Member of host-groups'), ), Str('memberof_permission?', label=_('Permissions'), ), Str('memberof_privilege?', label='Privileges', ), Str('memberof_role?', label=_('Roles'), ), Str('memberof_sudocmdgroup?', label=_('Sudo Command Groups'), ), Str('member_privilege?', label='Granted to Privilege', ), Str('member_role?', label=_('Granting privilege to roles'), ), Str('member_netgroup?', label=_('Member netgroups'), ), Str('memberof_netgroup?', label=_('Member of netgroups'), ), Str('member_service?', label=_('Member services'), ), Str('member_servicegroup?', label=_('Member service groups'), ), Str('memberof_servicegroup?', label='Member of service groups', ), Str('member_hbacsvc?', label=_('Member HBAC service'), ), Str('member_hbacsvcgroup?', label=_('Member HBAC service groups'), ), Str('memberof_hbacsvcgroup?', label='Member of HBAC service groups', ), Str('member_sudocmd?', label='Member Sudo commands', ), Str('memberof_sudorule?', label='Member of Sudo rule', ), Str('memberof_hbacrule?', label='Member of HBAC rule', ), Str('memberindirect_user?', label=_('Indirect Member users'), ), Str('memberindirect_group?', label=_('Indirect Member groups'), ), Str('memberindirect_host?', label=_('Indirect Member hosts'), ), Str('memberindirect_hostgroup?', label=_('Indirect Member host-groups'), ), Str('memberindirect_role?', label=_('Indirect Member of roles'), ), Str('memberindirect_permission?', label=_('Indirect Member permissions'), ), Str('memberindirect_hbacsvc?', label=_('Indirect Member HBAC service'), ), Str('memberindirect_hbacsvcgrp?', label=_('Indirect Member HBAC service group'), ), Str('memberindirect_netgroup?', label=_('Indirect Member netgroups'), ), Str('memberofindirect_group?', label='Indirect Member of group', ), Str('memberofindirect_netgroup?', label='Indirect Member of netgroup', ), Str('memberofindirect_hostgroup?', label='Indirect Member of host-group', ), Str('memberofindirect_role?', label='Indirect Member of role', ), Str('memberofindirect_sudorule?', label='Indirect Member of Sudo rule', ), Str('memberofindirect_hbacrule?', label='Indirect Member of HBAC rule', ), Str('sourcehost', label=_('Failed source hosts/hostgroups'), ), Str('memberhost', label=_('Failed hosts/hostgroups'), ), Str('memberuser', label=_('Failed users/groups'), ), Str('memberservice', label=_('Failed service/service groups'), ), Str('failed', label=_('Failed to remove'), flags=['suppress_empty'], ), Str('ipasudorunas', label=_('Failed RunAs'), ), Str('ipasudorunasgroup', label=_('Failed RunAsGroup'), ), ) def validate_add_attribute(ugettext, attr): validate_attribute(ugettext, 'addattr', attr) def validate_set_attribute(ugettext, attr): validate_attribute(ugettext, 'setattr', attr) def validate_del_attribute(ugettext, attr): validate_attribute(ugettext, 'delattr', attr) def validate_attribute(ugettext, name, attr): m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", attr) if not m or len(m.groups()) != 2: raise errors.ValidationError( name=name, error=_('Invalid format. Should be name=value')) def get_effective_rights(ldap, dn, attrs=None): assert isinstance(dn, DN) if attrs is None: attrs = ['*', 'nsaccountlock', 'cospriority'] rights = ldap.get_effective_rights(dn, attrs) rdict = {} if 'attributelevelrights' in rights[1]: rights = rights[1]['attributelevelrights'] rights = rights[0].split(', ') for r in rights: (k,v) = r.split(':') rdict[k.strip().lower()] = v return rdict def entry_from_entry(entry, newentry): """ Python is more or less pass-by-value except for immutable objects. So if you pass in a dict to a function you are free to change members of that dict but you can't create a new dict in the function and expect to replace what was passed in. In some post-op plugins that is exactly what we want to do, so here is a clumsy way around the problem. """ # Wipe out the current data for e in entry.keys(): del entry[e] # Re-populate it with new wentry for e in newentry.keys(): entry[e] = newentry[e] def entry_to_dict(entry, **options): if options.get('raw', False): result = dict(entry) else: result = dict((k.lower(), v) for (k, v) in entry.iteritems()) if options.get('all', False): result['dn'] = entry.dn return result def wait_for_value(ldap, dn, attr, value): """ 389-ds postoperation plugins are executed after the data has been returned to a client. This means that plugins that add data in a postop are not included in data returned to the user. The downside of waiting is that this increases the time of the command. The updated entry is returned. """ # Loop a few times to give the postop-plugin a chance to complete # Don't sleep for more than 6 seconds. x = 0 while x < 20: # sleep first because the first search, even on a quiet system, # almost always fails. time.sleep(.3) x = x + 1 # FIXME: put a try/except around here? I think it is probably better # to just let the exception filter up to the caller. (dn, entry_attrs) = ldap.get_entry( dn, ['*']) if attr in entry_attrs: if isinstance(entry_attrs[attr], (list, tuple)): values = map(lambda y:y.lower(), entry_attrs[attr]) if value.lower() in values: break else: if value.lower() == entry_attrs[attr].lower(): break return entry_attrs def validate_externalhost(ugettext, hostname): try: validate_hostname(hostname, check_fqdn=False, allow_underscore=True) except ValueError, e: return unicode(e) external_host_param = Str('externalhost*', validate_externalhost, label=_('External host'), flags=['no_option'], ) def add_external_pre_callback(membertype, ldap, dn, keys, options): """ Pre callback to validate external members. This should be called by a command pre callback directly. membertype is the type of member """ assert isinstance(dn, DN) # validate hostname with allowed underscore characters, non-fqdn # hostnames are allowed def validate_host(hostname): validate_hostname(hostname, check_fqdn=False, allow_underscore=True) if options.get(membertype): if membertype == 'host': validator = validate_host else: validator = api.Object[membertype].primary_key for value in options[membertype]: try: validator(value) except errors.ValidationError as e: raise errors.ValidationError(name=membertype, error=e.error) except ValueError as e: raise errors.ValidationError(name=membertype, error=e) return dn def add_external_post_callback(memberattr, membertype, externalattr, ldap, completed, failed, dn, entry_attrs, *keys, **options): """ Post callback to add failed members as external members. This should be called by a commands post callback directly. memberattr is one of memberuser, membertype is the type of member: user, externalattr is one of externaluser, """ assert isinstance(dn, DN) completed_external = 0 normalize = options.get('external_callback_normalize', True) # Sift through the failures. We assume that these are all # entries that aren't stored in IPA, aka external entries. if memberattr in failed and membertype in failed[memberattr]: (dn, entry_attrs_) = ldap.get_entry(dn, [externalattr]) assert isinstance(dn, DN) members = entry_attrs.get(memberattr, []) external_entries = entry_attrs_.get(externalattr, []) lc_external_entries = set(e.lower() for e in external_entries) failed_entries = [] for entry in failed[memberattr][membertype]: membername = entry[0].lower() member_dn = api.Object[membertype].get_dn(membername) assert isinstance(member_dn, DN) if (membername not in lc_external_entries and member_dn not in members): # Not an IPA entry, assume external if normalize: external_entries.append(membername) else: external_entries.append(entry[0]) lc_external_entries.add(membername) completed_external += 1 elif (membername in lc_external_entries and member_dn not in members): # Already an external member, reset the error message msg = unicode(errors.AlreadyGroupMember().message) newerror = (entry[0], msg) ind = failed[memberattr][membertype].index(entry) failed[memberattr][membertype][ind] = newerror failed_entries.append(membername) else: # Really a failure failed_entries.append(membername) if completed_external: try: ldap.update_entry(dn, {externalattr: external_entries}) except errors.EmptyModlist: pass failed[memberattr][membertype] = failed_entries entry_attrs[externalattr] = external_entries return (completed + completed_external, dn) def remove_external_post_callback(memberattr, membertype, externalattr, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # Run through the failures and gracefully remove any member defined # as an external member. if memberattr in failed and membertype in failed[memberattr]: (dn, entry_attrs_) = ldap.get_entry(dn, [externalattr]) external_entries = entry_attrs_.get(externalattr, []) failed_entries = [] completed_external = 0 for entry in failed[memberattr][membertype]: membername = entry[0].lower() if membername in external_entries or entry[0] in external_entries: try: external_entries.remove(membername) except ValueError: external_entries.remove(entry[0]) completed_external += 1 else: msg = unicode(errors.NotGroupMember().message) newerror = (entry[0], msg) ind = failed[memberattr][membertype].index(entry) failed[memberattr][membertype][ind] = newerror failed_entries.append(membername) if completed_external: try: ldap.update_entry(dn, {externalattr: external_entries}) except errors.EmptyModlist: pass failed[memberattr][membertype] = failed_entries entry_attrs[externalattr] = external_entries return (completed + completed_external, dn) def host_is_master(ldap, fqdn): """ Check to see if this host is a master. Raises an exception if a master, otherwise returns nothing. """ master_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) try: (dn, entry_attrs) = ldap.get_entry(master_dn, ['objectclass']) raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted or disabled')) except errors.NotFound: # Good, not a master return class LDAPObject(Object): """ Object representing a LDAP entry. """ backend_name = 'ldap2' parent_object = '' container_dn = '' object_name = _('entry') object_name_plural = _('entries') object_class = [] object_class_config = None # If an objectclass is possible but not default in an entry. Needed for # collecting attributes for ACI UI. possible_objectclasses = [] limit_object_classes = [] # Only attributes in these are allowed disallow_object_classes = [] # Disallow attributes in these search_attributes = [] search_attributes_config = None default_attributes = [] search_display_attributes = [] # attributes displayed in LDAPSearch hidden_attributes = ['objectclass', 'aci'] # set rdn_attribute only if RDN attribute differs from primary key! rdn_attribute = '' uuid_attribute = '' attribute_members = {} rdn_is_primary_key = False # Do we need RDN change to do a rename? password_attributes = [] # Can bind as this entry (has userPassword or krbPrincipalKey) bindable = False relationships = { # attribute: (label, inclusive param prefix, exclusive param prefix) 'member': ('Member', '', 'no_'), 'memberof': ('Member Of', 'in_', 'not_in_'), 'memberindirect': ( 'Indirect Member', None, 'no_indirect_' ), 'memberofindirect': ( 'Indirect Member Of', None, 'not_in_indirect_' ), } label = _('Entry') label_singular = _('Entry') container_not_found_msg = _('container entry (%(container)s) not found') parent_not_found_msg = _('%(parent)s: %(oname)s not found') object_not_found_msg = _('%(pkey)s: %(oname)s not found') already_exists_msg = _('%(oname)s with name "%(pkey)s" already exists') def get_dn(self, *keys, **kwargs): if self.parent_object: parent_dn = self.api.Object[self.parent_object].get_dn(*keys[:-1]) else: parent_dn = DN(self.container_dn, api.env.basedn) if self.rdn_attribute: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( self.primary_key.name, keys[-1], self.object_class, [''], DN(self.container_dn, api.env.basedn) ) except errors.NotFound: pass else: return dn if self.primary_key and keys[-1] is not None: return self.backend.make_dn_from_attr( self.primary_key.name, keys[-1], parent_dn ) assert isinstance(parent_dn, DN) return parent_dn def get_dn_if_exists(self, *keys, **kwargs): dn = self.get_dn(*keys, **kwargs) entry = self.backend.get_entry(dn, ['']) return entry.dn def get_primary_key_from_dn(self, dn): assert isinstance(dn, DN) try: if self.rdn_attribute: (dn, entry_attrs) = self.backend.get_entry( dn, [self.primary_key.name] ) try: return entry_attrs[self.primary_key.name][0] except (KeyError, IndexError): return '' except errors.NotFound: pass try: return dn[self.primary_key.name] except KeyError: # The primary key is not in the DN. # This shouldn't happen, but we don't want a "show" command to # crash. # Just return the entire DN, it's all we have if the entry # doesn't exist return unicode(dn) def get_ancestor_primary_keys(self): if self.parent_object: parent_obj = self.api.Object[self.parent_object] for key in parent_obj.get_ancestor_primary_keys(): yield key if parent_obj.primary_key: pkey = parent_obj.primary_key yield pkey.__class__( parent_obj.name + pkey.name, required=True, query=True, cli_name=parent_obj.name, label=pkey.label ) def has_objectclass(self, classes, objectclass): oc = map(lambda x:x.lower(),classes) return objectclass.lower() in oc def convert_attribute_members(self, entry_attrs, *keys, **options): if options.get('raw', False): return for attr in self.attribute_members: for member in entry_attrs.setdefault(attr, []): for ldap_obj_name in self.attribute_members[attr]: ldap_obj = self.api.Object[ldap_obj_name] container_dn = DN(ldap_obj.container_dn, api.env.basedn) if member.endswith(container_dn): new_attr = '%s_%s' % (attr, ldap_obj.name) entry_attrs.setdefault(new_attr, []).append( ldap_obj.get_primary_key_from_dn(member) ) del entry_attrs[attr] def get_password_attributes(self, ldap, dn, entry_attrs): """ Search on the entry to determine if it has a password or keytab set. A tuple is used to determine which attribute is set in entry_attrs. The value is set to True/False whether a given password type is set. """ for (pwattr, attr) in self.password_attributes: search_filter = '(%s=*)' % pwattr try: (entries, truncated) = ldap.find_entries( search_filter, [pwattr], dn, ldap.SCOPE_BASE ) entry_attrs[attr] = True except errors.NotFound: entry_attrs[attr] = False def handle_not_found(self, *keys): pkey = '' if self.primary_key: pkey = keys[-1] raise errors.NotFound( reason=self.object_not_found_msg % { 'pkey': pkey, 'oname': self.object_name, } ) def handle_duplicate_entry(self, *keys): pkey = '' if self.primary_key: pkey = keys[-1] raise errors.DuplicateEntry( message=self.already_exists_msg % { 'pkey': pkey, 'oname': self.object_name, } ) # list of attributes we want exported to JSON json_friendly_attributes = ( 'parent_object', 'container_dn', 'object_name', 'object_name_plural', 'object_class', 'object_class_config', 'default_attributes', 'label', 'label_singular', 'hidden_attributes', 'uuid_attribute', 'attribute_members', 'name', 'takes_params', 'rdn_attribute', 'bindable', 'relationships', ) def __json__(self): ldap = self.backend json_dict = dict( (a, json_serialize(getattr(self, a))) for a in self.json_friendly_attributes ) if self.primary_key: json_dict['primary_key'] = self.primary_key.name objectclasses = self.object_class if self.object_class_config: config = ldap.get_ipa_config()[1] objectclasses = config.get( self.object_class_config, 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) attrlist = [] # Go through the MUST first for (oid, attr) in attrs[0].iteritems(): attrlist.append(attr.names[0].lower()) # And now the MAY for (oid, attr) in attrs[1].iteritems(): attrlist.append(attr.names[0].lower()) json_dict['aciattrs'] = attrlist attrlist.sort() json_dict['methods'] = [m for m in self.methods] return json_dict # addattr can cause parameters to have more than one value even if not defined # as multivalue, make sure this isn't the case def _check_single_value_attrs(params, entry_attrs): for (a, v) in entry_attrs.iteritems(): if isinstance(v, (list, tuple)) and len(v) > 1: if a in params and not params[a].multivalue: raise errors.OnlyOneValueAllowed(attr=a) # setattr or --option='' can cause parameters to be empty that are otherwise # required, make sure we enforce that. def _check_empty_attrs(params, entry_attrs): for (a, v) in entry_attrs.iteritems(): if v is None or (isinstance(v, basestring) and len(v) == 0): if a in params and params[a].required: raise errors.RequirementError(name=a) def _check_limit_object_class(attributes, attrs, allow_only): """ If the set of objectclasses is limited enforce that only those are updated in entry_attrs (plus dn) allow_only tells us what mode to check in: If True then we enforce that the attributes must be in the list of allowed. If False then those attributes are not allowed. """ if len(attributes[0]) == 0 and len(attributes[1]) == 0: return limitattrs = deepcopy(attrs) # Go through the MUST first for (oid, attr) in attributes[0].iteritems(): if attr.names[0].lower() in limitattrs: if not allow_only: raise errors.ObjectclassViolation( info=_('attribute "%(attribute)s" not allowed') % dict( attribute=attr.names[0].lower())) limitattrs.remove(attr.names[0].lower()) # And now the MAY for (oid, attr) in attributes[1].iteritems(): if attr.names[0].lower() in limitattrs: if not allow_only: raise errors.ObjectclassViolation( info=_('attribute "%(attribute)s" not allowed') % dict( attribute=attr.names[0].lower())) limitattrs.remove(attr.names[0].lower()) if len(limitattrs) > 0 and allow_only: raise errors.ObjectclassViolation( info=_('attribute "%(attribute)s" not allowed') % dict( attribute=limitattrs[0])) class CallbackInterface(Method): """Callback registration interface This class's subclasses allow different types of callbacks to be added and removed to them. Registering a callback is done either by ``register_callback``, or by defining a ``_callback`` method. Subclasses should define the `_callback_registry` attribute as a dictionary mapping allowed callback types to (initially) empty dictionaries. """ _callback_registry = dict() @classmethod def get_callbacks(cls, callback_type): """Yield callbacks of the given type""" # Use one shared callback registry, keyed on class, to avoid problems # with missing attributes being looked up in superclasses callbacks = cls._callback_registry[callback_type].get(cls, [None]) for callback in callbacks: if callback is None: try: yield getattr(cls, '%s_callback' % callback_type) except AttributeError: pass else: yield callback @classmethod def register_callback(cls, callback_type, callback, first=False): """Register a callback :param callback_type: The callback type (e.g. 'pre', 'post') :param callback: The callable added :param first: If true, the new callback will be added before all existing callbacks; otherwise it's added after them Note that callbacks registered this way will be attached to this class only, not to its subclasses. """ assert callable(callback) try: callbacks = cls._callback_registry[callback_type][cls] except KeyError: callbacks = cls._callback_registry[callback_type][cls] = [None] if first: callbacks.insert(0, callback) else: callbacks.append(callback) class BaseLDAPCommand(CallbackInterface, Command): """ Base class for Base LDAP Commands. """ setattr_option = Str('setattr*', validate_set_attribute, cli_name='setattr', doc=_("""Set an attribute to a name/value pair. Format is attr=value. For multi-valued attributes, the command replaces the values already present."""), exclude='webui', ) addattr_option = Str('addattr*', validate_add_attribute, cli_name='addattr', doc=_("""Add an attribute/value pair. Format is attr=value. The attribute must be part of the schema."""), exclude='webui', ) delattr_option = Str('delattr*', validate_del_attribute, cli_name='delattr', doc=_("""Delete an attribute/value pair. The option will be evaluated last, after all sets and adds."""), exclude='webui', ) _callback_registry = dict(pre={}, post={}, exc={}, interactive_prompt={}) def _convert_2_dict(self, ldap, attrs): """ Convert a string in the form of name/value pairs into a dictionary. :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): attrs = [attrs] for a in attrs: m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", a) attr = str(m.group(1)).lower() value = m.group(2) 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] return newdict def process_attr_options(self, entry_attrs, dn, keys, options): """ Process all --setattr, --addattr, and --delattr options and add the resulting value to the list of attributes. --setattr is processed first, then --addattr and finally --delattr. When --setattr is not used then the original LDAP object is looked up (of course, not when dn is None) and the changes are applied to old object values. Attribute values deleted by --delattr may be deleted from attribute values set or added by --setattr, --addattr. For example, the following attributes will result in a NOOP: --addattr=attribute=foo --delattr=attribute=foo AttrValueNotFound exception may be raised when an attribute value was not found either by --setattr and --addattr nor in existing LDAP object. :param entry_attrs: A list of attributes that will be updated :param dn: dn of updated LDAP object or None if a new object is created :param keys: List of command arguments :param options: List of options """ if all(k not in options for k in ("setattr", "addattr", "delattr")): return ldap = self.obj.backend adddict = self._convert_2_dict(ldap, options.get('addattr', [])) setdict = self._convert_2_dict(ldap, options.get('setattr', [])) deldict = self._convert_2_dict(ldap, options.get('delattr', [])) setattrs = set(setdict.keys()) addattrs = set(adddict.keys()) delattrs = set(deldict.keys()) if dn is None: direct_add = addattrs direct_del = delattrs needldapattrs = [] else: assert isinstance(dn, DN) direct_add = setattrs & addattrs direct_del = setattrs & delattrs needldapattrs = list((addattrs | delattrs) - setattrs) for attr, val in setdict.iteritems(): entry_attrs[attr] = val for attr in direct_add: try: val = entry_attrs[attr] except KeyError: val = [] else: if not isinstance(val, (list, tuple)): val = [val] elif isinstance(val, tuple): val = list(val) val.extend(adddict[attr]) entry_attrs[attr] = val for attr in direct_del: for delval in deldict[attr]: try: entry_attrs[attr].remove(delval) except ValueError: raise errors.AttrValueNotFound(attr=attr, value=delval) if needldapattrs: try: (dn, old_entry) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, needldapattrs ) except errors.NotFound: self.obj.handle_not_found(*keys) # Provide a nice error message when user tries to delete an # attribute that does not exist on the entry (and user is not # adding it) names = set(n.lower() for n in old_entry.keys()) del_nonexisting = delattrs - (names | setattrs | addattrs) if del_nonexisting: raise errors.ValidationError(name=del_nonexisting.pop(), error=_('No such attribute on this entry')) for attr in needldapattrs: entry_attrs[attr] = old_entry.get(attr, []) if attr in addattrs: entry_attrs[attr].extend(adddict.get(attr, [])) for delval in deldict.get(attr, []): try: entry_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: if attr in self.params and self.params[attr].attribute: # convert single-value params to scalars param = self.params[attr] value = entry_attrs[attr] if not param.multivalue: if len(value) == 1: value = value[0] elif not value: value = None else: raise errors.OnlyOneValueAllowed(attr=attr) # validate, convert and encode params try: 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] @classmethod def register_pre_callback(cls, callback, first=False): """Shortcut for register_callback('pre', ...)""" cls.register_callback('pre', callback, first) @classmethod def register_post_callback(cls, callback, first=False): """Shortcut for register_callback('post', ...)""" cls.register_callback('post', callback, first) @classmethod def register_exc_callback(cls, callback, first=False): """Shortcut for register_callback('exc', ...)""" cls.register_callback('exc', callback, first) @classmethod def register_interactive_prompt_callback(cls, callback, first=False): """Shortcut for register_callback('interactive_prompt', ...)""" cls.register_callback('interactive_prompt', callback, first) def _exc_wrapper(self, keys, options, call_func): """Function wrapper that automatically calls exception callbacks""" def wrapped(*call_args, **call_kwargs): # call call_func first func = call_func callbacks = list(self.get_callbacks('exc')) while True: try: return func(*call_args, **call_kwargs) except errors.ExecutionError, e: if not callbacks: raise # call exc_callback in the next loop callback = callbacks.pop(0) def exc_func(*args, **kwargs): return callback( self, keys, options, e, call_func, *args, **kwargs) func = exc_func return wrapped def get_options(self): for param in super(BaseLDAPCommand, self).get_options(): yield param if self.obj.attribute_members: for o in self.has_output: if isinstance(o, (output.Entry, output.ListOfEntries)): yield Flag('no_members', doc=_('Suppress processing of membership attributes.'), exclude='webui', flags=['no_option', 'no_output'], ) break class LDAPCreate(BaseLDAPCommand, crud.Create): """ Create a new entry in LDAP. """ takes_options = (BaseLDAPCommand.setattr_option, BaseLDAPCommand.addattr_option) def get_args(self): #pylint: disable=E1003 for key in self.obj.get_ancestor_primary_keys(): yield key if self.obj.primary_key: yield self.obj.primary_key.clone(attribute=True) for arg in super(crud.Create, self).get_args(): yield arg has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend entry_attrs = self.args_options_2_entry(*keys, **options) entry_attrs = ldap.make_entry(DN(), entry_attrs) self.process_attr_options(entry_attrs, None, keys, options) entry_attrs['objectclass'] = deepcopy(self.obj.object_class) if self.obj.object_class_config: config = ldap.get_ipa_config()[1] entry_attrs['objectclass'] = config.get( self.obj.object_class_config, entry_attrs['objectclass'] ) if self.obj.uuid_attribute: entry_attrs[self.obj.uuid_attribute] = 'autogenerate' dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) if self.obj.rdn_attribute: try: dn_attr = dn[0].attr except (IndexError, KeyError): dn_attr = None if dn_attr != self.obj.primary_key.name: self.obj.handle_duplicate_entry(*keys) dn = ldap.make_dn( entry_attrs, self.obj.rdn_attribute, DN(self.obj.container_dn, api.env.basedn) ) if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) attrs_list.update(entry_attrs.keys()) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) for callback in self.get_callbacks('pre'): dn = callback( self, ldap, dn, entry_attrs, attrs_list, *keys, **options) assert isinstance(dn, DN) _check_single_value_attrs(self.params, entry_attrs) _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True) _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False) try: self._exc_wrapper(keys, options, ldap.add_entry)(dn, entry_attrs) except errors.NotFound: parent = self.obj.parent_object if parent: raise errors.NotFound( reason=self.obj.parent_not_found_msg % { 'parent': keys[-2], 'oname': self.api.Object[parent].object_name, } ) raise errors.NotFound( reason=self.obj.container_not_found_msg % { 'container': self.obj.container_dn, } ) except errors.DuplicateEntry: self.obj.handle_duplicate_entry(*keys) try: if self.obj.rdn_attribute: # make sure objectclass is either set or None if self.obj.object_class: object_class = self.obj.object_class else: object_class = None (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.find_entry_by_attr)( self.obj.primary_key.name, keys[-1], object_class, attrs_list, DN(self.obj.container_dn, api.env.basedn) ) assert isinstance(dn, DN) else: (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, attrs_list ) assert isinstance(dn, DN) except errors.NotFound: self.obj.handle_not_found(*keys) for callback in self.get_callbacks('post'): dn = callback(self, ldap, dn, entry_attrs, *keys, **options) self.obj.convert_attribute_members(entry_attrs, *keys, **options) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn if self.obj.primary_key and keys[-1] is not None: return dict(result=entry_attrs, value=keys[-1]) return dict(result=entry_attrs, value=u'') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return # list of attributes we want exported to JSON json_friendly_attributes = ( 'takes_args', ) def __json__(self): json_dict = dict( (a, getattr(self, a)) for a in self.json_friendly_attributes ) json_dict['takes_options'] = list(self.get_json_options()) return json_dict class LDAPQuery(BaseLDAPCommand, crud.PKQuery): """ Base class for commands that need to retrieve an existing entry. """ def get_args(self): #pylint: disable=E1003 for key in self.obj.get_ancestor_primary_keys(): yield key if self.obj.primary_key: yield self.obj.primary_key.clone(attribute=True, query=True) for arg in super(crud.PKQuery, self).get_args(): yield arg # list of attributes we want exported to JSON json_friendly_attributes = ( 'takes_args', ) def __json__(self): json_dict = dict( (a, getattr(self, a)) for a in self.json_friendly_attributes ) json_dict['takes_options'] = list(self.get_json_options()) return json_dict class LDAPMultiQuery(LDAPQuery): """ Base class for commands that need to retrieve one or more existing entries. """ takes_options = ( Flag('continue', cli_name='continue', doc=_('Continuous mode: Don\'t stop on errors.'), ), ) def get_args(self): #pylint: disable=E1003 for key in self.obj.get_ancestor_primary_keys(): yield key if self.obj.primary_key: yield self.obj.primary_key.clone( attribute=True, query=True, multivalue=True ) for arg in super(crud.PKQuery, self).get_args(): yield arg class LDAPRetrieve(LDAPQuery): """ Retrieve an LDAP entry. """ has_output = output.standard_entry has_output_params = global_output_params takes_options = ( Flag('rights', label=_('Rights'), doc=_('Display the access rights of this entry (requires --all). See ipa man page for details.'), ), ) def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, attrs_list, *keys, **options) assert isinstance(dn, DN) try: (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, attrs_list ) assert isinstance(dn, DN) except errors.NotFound: self.obj.handle_not_found(*keys) if options.get('rights', False) and options.get('all', False): entry_attrs['attributelevelrights'] = get_effective_rights(ldap, dn) for callback in self.get_callbacks('post'): dn = callback(self, ldap, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) self.obj.convert_attribute_members(entry_attrs, *keys, **options) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn if self.obj.primary_key and keys[-1] is not None: return dict(result=entry_attrs, value=keys[-1]) return dict(result=entry_attrs, value=u'') def pre_callback(self, ldap, dn, attrs_list, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return class LDAPUpdate(LDAPQuery, crud.Update): """ Update an LDAP entry. """ takes_options = ( BaseLDAPCommand.setattr_option, BaseLDAPCommand.addattr_option, BaseLDAPCommand.delattr_option, Flag('rights', label=_('Rights'), doc=_('Display the access rights of this entry (requires --all). See ipa man page for details.'), ), ) has_output_params = global_output_params def _get_rename_option(self): rdnparam = getattr(self.obj.params, self.obj.primary_key.name) return rdnparam.clone_rename('rename', cli_name='rename', required=False, label=_('Rename'), doc=_('Rename the %(ldap_obj_name)s object') % dict( ldap_obj_name=self.obj.object_name ) ) def get_options(self): for option in super(LDAPUpdate, self).get_options(): yield option if self.obj.rdn_is_primary_key: yield self._get_rename_option() def execute(self, *keys, **options): ldap = self.obj.backend if len(options) == 2: # 'all' and 'raw' are always sent raise errors.EmptyModlist() dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) entry_attrs = self.args_options_2_entry(**options) entry_attrs = ldap.make_entry(dn, entry_attrs) self.process_attr_options(entry_attrs, dn, keys, options) if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) attrs_list.update(entry_attrs.keys()) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) _check_single_value_attrs(self.params, entry_attrs) _check_empty_attrs(self.obj.params, entry_attrs) for callback in self.get_callbacks('pre'): dn = callback( self, ldap, dn, entry_attrs, attrs_list, *keys, **options) assert isinstance(dn, DN) _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True) _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False) rdnupdate = False try: if self.obj.rdn_is_primary_key and 'rename' in options: if not options['rename']: raise errors.ValidationError(name='rename', error=u'can\'t be empty') entry_attrs[self.obj.primary_key.name] = options['rename'] if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs: # RDN change self._exc_wrapper(keys, options, ldap.update_entry_rdn)(dn, RDN((self.obj.primary_key.name, entry_attrs[self.obj.primary_key.name]))) rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], ) dn = self.obj.get_dn(*rdnkeys) assert isinstance(dn, DN) del entry_attrs[self.obj.primary_key.name] options['rdnupdate'] = True rdnupdate = True # Exception callbacks will need to test for options['rdnupdate'] # to decide what to do. An EmptyModlist in this context doesn't # mean an error occurred, just that there were no other updates to # perform. assert isinstance(dn, DN) self._exc_wrapper(keys, options, ldap.update_entry)(dn, entry_attrs) except errors.EmptyModlist, e: if not rdnupdate: raise e except errors.NotFound: self.obj.handle_not_found(*keys) try: (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, attrs_list ) except errors.NotFound: raise errors.MidairCollision( format=_('the entry was deleted while being modified') ) if options.get('rights', False) and options.get('all', False): entry_attrs['attributelevelrights'] = get_effective_rights(ldap, dn) for callback in self.get_callbacks('post'): dn = callback(self, ldap, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) self.obj.convert_attribute_members(entry_attrs, *keys, **options) entry_attrs = entry_to_dict(entry_attrs, **options) if self.obj.primary_key and keys[-1] is not None: return dict(result=entry_attrs, value=keys[-1]) return dict(result=entry_attrs, value=u'') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return class LDAPDelete(LDAPMultiQuery): """ Delete an LDAP entry and all of its direct subentries. """ has_output = output.standard_delete has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend def delete_entry(pkey): nkeys = keys[:-1] + (pkey, ) dn = self.obj.get_dn(*nkeys, **options) assert isinstance(dn, DN) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, *nkeys, **options) assert isinstance(dn, DN) def delete_subtree(base_dn): assert isinstance(base_dn, DN) truncated = True while truncated: try: (subentries, truncated) = ldap.find_entries( None, [''], base_dn, ldap.SCOPE_ONELEVEL ) except errors.NotFound: break else: for (dn_, entry_attrs) in subentries: delete_subtree(dn_) try: self._exc_wrapper(nkeys, options, ldap.delete_entry)(base_dn) except errors.NotFound: self.obj.handle_not_found(*nkeys) try: self._exc_wrapper(nkeys, options, ldap.delete_entry)(dn) except errors.NotFound: self.obj.handle_not_found(*nkeys) except errors.NotAllowedOnNonLeaf: # this entry is not a leaf entry, delete all child nodes delete_subtree(dn) for callback in self.get_callbacks('post'): result = callback(self, ldap, dn, *nkeys, **options) return result if not self.obj.primary_key or not isinstance(keys[-1], (list, tuple)): pkeyiter = (keys[-1], ) else: pkeyiter = keys[-1] deleted = [] failed = [] result = True for pkey in pkeyiter: try: if not delete_entry(pkey): result = False except errors.ExecutionError: if not options.get('continue', False): raise failed.append(pkey) else: deleted.append(pkey) if self.obj.primary_key and pkeyiter[0] is not None: return dict(result=dict(failed=u','.join(failed)), value=u','.join(deleted)) return dict(result=dict(failed=u''), value=u'') def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) return True def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return class LDAPModMember(LDAPQuery): """ Base class for member manipulation. """ member_attributes = ['member'] member_param_doc = _('%s') member_count_out = ('%i member processed.', '%i members processed.') def get_options(self): for option in super(LDAPModMember, self).get_options(): yield option for attr in self.member_attributes: for ldap_obj_name in self.obj.attribute_members[attr]: ldap_obj = self.api.Object[ldap_obj_name] name = to_cli(ldap_obj_name) doc = self.member_param_doc % ldap_obj.object_name_plural yield Str('%s*' % name, cli_name='%ss' % name, doc=doc, label=_('member %s') % ldap_obj.object_name, csv=True, alwaysask=True) def get_member_dns(self, **options): dns = {} failed = {} for attr in self.member_attributes: dns[attr] = {} failed[attr] = {} for ldap_obj_name in self.obj.attribute_members[attr]: dns[attr][ldap_obj_name] = [] failed[attr][ldap_obj_name] = [] names = options.get(to_cli(ldap_obj_name), []) if not names: continue for name in names: if not name: continue ldap_obj = self.api.Object[ldap_obj_name] try: dns[attr][ldap_obj_name].append(ldap_obj.get_dn(name)) except errors.PublicError, e: failed[attr][ldap_obj_name].append((name, unicode(e))) return (dns, failed) class LDAPAddMember(LDAPModMember): """ Add other LDAP entries to members. """ member_param_doc = _('%s to add') member_count_out = ('%i member added.', '%i members added.') allow_same = False has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of members added'), ), ) has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend (member_dns, failed) = self.get_member_dns(**options) dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, member_dns, failed, *keys, **options) assert isinstance(dn, DN) completed = 0 for (attr, objs) in member_dns.iteritems(): for ldap_obj_name in objs: for m_dn in member_dns[attr][ldap_obj_name]: assert isinstance(m_dn, DN) if not m_dn: continue try: ldap.add_entry_to_group(m_dn, dn, attr, allow_same=self.allow_same) except errors.PublicError, e: ldap_obj = self.api.Object[ldap_obj_name] failed[attr][ldap_obj_name].append(( ldap_obj.get_primary_key_from_dn(m_dn), unicode(e),) ) else: completed += 1 if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) attrs_list.update(member_dns.keys()) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) try: (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, attrs_list ) except errors.NotFound: self.obj.handle_not_found(*keys) for callback in self.get_callbacks('post'): (completed, dn) = callback( self, ldap, completed, failed, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) self.obj.convert_attribute_members(entry_attrs, *keys, **options) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn return dict( completed=completed, failed=failed, result=entry_attrs, ) def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return (completed, dn) def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return class LDAPRemoveMember(LDAPModMember): """ Remove LDAP entries from members. """ member_param_doc = _('%s to remove') member_count_out = ('%i member removed.', '%i members removed.') has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be removed'), ), output.Output('completed', type=int, doc=_('Number of members removed'), ), ) has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend (member_dns, failed) = self.get_member_dns(**options) dn = self.obj.get_dn(*keys, **options) assert isinstance(dn, DN) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, member_dns, failed, *keys, **options) assert isinstance(dn, DN) completed = 0 for (attr, objs) in member_dns.iteritems(): for ldap_obj_name, m_dns in objs.iteritems(): for m_dn in m_dns: assert isinstance(m_dn, DN) if not m_dn: continue try: ldap.remove_entry_from_group(m_dn, dn, attr) except errors.PublicError, e: ldap_obj = self.api.Object[ldap_obj_name] failed[attr][ldap_obj_name].append(( ldap_obj.get_primary_key_from_dn(m_dn), unicode(e),) ) else: completed += 1 if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) attrs_list.update(member_dns.keys()) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) # Give memberOf a chance to update entries time.sleep(.3) try: (dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)( dn, attrs_list ) except errors.NotFound: self.obj.handle_not_found(*keys) for callback in self.get_callbacks('post'): (completed, dn) = callback( self, ldap, completed, failed, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) self.obj.convert_attribute_members(entry_attrs, *keys, **options) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn return dict( completed=completed, failed=failed, result=entry_attrs, ) def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return (completed, dn) def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return def gen_pkey_only_option(cli_name): return Flag('pkey_only?', label=_('Primary key only'), doc=_('Results should contain primary key attribute only ("%s")') \ % to_cli(cli_name),) class LDAPSearch(BaseLDAPCommand, crud.Search): """ Retrieve all LDAP entries matching the given criteria. """ member_attributes = [] member_param_incl_doc = _('Search for %(searched_object)s with these %(relationship)s %(ldap_object)s.') member_param_excl_doc = _('Search for %(searched_object)s without these %(relationship)s %(ldap_object)s.') # LDAPSearch sorts all matched records in the end using their primary key # as a key attribute # Set the following attribute to False to turn sorting off sort_result_entries = True takes_options = ( Int('timelimit?', label=_('Time Limit'), doc=_('Time limit of search in seconds'), flags=['no_display'], minvalue=0, autofill=False, ), Int('sizelimit?', label=_('Size Limit'), doc=_('Maximum number of entries returned'), flags=['no_display'], minvalue=0, autofill=False, ), ) def get_args(self): #pylint: disable=E1003 for key in self.obj.get_ancestor_primary_keys(): yield key yield Str('criteria?', noextrawhitespace=False, doc=_('A string searched in all relevant object attributes')) for arg in super(crud.Search, self).get_args(): yield arg def get_member_options(self, attr): for ldap_obj_name in self.obj.attribute_members[attr]: ldap_obj = self.api.Object[ldap_obj_name] relationship = self.obj.relationships.get( attr, ['member', '', 'no_'] ) doc = self.member_param_incl_doc % dict( searched_object=self.obj.object_name_plural, relationship=relationship[0].lower(), ldap_object=ldap_obj.object_name_plural ) name = '%s%s' % (relationship[1], to_cli(ldap_obj_name)) yield Str( '%s*' % name, cli_name='%ss' % name, doc=doc, label=ldap_obj.object_name, csv=True ) doc = self.member_param_excl_doc % dict( searched_object=self.obj.object_name_plural, relationship=relationship[0].lower(), ldap_object=ldap_obj.object_name_plural ) name = '%s%s' % (relationship[2], to_cli(ldap_obj_name)) yield Str( '%s*' % name, cli_name='%ss' % name, doc=doc, label=ldap_obj.object_name, csv=True ) def get_options(self): for option in super(LDAPSearch, self).get_options(): yield option if self.obj.primary_key and \ 'no_output' not in self.obj.primary_key.flags: yield gen_pkey_only_option(self.obj.primary_key.cli_name) for attr in self.member_attributes: for option in self.get_member_options(attr): yield option def get_member_filter(self, ldap, **options): filter = '' for attr in self.member_attributes: for ldap_obj_name in self.obj.attribute_members[attr]: ldap_obj = self.api.Object[ldap_obj_name] relationship = self.obj.relationships.get( attr, ['member', '', 'no_'] ) # Handle positive (MATCH_ALL) and negative (MATCH_NONE) # searches similarly param_prefixes = relationship[1:] # e.g. ('in_', 'not_in_') rules = ldap.MATCH_ALL, ldap.MATCH_NONE for param_prefix, rule in zip(param_prefixes, rules): param_name = '%s%s' % (param_prefix, to_cli(ldap_obj_name)) if options.get(param_name): dns = [] for pkey in options[param_name]: dns.append(ldap_obj.get_dn(pkey)) flt = ldap.make_filter_from_attr(attr, dns, rule) filter = ldap.combine_filters( (filter, flt), ldap.MATCH_ALL ) return filter has_output_params = global_output_params def execute(self, *args, **options): ldap = self.obj.backend term = args[-1] if self.obj.parent_object: base_dn = self.api.Object[self.obj.parent_object].get_dn(*args[:-1]) else: base_dn = DN(self.obj.container_dn, api.env.basedn) assert isinstance(base_dn, DN) search_kw = self.args_options_2_entry(**options) if self.obj.search_display_attributes: defattrs = self.obj.search_display_attributes else: defattrs = self.obj.default_attributes if options.get('pkey_only', False): attrs_list = [self.obj.primary_key.name] elif options.get('all', False): attrs_list = ['*'] + defattrs else: attrs_list = set(defattrs) attrs_list.update(search_kw.keys()) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) if self.obj.search_attributes: search_attrs = self.obj.search_attributes else: search_attrs = self.obj.default_attributes if self.obj.search_attributes_config: config = ldap.get_ipa_config()[1] config_attrs = config.get( self.obj.search_attributes_config, []) if len(config_attrs) == 1 and ( isinstance(config_attrs[0], basestring)): search_attrs = config_attrs[0].split(',') search_kw['objectclass'] = self.obj.object_class attr_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL) search_kw = {} for a in search_attrs: search_kw[a] = term term_filter = ldap.make_filter(search_kw, exact=False) member_filter = self.get_member_filter(ldap, **options) filter = ldap.combine_filters( (term_filter, attr_filter, member_filter), rules=ldap.MATCH_ALL ) scope = ldap.SCOPE_ONELEVEL for callback in self.get_callbacks('pre'): (filter, base_dn, scope) = callback( self, ldap, filter, attrs_list, base_dn, scope, *args, **options) assert isinstance(base_dn, DN) try: (entries, truncated) = self._exc_wrapper(args, options, ldap.find_entries)( filter, attrs_list, base_dn, scope, time_limit=options.get('timelimit', None), size_limit=options.get('sizelimit', None) ) except errors.NotFound: (entries, truncated) = ([], False) for callback in self.get_callbacks('post'): truncated = callback(self, ldap, entries, truncated, *args, **options) if self.sort_result_entries: if self.obj.primary_key: def sort_key(x): return x[1][self.obj.primary_key.name][0].lower() entries.sort(key=sort_key) if not options.get('raw', False): for e in entries: self.obj.convert_attribute_members(e[1], *args, **options) for (i, e) in enumerate(entries): entries[i] = entry_to_dict(e, **options) entries[i]['dn'] = e.dn return dict( result=entries, count=len(entries), truncated=truncated, ) def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) return (filters, base_dn, scope) def post_callback(self, ldap, entries, truncated, *args, **options): return truncated def exc_callback(self, args, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return # list of attributes we want exported to JSON json_friendly_attributes = ( 'takes_args', ) def __json__(self): json_dict = dict( (a, getattr(self, a)) for a in self.json_friendly_attributes ) json_dict['takes_options'] = list(self.get_json_options()) return json_dict class LDAPModReverseMember(LDAPQuery): """ Base class for reverse member manipulation. """ reverse_attributes = ['member'] reverse_param_doc = _('%s') reverse_count_out = ('%i member processed.', '%i members processed.') has_output_params = global_output_params def get_options(self): for option in super(LDAPModReverseMember, self).get_options(): yield option for attr in self.reverse_attributes: for ldap_obj_name in self.obj.reverse_members[attr]: ldap_obj = self.api.Object[ldap_obj_name] name = to_cli(ldap_obj_name) doc = self.reverse_param_doc % ldap_obj.object_name_plural yield Str('%s*' % name, cli_name='%ss' % name, doc=doc, label=ldap_obj.object_name, csv=True, alwaysask=True) class LDAPAddReverseMember(LDAPModReverseMember): """ Add other LDAP entries to members in reverse. The call looks like "add A to B" but in fact executes add B to A to handle reverse membership. """ member_param_doc = _('%s to add') member_count_out = ('%i member added.', '%i members added.') show_command = None member_command = None reverse_attr = None member_attr = None has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of members added'), ), ) has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend # Ensure our target exists result = self.api.Command[self.show_command](keys[-1])['result'] dn = result['dn'] assert isinstance(dn, DN) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, *keys, **options) assert isinstance(dn, DN) if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) # Pull the record as it is now so we can know how many members # there are. entry_start = self.api.Command[self.show_command](keys[-1])['result'] completed = 0 failed = {'member': {self.reverse_attr: []}} for attr in options.get(self.reverse_attr) or []: try: options = {'%s' % self.member_attr: keys[-1]} try: result = self._exc_wrapper(keys, options, self.api.Command[self.member_command])(attr, **options) if result['completed'] == 1: completed = completed + 1 else: failed['member'][self.reverse_attr].append((attr, result['failed']['member'][self.member_attr][0][1])) except errors.NotFound, e: msg = str(e) (attr, msg) = msg.split(':', 1) failed['member'][self.reverse_attr].append((attr, unicode(msg.strip()))) except errors.PublicError, e: failed['member'][self.reverse_attr].append((attr, unicode(msg))) # Update the member data. (dn, entry_attrs) = ldap.get_entry(dn, ['*']) self.obj.convert_attribute_members(entry_attrs, *keys, **options) for callback in self.get_callbacks('post'): (completed, dn) = callback( self, ldap, completed, failed, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn return dict( completed=completed, failed=failed, result=entry_attrs, ) def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return (completed, dn) def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return class LDAPRemoveReverseMember(LDAPModReverseMember): """ Remove other LDAP entries from members in reverse. The call looks like "remove A from B" but in fact executes remove B from A to handle reverse membership. """ member_param_doc = _('%s to remove') member_count_out = ('%i member removed.', '%i members removed.') show_command = None member_command = None reverse_attr = None member_attr = None has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be removed'), ), output.Output('completed', type=int, doc=_('Number of members removed'), ), ) has_output_params = global_output_params def execute(self, *keys, **options): ldap = self.obj.backend # Ensure our target exists result = self.api.Command[self.show_command](keys[-1])['result'] dn = result['dn'] assert isinstance(dn, DN) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, *keys, **options) assert isinstance(dn, DN) if options.get('all', False): attrs_list = ['*'] + self.obj.default_attributes else: attrs_list = set(self.obj.default_attributes) if options.get('no_members', False): attrs_list.difference_update(self.obj.attribute_members) attrs_list = list(attrs_list) # Pull the record as it is now so we can know how many members # there are. entry_start = self.api.Command[self.show_command](keys[-1])['result'] completed = 0 failed = {'member': {self.reverse_attr: []}} for attr in options.get(self.reverse_attr) or []: try: options = {'%s' % self.member_attr: keys[-1]} try: result = self._exc_wrapper(keys, options, self.api.Command[self.member_command])(attr, **options) if result['completed'] == 1: completed = completed + 1 else: failed['member'][self.reverse_attr].append((attr, result['failed']['member'][self.member_attr][0][1])) except errors.NotFound, e: msg = str(e) (attr, msg) = msg.split(':', 1) failed['member'][self.reverse_attr].append((attr, unicode(msg.strip()))) except errors.PublicError, e: failed['member'][self.reverse_attr].append((attr, unicode(msg))) # Update the member data. (dn, entry_attrs) = ldap.get_entry(dn, ['*']) self.obj.convert_attribute_members(entry_attrs, *keys, **options) for callback in self.get_callbacks('post'): (completed, dn) = callback( self, ldap, completed, failed, dn, entry_attrs, *keys, **options) assert isinstance(dn, DN) assert isinstance(dn, DN) entry_attrs = entry_to_dict(entry_attrs, **options) entry_attrs['dn'] = dn return dict( completed=completed, failed=failed, result=entry_attrs, ) def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) return dn def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return (completed, dn) def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): raise exc def interactive_prompt_callback(self, kw): return freeipa-3.3.4/ipalib/plugins/hbacrule.py0000664000175000017500000004025712271663206017577 0ustar mkosekmkosek# Authors: # Pavel Zuna # # Copyright (C) 2009 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 . from ipalib import api, errors from ipalib import AccessTime, Password, Str, StrEnum, Bool, DeprecatedParam from ipalib.plugins.baseldap import * from ipalib import _, ngettext __doc__ = _(""" Host-based access control Control who can access what services on what hosts. You can use HBAC to control which users or groups can access a service, or group of services, on a target host. You can also specify a category of users and target hosts. This is currently limited to "all", but might be expanded in the future. Target hosts in HBAC rules must be hosts managed by IPA. The available services and groups of services are controlled by the hbacsvc and hbacsvcgroup plug-ins respectively. EXAMPLES: Create a rule, "test1", that grants all users access to the host "server" from anywhere: ipa hbacrule-add --usercat=all test1 ipa hbacrule-add-host --hosts=server.example.com test1 Display the properties of a named HBAC rule: ipa hbacrule-show test1 Create a rule for a specific service. This lets the user john access the sshd service on any machine from any machine: ipa hbacrule-add --hostcat=all john_sshd ipa hbacrule-add-user --users=john john_sshd ipa hbacrule-add-service --hbacsvcs=sshd john_sshd Create a rule for a new service group. This lets the user john access the FTP service on any machine from any machine: ipa hbacsvcgroup-add ftpers ipa hbacsvc-add sftp ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers ipa hbacrule-add --hostcat=all john_ftp ipa hbacrule-add-user --users=john john_ftp ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp Disable a named HBAC rule: ipa hbacrule-disable test1 Remove a named HBAC rule: ipa hbacrule-del allow_server """) # AccessTime support is being removed for now. # # You can also control the times that the rule is active. # # The access time(s) of a host are cumulative and are not guaranteed to be # applied in the order displayed. # # Specify that the rule "test1" be active every day between 0800 and 1400: # ipa hbacrule-add-accesstime --time='periodic daily 0800-1400' test1 # # Specify that the rule "test1" be active once, from 10:32 until 10:33 on # December 16, 2010: # ipa hbacrule-add-accesstime --time='absolute 201012161032 ~ 201012161033' test1 topic = ('hbac', _('Host-based access control commands')) def validate_type(ugettext, type): if type.lower() == 'deny': raise errors.ValidationError(name='type', error=_('The deny type has been deprecated.')) def is_all(options, attribute): """ See if options[attribute] is lower-case 'all' in a safe way. """ if attribute in options and options[attribute] is not None: if type(options[attribute]) in (list, tuple): value = options[attribute][0].lower() else: value = options[attribute].lower() if value == 'all': return True else: return False class hbacrule(LDAPObject): """ HBAC object. """ container_dn = api.env.container_hbac object_name = _('HBAC rule') object_name_plural = _('HBAC rules') object_class = ['ipaassociation', 'ipahbacrule'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'sourcehostcategory', 'servicecategory', 'ipaenabledflag', 'memberuser', 'sourcehost', 'memberhost', 'memberservice', 'memberhostgroup', 'externalhost', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'sourcehost': ['host', 'hostgroup'], 'memberservice': ['hbacsvc', 'hbacsvcgroup'], } label = _('HBAC Rules') label_singular = _('HBAC Rule') takes_params = ( Str('cn', cli_name='name', label=_('Rule name'), primary_key=True, ), StrEnum('accessruletype', validate_type, cli_name='type', doc=_('Rule type (allow)'), label=_('Rule type'), values=(u'allow', u'deny'), default=u'allow', autofill=True, exclude='webui', flags=['no_option', 'no_output'], ), # FIXME: {user,host,service}categories should expand in the future StrEnum('usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum('hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), DeprecatedParam('sourcehostcategory?'), StrEnum('servicecategory?', cli_name='servicecat', label=_('Service category'), doc=_('Service category the rule applies to'), values=(u'all', ), ), # AccessTime('accesstime?', # cli_name='time', # label=_('Access time'), # ), Str('description?', cli_name='desc', label=_('Description'), ), Bool('ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str('memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), DeprecatedParam('sourcehost_host?'), DeprecatedParam('sourcehost_hostgroup?'), Str('memberservice_hbacsvc?', label=_('Services'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberservice_hbacsvcgroup?', label=_('Service Groups'), flags=['no_create', 'no_update', 'no_search'], ), external_host_param, ) api.register(hbacrule) class hbacrule_add(LDAPCreate): __doc__ = _('Create a new HBAC rule.') msg_summary = _('Added HBAC rule "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # HBAC rules are enabled by default entry_attrs['ipaenabledflag'] = 'TRUE' return dn api.register(hbacrule_add) class hbacrule_del(LDAPDelete): __doc__ = _('Delete an HBAC rule.') msg_summary = _('Deleted HBAC rule "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) kw = dict(seealso=keys[0]) _entries = api.Command.selinuxusermap_find(None, **kw) if _entries['count']: raise errors.DependentEntry(key=keys[0], label=self.api.Object['selinuxusermap'].label_singular, dependent=_entries['result'][0]['cn'][0]) return dn api.register(hbacrule_del) class hbacrule_mod(LDAPUpdate): __doc__ = _('Modify an HBAC rule.') msg_summary = _('Modified HBAC rule "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(options, 'usercategory') and 'memberuser' in entry_attrs: raise errors.MutuallyExclusiveError(reason=_("user category cannot be set to 'all' while there are allowed users")) if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs: raise errors.MutuallyExclusiveError(reason=_("host category cannot be set to 'all' while there are allowed hosts")) if is_all(options, 'servicecategory') and 'memberservice' in entry_attrs: raise errors.MutuallyExclusiveError(reason=_("service category cannot be set to 'all' while there are allowed services")) return dn api.register(hbacrule_mod) class hbacrule_find(LDAPSearch): __doc__ = _('Search for HBAC rules.') msg_summary = ngettext( '%(count)d HBAC rule matched', '%(count)d HBAC rules matched', 0 ) api.register(hbacrule_find) class hbacrule_show(LDAPRetrieve): __doc__ = _('Display the properties of an HBAC rule.') api.register(hbacrule_show) class hbacrule_enable(LDAPQuery): __doc__ = _('Enable an HBAC rule.') msg_summary = _('Enabled HBAC rule "%(value)s"') has_output = output.standard_value def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'TRUE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) return dict( result=True, value=cn, ) api.register(hbacrule_enable) class hbacrule_disable(LDAPQuery): __doc__ = _('Disable an HBAC rule.') msg_summary = _('Disabled HBAC rule "%(value)s"') has_output = output.standard_value def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) entry_attrs = {'ipaenabledflag': 'FALSE'} try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) return dict( result=True, value=cn, ) api.register(hbacrule_disable) class hbacrule_add_accesstime(LDAPQuery): """ Add an access time to an HBAC rule. """ takes_options = ( AccessTime('accesstime', cli_name='time', label=_('Access time'), ), ) def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) (dn, entry_attrs) = ldap.get_entry(dn, ['accesstime']) entry_attrs.setdefault('accesstime', []).append( options['accesstime'] ) try: ldap.update_entry(dn, entry_attrs) except errors.EmptyModlist: pass except errors.NotFound: self.obj.handle_not_found(cn) return dict(result=True) def output_for_cli(self, textui, result, cn, **options): textui.print_name(self.name) textui.print_dashed( 'Added access time "%s" to HBAC rule "%s"' % ( options['accesstime'], cn ) ) #api.register(hbacrule_add_accesstime) class hbacrule_remove_accesstime(LDAPQuery): """ Remove access time to HBAC rule. """ takes_options = ( AccessTime('accesstime?', cli_name='time', label=_('Access time'), ), ) def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) (dn, entry_attrs) = ldap.get_entry(dn, ['accesstime']) try: entry_attrs.setdefault('accesstime', []).remove( options['accesstime'] ) ldap.update_entry(dn, entry_attrs) except (ValueError, errors.EmptyModlist): pass except errors.NotFound: self.obj.handle_not_found(cn) return dict(result=True) def output_for_cli(self, textui, result, cn, **options): textui.print_name(self.name) textui.print_dashed( 'Removed access time "%s" from HBAC rule "%s"' % ( options['accesstime'], cn ) ) #api.register(hbacrule_remove_accesstime) class hbacrule_add_user(LDAPAddMember): __doc__ = _('Add users and groups to an HBAC rule.') member_attributes = ['memberuser'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercategory' in entry_attrs and \ entry_attrs['usercategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError( reason=_("users cannot be added when user category='all'")) return dn api.register(hbacrule_add_user) class hbacrule_remove_user(LDAPRemoveMember): __doc__ = _('Remove users and groups from an HBAC rule.') member_attributes = ['memberuser'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(hbacrule_remove_user) class hbacrule_add_host(LDAPAddMember): __doc__ = _('Add target hosts and hostgroups to an HBAC rule.') member_attributes = ['memberhost'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'hostcategory' in entry_attrs and \ entry_attrs['hostcategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError( reason=_("hosts cannot be added when host category='all'")) return dn api.register(hbacrule_add_host) class hbacrule_remove_host(LDAPRemoveMember): __doc__ = _('Remove target hosts and hostgroups from an HBAC rule.') member_attributes = ['memberhost'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(hbacrule_remove_host) class hbacrule_add_sourcehost(LDAPAddMember): NO_CLI = True member_attributes = ['sourcehost'] member_count_out = ('%i object added.', '%i objects added.') def validate(self, **kw): raise errors.DeprecationError(name='hbacrule_add_sourcehost') api.register(hbacrule_add_sourcehost) class hbacrule_remove_sourcehost(LDAPRemoveMember): NO_CLI = True member_attributes = ['sourcehost'] member_count_out = ('%i object removed.', '%i objects removed.') def validate(self, **kw): raise errors.DeprecationError(name='hbacrule_remove_sourcehost') api.register(hbacrule_remove_sourcehost) class hbacrule_add_service(LDAPAddMember): __doc__ = _('Add services to an HBAC rule.') member_attributes = ['memberservice'] member_count_out = ('%i object added.', '%i objects added.') def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) if 'servicecategory' in entry_attrs and \ entry_attrs['servicecategory'][0].lower() == 'all': raise errors.MutuallyExclusiveError(reason=_( "services cannot be added when service category='all'")) return dn api.register(hbacrule_add_service) class hbacrule_remove_service(LDAPRemoveMember): __doc__ = _('Remove service and service groups from an HBAC rule.') member_attributes = ['memberservice'] member_count_out = ('%i object removed.', '%i objects removed.') api.register(hbacrule_remove_service) freeipa-3.3.4/ipalib/plugins/config.py0000664000175000017500000003071312271663206017253 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # 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 . from ipalib import api from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam from ipalib.plugins.baseldap import * from ipalib.plugins.selinuxusermap import validate_selinuxuser from ipalib import _ from ipalib.errors import ValidationError # 389-ds attributes that should be skipped in attribute checks OPERATIONAL_ATTRIBUTES = ('nsaccountlock', 'member', 'memberof', 'memberindirect', 'memberofindirect',) __doc__ = _(""" Server configuration Manage the default values that IPA uses and some of its tuning parameters. NOTES: The password notification value (--pwdexpnotify) is stored here so it will be replicated. It is not currently used to notify users in advance of an expiring password. Some attributes are read-only, provided only for information purposes. These include: Certificate Subject base: the configured certificate subject base, e.g. O=EXAMPLE.COM. This is configurable only at install time. Password plug-in features: currently defines additional hashes that the password will generate (there may be other conditions). When setting the order list for mapping SELinux users you may need to quote the value so it isn't interpreted by the shell. EXAMPLES: Show basic server configuration: ipa config-show Show all configuration options: ipa config-show --all Change maximum username length to 99 characters: ipa config-mod --maxusername=99 Increase default time and size limits for maximum IPA server search: ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000 Set default user e-mail domain: ipa config-mod --emaildomain=example.com Enable migration mode to make "ipa migrate-ds" command operational: ipa config-mod --enable-migration=TRUE Define SELinux user map order: ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023' """) def validate_searchtimelimit(ugettext, limit): if limit == 0: raise ValidationError(name='ipasearchtimelimit', error=_('searchtimelimit must be -1 or > 1.')) return None class config(LDAPObject): """ IPA configuration object """ object_name = _('configuration options') default_attributes = [ 'ipamaxusernamelength', 'ipahomesrootdir', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipadefaultemaildomain', 'ipasearchtimelimit', 'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields', 'ipamigrationenabled', 'ipacertificatesubjectbase', 'ipapwdexpadvnotify', 'ipaselinuxusermaporder', 'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata', ] label = _('Configuration') label_singular = _('Configuration') takes_params = ( Int('ipamaxusernamelength', cli_name='maxusername', label=_('Maximum username length'), minvalue=1, ), IA5Str('ipahomesrootdir', cli_name='homedirectory', label=_('Home directory base'), doc=_('Default location of home directories'), ), Str('ipadefaultloginshell', cli_name='defaultshell', label=_('Default shell'), doc=_('Default shell for new users'), ), Str('ipadefaultprimarygroup', cli_name='defaultgroup', label=_('Default users group'), doc=_('Default group for new users'), ), Str('ipadefaultemaildomain?', cli_name='emaildomain', label=_('Default e-mail domain'), doc=_('Default e-mail domain'), ), Int('ipasearchtimelimit', validate_searchtimelimit, cli_name='searchtimelimit', label=_('Search time limit'), doc=_('Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)'), minvalue=-1, ), Int('ipasearchrecordslimit', cli_name='searchrecordslimit', label=_('Search size limit'), doc=_('Maximum number of records to search (-1 is unlimited)'), minvalue=-1, ), IA5Str('ipausersearchfields', cli_name='usersearch', label=_('User search fields'), doc=_('A comma-separated list of fields to search in when searching for users'), ), IA5Str('ipagroupsearchfields', cli_name='groupsearch', label='Group search fields', doc=_('A comma-separated list of fields to search in when searching for groups'), ), Bool('ipamigrationenabled', cli_name='enable_migration', label=_('Enable migration mode'), doc=_('Enable migration mode'), ), DNParam('ipacertificatesubjectbase', cli_name='subject', label=_('Certificate Subject base'), doc=_('Base for certificate subjects (OU=Test,O=Example)'), flags=['no_update'], ), Str('ipagroupobjectclasses+', cli_name='groupobjectclasses', label=_('Default group objectclasses'), doc=_('Default group objectclasses (comma-separated list)'), csv=True, ), Str('ipauserobjectclasses+', cli_name='userobjectclasses', label=_('Default user objectclasses'), doc=_('Default user objectclasses (comma-separated list)'), csv=True, ), Int('ipapwdexpadvnotify', cli_name='pwdexpnotify', label=_('Password Expiration Notification (days)'), doc=_('Number of days\'s notice of impending password expiration'), minvalue=0, ), StrEnum('ipaconfigstring*', cli_name='ipaconfigstring', label=_('Password plugin features'), doc=_('Extra hashes to generate in password plug-in'), values=(u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout'), csv=True, ), Str('ipaselinuxusermaporder', label=_('SELinux user map order'), doc=_('Order in increasing priority of SELinux users, delimited by $'), ), Str('ipaselinuxusermapdefault?', label=_('Default SELinux user'), doc=_('Default SELinux user when no match is found in SELinux map rule'), ), StrEnum('ipakrbauthzdata*', cli_name='pac_type', label=_('Default PAC types'), doc=_('Default types of PAC supported for services'), values=(u'MS-PAC', u'PAD', u'nfs:NONE'), csv=True, ), ) def get_dn(self, *keys, **kwargs): return DN(('cn', 'ipaconfig'), ('cn', 'etc'), api.env.basedn) api.register(config) class config_mod(LDAPUpdate): __doc__ = _('Modify configuration options.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if 'ipadefaultprimarygroup' in entry_attrs: group=entry_attrs['ipadefaultprimarygroup'] try: api.Object['group'].get_dn_if_exists(group) except errors.NotFound: raise errors.NotFound(message=_("The group doesn't exist")) kw = {} if 'ipausersearchfields' in entry_attrs: kw['ipausersearchfields'] = 'ipauserobjectclasses' if 'ipagroupsearchfields' in entry_attrs: kw['ipagroupsearchfields'] = 'ipagroupobjectclasses' if kw: config = ldap.get_ipa_config(kw.values()) for (k, v) in kw.iteritems(): allowed_attrs = ldap.get_allowed_attributes(config[1][v]) fields = entry_attrs[k].split(',') for a in fields: a = a.strip() if a not in allowed_attrs: raise errors.ValidationError( name=k, error=_('attribute "%s" not allowed') % a ) for (attr, obj) in (('ipauserobjectclasses', 'user'), ('ipagroupobjectclasses', 'group')): if attr in entry_attrs: if not entry_attrs[attr]: raise errors.ValidationError(name=attr, error=_('May not be empty')) objectclasses = list(set(entry_attrs[attr]).union( self.api.Object[obj].possible_objectclasses)) new_allowed_attrs = ldap.get_allowed_attributes(objectclasses, raise_on_unknown=True) checked_attrs = self.api.Object[obj].default_attributes if self.api.Object[obj].uuid_attribute: checked_attrs = checked_attrs + [self.api.Object[obj].uuid_attribute] for obj_attr in checked_attrs: if obj_attr in OPERATIONAL_ATTRIBUTES: continue if obj_attr in self.api.Object[obj].params and \ 'virtual_attribute' in \ self.api.Object[obj].params[obj_attr].flags: # skip virtual attributes continue if obj_attr not in new_allowed_attrs: raise errors.ValidationError(name=attr, error=_('%(obj)s default attribute %(attr)s would not be allowed!') \ % dict(obj=obj, attr=obj_attr)) if ('ipaselinuxusermapdefault' in entry_attrs or 'ipaselinuxusermaporder' in entry_attrs): config = None failedattr = 'ipaselinuxusermaporder' if 'ipaselinuxusermapdefault' in entry_attrs: defaultuser = entry_attrs['ipaselinuxusermapdefault'] failedattr = 'ipaselinuxusermapdefault' # validate the new default user first if defaultuser is not None: error_message = validate_selinuxuser(_, defaultuser) if error_message: raise errors.ValidationError(name='ipaselinuxusermapdefault', error=error_message) else: config = ldap.get_ipa_config()[1] defaultuser = config.get('ipaselinuxusermapdefault', [None])[0] if 'ipaselinuxusermaporder' in entry_attrs: order = entry_attrs['ipaselinuxusermaporder'] userlist = order.split('$') # validate the new user order first for user in userlist: if not user: raise errors.ValidationError(name='ipaselinuxusermaporder', error=_('A list of SELinux users delimited by $ expected')) error_message = validate_selinuxuser(_, user) if error_message: error_message = _("SELinux user '%(user)s' is not " "valid: %(error)s") % dict(user=user, error=error_message) raise errors.ValidationError(name='ipaselinuxusermaporder', error=error_message) else: if not config: config = ldap.get_ipa_config()[1] order = config['ipaselinuxusermaporder'] userlist = order[0].split('$') if defaultuser and defaultuser not in userlist: raise errors.ValidationError(name=failedattr, error=_('SELinux user map default user not in order list')) return dn api.register(config_mod) class config_show(LDAPRetrieve): __doc__ = _('Show the current configuration.') api.register(config_show) freeipa-3.3.4/ipalib/plugins/netgroup.py0000664000175000017500000002315612271663206017654 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # Copyright (C) 2009 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 . from ipalib import api, errors from ipalib import Str, StrEnum from ipalib.plugins.baseldap import * from ipalib import _, ngettext from ipalib.plugins.hbacrule import is_all __doc__ = _(""" Netgroups A netgroup is a group used for permission checking. It can contain both user and host values. EXAMPLES: Add a new netgroup: ipa netgroup-add --desc="NFS admins" admins Add members to the netgroup: ipa netgroup-add-member --users=tuser1 --users=tuser2 admins Remove a member from the netgroup: ipa netgroup-remove-member --users=tuser2 admins Display information about a netgroup: ipa netgroup-show admins Delete a netgroup: ipa netgroup-del admins """) NETGROUP_PATTERN='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*$' NETGROUP_PATTERN_ERRMSG='may only include letters, numbers, _, -, and .' # according to most common use cases the netgroup pattern should fit # also the nisdomain pattern NISDOMAIN_PATTERN=NETGROUP_PATTERN NISDOMAIN_PATTERN_ERRMSG=NETGROUP_PATTERN_ERRMSG output_params = ( Str('memberuser_user?', label='Member User', ), Str('memberuser_group?', label='Member Group', ), Str('memberhost_host?', label=_('Member Host'), ), Str('memberhost_hostgroup?', label='Member Hostgroup', ), ) class netgroup(LDAPObject): """ Netgroup object. """ container_dn = api.env.container_netgroup object_name = _('netgroup') object_name_plural = _('netgroups') object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup'] default_attributes = [ 'cn', 'description', 'memberof', 'externalhost', 'nisdomainname', 'memberuser', 'memberhost', 'member', 'memberindirect', 'usercategory', 'hostcategory', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'member': ['netgroup'], 'memberof': ['netgroup'], 'memberindirect': ['netgroup'], 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } relationships = { 'member': ('Member', '', 'no_'), 'memberof': ('Member Of', 'in_', 'not_in_'), 'memberindirect': ( 'Indirect Member', None, 'no_indirect_' ), 'memberuser': ('Member', '', 'no_'), 'memberhost': ('Member', '', 'no_'), } label = _('Netgroups') label_singular = _('Netgroup') takes_params = ( Str('cn', pattern=NETGROUP_PATTERN, pattern_errmsg=NETGROUP_PATTERN_ERRMSG, cli_name='name', label=_('Netgroup name'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description', cli_name='desc', label=_('Description'), doc=_('Netgroup description'), ), Str('nisdomainname?', pattern=NISDOMAIN_PATTERN, pattern_errmsg=NISDOMAIN_PATTERN_ERRMSG, cli_name='nisdomain', label=_('NIS domain name'), ), Str('ipauniqueid?', cli_name='uuid', label='IPA unique ID', doc=_('IPA unique ID'), flags=['no_create', 'no_update'], ), StrEnum('usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum('hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), external_host_param, ) api.register(netgroup) class netgroup_add(LDAPCreate): __doc__ = _('Add a new netgroup.') has_output_params = LDAPCreate.has_output_params + output_params msg_summary = _('Added netgroup "%(value)s"') msg_collision = _(u'hostgroup with name "%s" already exists. ' \ u'Hostgroups and netgroups share a common namespace') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) entry_attrs.setdefault('nisdomainname', self.api.env.domain) try: test_dn = self.obj.get_dn(keys[-1]) (test_dn_, netgroup) = ldap.get_entry(test_dn, ['objectclass']) if 'mepManagedEntry' in netgroup.get('objectclass', []): raise errors.DuplicateEntry(message=unicode(self.msg_collision % keys[-1])) else: self.obj.handle_duplicate_entry(*keys) except errors.NotFound: pass try: # when enabled, a managed netgroup is created for every hostgroup # make sure that we don't create a collision if the plugin is # (temporarily) disabled api.Object['hostgroup'].get_dn_if_exists(keys[-1]) raise errors.DuplicateEntry(message=unicode(self.msg_collision % keys[-1])) except errors.NotFound: pass return dn api.register(netgroup_add) class netgroup_del(LDAPDelete): __doc__ = _('Delete a netgroup.') msg_summary = _('Deleted netgroup "%(value)s"') api.register(netgroup_del) class netgroup_mod(LDAPUpdate): __doc__ = _('Modify a netgroup.') has_output_params = LDAPUpdate.has_output_params + output_params msg_summary = _('Modified netgroup "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) except errors.NotFound: self.obj.handle_not_found(*keys) if is_all(options, 'usercategory') and 'memberuser' in entry_attrs: raise errors.MutuallyExclusiveError(reason=_("user category cannot be set to 'all' while there are allowed users")) if is_all(options, 'hostcategory') and 'memberhost' in entry_attrs: raise errors.MutuallyExclusiveError(reason=_("host category cannot be set to 'all' while there are allowed hosts")) return dn api.register(netgroup_mod) class netgroup_find(LDAPSearch): __doc__ = _('Search for a netgroup.') member_attributes = ['member', 'memberuser', 'memberhost', 'memberof'] has_output_params = LDAPSearch.has_output_params + output_params msg_summary = ngettext( '%(count)d netgroup matched', '%(count)d netgroups matched', 0 ) takes_options = LDAPSearch.takes_options + ( Flag('private', exclude='webui', flags=['no_option', 'no_output'], ), Flag('managed', cli_name='managed', doc=_('search for managed groups'), default_from=lambda private: private, ), ) def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) # Do not display private mepManagedEntry netgroups by default # If looking for managed groups, we need to omit the negation search filter search_kw = {} search_kw['objectclass'] = ['mepManagedEntry'] if not options['managed']: local_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_NONE) else: local_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL) filter = ldap.combine_filters((local_filter, filter), rules=ldap.MATCH_ALL) return (filter, base_dn, scope) api.register(netgroup_find) class netgroup_show(LDAPRetrieve): __doc__ = _('Display information about a netgroup.') has_output_params = LDAPRetrieve.has_output_params + output_params api.register(netgroup_show) class netgroup_add_member(LDAPAddMember): __doc__ = _('Add members to a netgroup.') member_attributes = ['memberuser', 'memberhost', 'member'] has_output_params = LDAPAddMember.has_output_params + output_params def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) return add_external_pre_callback('host', ldap, dn, keys, options) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(netgroup_add_member) class netgroup_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from a netgroup.') member_attributes = ['memberuser', 'memberhost', 'member'] has_output_params = LDAPRemoveMember.has_output_params + output_params def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options) api.register(netgroup_remove_member) freeipa-3.3.4/ipalib/plugins/automember.pyc0000664000175000017500000004627712271707517020331 0ustar mkosekmkosekó †fçRc @sddlmZmZddlmZmZddlTddlmZmZddlm Z ddl Z ddl m Z edƒZd Zd Zed d d dedƒdedƒdedeƒedd ddedƒdedƒdedeƒeddedƒdedƒddddgƒfZeddedƒdedƒd d?ƒfZed#d d$ded%ƒded%ƒd&d'„ƒfZd(efd)„ƒYZejeƒd*„Zd+efd,„ƒYZejeƒd-efd.„ƒYZejeƒd/efd0„ƒYZejeƒd1efd2„ƒYZejeƒd3efd4„ƒYZ eje ƒd5e!fd6„ƒYZ"eje"ƒd7e#fd8„ƒYZ$eje$ƒd9efd:„ƒYZ%eje%ƒd;efd<„ƒYZ&eje&ƒd=e#fd>„ƒYZ'eje'ƒdS(@iÿÿÿÿ(tapiterrors(tStrtStrEnum(t*(t_tngettext(tcontextN(tDNsU Auto Membership Rule. Bring clarity to the membership of hosts and users by configuring inclusive or exclusive regex patterns, you can automatically assign a new entries into a group or hostgroup based upon attribute information. A rule is directly associated with a group by name, so you cannot create a rule without an accompanying group or hostgroup. A condition is a regular expression used by 389-ds to match a new incoming entry with an automember rule. If it matches an inclusive rule then the entry is added to the appropriate group or hostgroup. A default group or hostgroup could be specified for entries that do not match any rule. In case of user entries this group will be a fallback group because all users are by default members of group specified in IPA config. EXAMPLES: Add the initial group or hostgroup: ipa hostgroup-add --desc="Web Servers" webservers ipa group-add --desc="Developers" devel Add the initial rule: ipa automember-add --type=hostgroup webservers ipa automember-add --type=group devel Add a condition to the rule: ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers ipa automember-add-condition --key=manager --type=group --inclusive-regex=^uid=mscott devel Add an exclusive condition to the rule to prevent auto assignment: ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-regex=^web5\.example\.com webservers Add a host: ipa host-add web1.example.com Add a user: ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott Verify automembership: ipa hostgroup-show webservers Host-group: webservers Description: Web Servers Member hosts: web1.example.com ipa group-show devel Group name: devel Description: Developers GID: 1004200000 Member users: tuser Remove a condition from the rule: ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers Modify the automember rule: ipa automember-mod Set the default (fallback) target group: ipa automember-default-group-set --default-group=webservers --type=hostgroup ipa automember-default-group-set --default-group=ipausers --type=group Remove the default (fallback) target group: ipa automember-default-group-remove --type=hostgroup ipa automember-default-group-remove --type=group Show the default (fallback) target group: ipa automember-default-group-show --type=hostgroup ipa automember-default-group-show --type=group Find all of the automember rules: ipa automember-find Display a automember rule: ipa automember-show --type=hostgroup webservers ipa automember-show --type=group devel Delete an automember rule: ipa automember-del --type=hostgroup webservers ipa automember-del --type=group devel tautomemberinclusiveregextautomemberexclusiveregexsautomemberinclusiveregex*tcli_nametinclusive_regextlabelsInclusive Regextdoctcsvt alwaysasksautomemberexclusiveregex*texclusive_regexsExclusive Regextkeys Attribute KeysQAttribute to filter via regex. For example fqdn for a host, or manager for a usertflagst no_createt no_updatet no_searchttypes Grouping Types"Grouping to which the rule appliestvaluesugroupu hostgrouptcntautomember_rulesAutomember Rulet normalizercCs |jƒS(N(tlower(tvalue((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pyt—st automemberc BsÔeZdZejjZdZdZddgZ ddddd d gZ e d ƒZ e d d dde dƒde dƒƒe dd dde dƒde dƒddddgƒfZd„Zd„Zd„ZRS(sG Bring automember to a hostgroup with an Auto Membership Rule. tauto_member_ruletauto_member_rulesttoptautomemberregexruleR R Rtautomembertargetgroupt descriptiontautomemberdefaultgroupsAuto Membership Rules description?R tdescR t DescriptionRs&A description of this auto member rulesautomemberdefaultgroup?t default_groupsDefault (fallback) Groups!Default group for entries to landRRRRcGs{|jjj}|jj|j|ƒ}y|j|gƒ\}}Wn0tjk rvtjdtdƒ|ƒ‚nX|S(NtreasonuGroup: %s not found!( RtBackendtldap2tObjecttget_dnt get_entryRtNotFoundR(tselft grouptypet groupnametkeystldaptdntgdnt entry_attrs((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pyt dn_exists»s cOs¡|jr,|jj|jj|d Œ}nt|jtjjƒ}|d}y&td|dfd|f|ƒ}Wn&tk rœtd|f|ƒ}nX|S(NiÿÿÿÿRR( t parent_objectRR-R.Rt container_dntenvtbasednt IndexError(R1R4toptionst parent_dnR2tndn((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pyR.Äs # & cCsZ|jjj}|jjtjj|ƒ}|dk r:|Stj dt dƒ|ƒ‚dS(sV Verify that the user supplied key is a valid attribute in the schema R*s%s is not a valid attribute.N( RR+R,tschematget_objt_ldapt AttributeTypetNoneRR0R(R1tattrR5tobj((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pyt check_attrÐs  (t__name__t __module__t__doc__RR<tcontainer_automemberR;t object_nametobject_name_pluralt object_classtdefault_attributesRR Rt takes_paramsR9R.RI(((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pyR›s(          cCsEy)|jttjjtjjƒgƒWntjk r@tSXt S(N( R/RRR<RMR=RR0tFalsetTrue(R5((s7/home/mkosek/freeipa-clean/ipalib/plugins/automember.pytautomember_container_existsÞs )tautomember_addcBsEeZedƒZejeZeZedƒZ d„Z d„Z RS(s! Add an automember rule. s!Added automember rule "%(value)s"cOsxt|tƒst‚|d|dt|tƒst‚d|kr:ttdƒƒ|dt|tƒst‚d|kr:ttdƒƒ|dst  R                 @   Z U       freeipa-3.3.4/ipalib/plugins/hbactest.pyc0000664000175000017500000003570512271707517017760 0ustar mkosekmkosekó †fçRc@s/ddlmZmZmZmZddlmZmZmZmZm Z ddl m Z ddl m Z ddlmZmZddlmZejjo±ejjddgkrçydd lZeZWnek rãeZnXndd lZed ƒZd „Zd efd „ƒYZejeƒd S(iÿÿÿÿ(tapiterrorstoutputtutil(tCommandtStrtFlagtInttDeprecatedParam(tNoneType(tto_cli(t_tngettext(tDNtlitetserverNs# Simulate use of Host-based access controls HBAC rules control who can access what services on what hosts. You can use HBAC to control which users or groups can access a service, or group of services, on a target host. Since applying HBAC rules implies use of a production environment, this plugin aims to provide simulation of HBAC rules evaluation without having access to the production environment. Test user coming to a service on a named host against existing enabled rules. ipa hbactest --user= --host= --service= [--rules=rules-list] [--nodetail] [--enabled] [--disabled] [--sizelimit= ] --user, --host, and --service are mandatory, others are optional. If --rules is specified simulate enabling of the specified rules and test the login of the user using only these rules. If --enabled is specified, all enabled HBAC rules will be added to simulation If --disabled is specified, all disabled HBAC rules will be added to simulation If --nodetail is specified, do not return information about rules matched/not matched. If both --rules and --enabled are specified, apply simulation to --rules _and_ all IPA enabled rules. If no --rules specified, simulation is run against all IPA enabled rules. By default there is a IPA-wide limit to number of entries fetched, you can change it with --sizelimit option. EXAMPLES: 1. Use all enabled HBAC rules in IPA database to simulate: $ ipa hbactest --user=a1a --host=bar --service=sshd -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Matched rules: allow_all 2. Disable detailed summary of how rules were applied: $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail -------------------- Access granted: True -------------------- 3. Test explicitly specified HBAC rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \ --rules=myrule --rules=my-second-rule --------------------- Access granted: False --------------------- Not matched rules: my-second-rule Not matched rules: myrule 4. Use all enabled HBAC rules in IPA database + explicitly specified rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \ --rules=myrule --rules=my-second-rule --enabled -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Matched rules: allow_all 5. Test all disabled HBAC rules in IPA database: $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled --------------------- Access granted: False --------------------- Not matched rules: new-rule 6. Test all disabled HBAC rules in IPA database + explicitly specified rules: $ ipa hbactest --user=a1a --host=bar --service=sshd \ --rules=myrule --rules=my-second-rule --disabled --------------------- Access granted: False --------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule 7. Test all (enabled and disabled) HBAC rules in IPA database: $ ipa hbactest --user=a1a --host=bar --service=sshd \ --enabled --disabled -------------------- Access granted: True -------------------- Not matched rules: my-second-rule Not matched rules: my-third-rule Not matched rules: myrule Not matched rules: new-rule Matched rules: allow_all HBACTEST AND TRUSTED DOMAINS When an external trusted domain is configured in IPA, HBAC rules are also applied on users accessing IPA resources from the trusted domain. Trusted domain users and groups (and their SIDs) can be then assigned to external groups which can be members of POSIX groups in IPA which can be used in HBAC rules and thus allowing access to resources protected by the HBAC system. hbactest plugin is capable of testing access for both local IPA users and users from the trusted domains, either by a fully qualified user name or by user SID. Such user names need to have a trusted domain specified as a short name (DOMAIN\Administrator) or with a user principal name (UPN), Administrator@ad.test. Please note that hbactest executed with a trusted domain user as --user parameter can be only run by members of "trust admins" group. EXAMPLES: 1. Test if a user from a trusted domain specified by its shortname matches any rule: $ ipa hbactest --user 'DOMAIN\Administrator' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 2. Test if a user from a trusted domain specified by its domain name matches any rule: $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 3. Test if a user from a trusted domain specified by its SID matches any rule: $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \ --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Matched rules: can_login 4. Test if other user from a trusted domain specified by its SID matches any rule: $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \ --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Not matched rules: can_login 5. Test if other user from a trusted domain specified by its shortname matches any rule: $ ipa hbactest --user 'DOMAIN\Otheruser' --host `hostname` --service sshd -------------------- Access granted: True -------------------- Matched rules: allow_all Not matched rules: can_login cCs‡tj|ddƒ}|dd|_dddd|jfdddd |jfd d dd |jfd d d d|jff}xØ|D]Ð}d|d}||kr½||ddksÍ|dd kréttjgƒ|d_ q‰d|d|df}||kr!|||d_ nd|d|df}||kr‰|||d_ q‰q‰Wd|krƒ|jj j |dƒn|S(Ntcnitipaenabledflagtusert memberusertgroupthostt memberhostt hostgroupt sourcehosttservicet memberservicethbacsvct hbacsvcgroups %scategoryuallis%s_%siiit externalhost( tpyhbactHbacRuletenabledtuserst targethoststsrchoststservicestsettHBAC_CATEGORY_ALLtcategorytnamestgroupstextend(truletipa_rulet structuretelementR't attr_name((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pytconvert_to_ipa_ruleÐs& 0   thbactestcBsëeZedƒZejejdeee fedƒƒejdeee fedƒƒejdeee fedƒƒejdeee fedƒƒejd e ed ƒd gƒfZ e d d d dedƒde ƒedƒe dd ddedƒƒe dd ddedƒƒe dd ddedƒde ƒedd ddedƒƒedd dded ƒƒed!d d"ded#ƒƒed$ded%ƒd&ed'ƒd(d gd)d*d+eƒf Zd,„Zd-„Zd.„ZRS(/s*Simulate use of Host-based access controlstwarningtWarningtmatcheds Matched rulest notmatchedsNot matched rulesterrorsNon-existent or invalid rulestvaluesResult of simulationt no_displayRtcli_nametlabels User namet primary_keys sourcehost?t targethostRs Target hostRtServicesrules*truless5Rules to test. If not specified, --enabled is assumedtcsvs nodetail?tnodetails=Hide details which rules are matched, not matched, or invalidsenabled?R s1Include all enabled IPA rules into test [default]s disabled?tdisableds(Include all disabled IPA rules into tests sizelimit?s Size Limittdocs?Maximum number of rules to process when no --rules is specifiedtflagstminvalueitautofillcCs-|jdƒdkr)d||jjfS|S(sY Canonicalize the host name -- add default IPA domain if that is missing t.iÿÿÿÿu%s.%s(tfindtenvtdomain(tselfR((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pyt canonicalize%sc( Osˆg}t}t}i}d|krCt|dƒ}t}t}nd}d|krht|dƒ}n|drt}t}n|dr”t}ng}t|ƒdkrË|jjjd|ƒd}n?x<|D]4} y$|j |jjj | ƒdƒWqÒqÒXqÒWxš|D]’} t | ƒ} | j |kr[t| _ |j | ƒ|j| j ƒq|rz| j rz|j | ƒq|r| j rt| _ |j | ƒqqWt|ƒdkróittdƒƒd6|d 6dd 6dd 6dd 6td 6Stjƒ} |ddkrttr.tjj|dƒ} nt} tj|dƒ} | sed| ksed| krõts†tjdtdƒƒ‚ntjj|jƒ}|jƒsÂtjdtdƒƒ‚n|j|dƒ\}}|| j_ ddj||gƒ}|jj j!}t"tj#j$tj#j%ƒ}y"|j&|dg|ƒ\}}Wn tjk rog| j_'qqXg}xa|D]Y\}}|j(dgƒ}x8|D]0}|j)|ƒr¢|j |ddj*ƒq¢q¢Wq}Wt+t,|ƒƒ| j_'qtyr|d| j_ |jjj-| jj ƒd}|d}d|krN||d7}nt+t,|ƒƒ| j_'WqtqtXn|ddkrãyR|d| j._ |jjj/| j.j ƒd}d|krÕ|d| j._'nWqãqãXn|ddkr{y{|j0|dƒ| j1_ |jjj2| j1j ƒd}|d}d|krU||d7}nt+t,|ƒƒ| j1_'Wq{q{Xng}g}g} g}!idd 6dd 6dd 6dd 6}"|dsÌxõ|D]í} yZ| j3| gƒ}#|#tj4kr|j | j ƒn|#tj5kr%|j | j ƒnWqÆtj6k r†\}$}%|$tj7kr³| j |%ƒ|j8j9d |%tj:|$ƒfƒq³qÆt;t<fk r²}&|j8j=d!|&ƒqÆXqÆWt|ƒdk}'n| j3|ƒ}#|#tj4k}'td"ƒ|'|"dt sizelimitRAR itresultuUnresolved rules in --rulestsummaryR6R4R5R2R7RuallRItflatnametreasonsšCannot perform external member validation without Samba 4 support installed. Make sure you have installed server-trust-ad sub-package of IPA on the servers‚Cannot search in trusted domains without own domain configured. Make sure you have run ipa-adtrust-install on the IPA server firsts:(&(objectclass=ipaexternalgroup)(|(ipaExternalMember=%s)))s)(ipaExternalMember=tmemberoftmemberof_grouptmemberofindirect_groupRtmemberof_hbacsvcgroupR<tmemberof_hostgrouptmemberofindirect_hostgroupR@s+Native IPA HBAC rule "%s" parsing error: %ss Native IPA HBAC module error: %ssAccess granted: %s(>tTruetFalsetlisttNonetinttlenRRt hbacrule_findtappendt hbacrule_showR0tnameR tremovetunicodeR Rt HbacRequestt_dcerpc_bindings_installedt ipaservertdcerpct is_sid_validRtnormalize_nameRtNotFoundtDomainValidatort is_configuredt"get_trusted_domain_user_and_groupsRtjointBackendtldap2R RHtcontainer_grouptbasednt find_entriesR)tgettendswithR7tsortedR%t user_showRt hbacsvc_showRKR<t host_showtevaluatetHBAC_EVAL_ALLOWtHBAC_EVAL_DENYt HbacErrortHBAC_EVAL_ERRORtlogtinfothbac_result_stringt TypeErrortIOErrorR6((RJtargstoptionsR>t all_enabledt all_disabledt testrulesRLthbacsetR+R,trequestt is_valid_sidt componentstdomain_validatortuser_sidt group_sidst filter_sidstldaptgroup_containertentriest truncatedR)tdntentryt memberof_dnst memberof_dnt search_resulttservice_resultttgthost_resultt matched_rulestnotmatched_rulest error_rulest warning_rulesRMtrestcodet rule_nameRtaccess_granted((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pytexecute-s        $          " #     "         cOsÊx¸|jD]­}|j|}d|jkr2q n||}t|ttfƒrv|jt|jƒ|ddtƒq t|tt fƒr |dkr§|j |ƒq·|j |ƒq q Wt |d ƒS(sº Command.output_for_cli() uses --all option to decide whether to print detailed output. We use --detail to allow that, thus we need to redefine output_for_cli(). R8s%s: %siRNR7( RRCt isinstanceRYttupletprint_attributeRbRBRWtboolt print_summarytprint_indentedR[(RJttextuiRRƒR„totoutpRM((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pytoutput_for_cliés  % (t__name__t __module__R t__doc__RRNtOutputRYR¥R R§t has_outputRRWRRRRXt takes_optionsRKR£R­(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pyR1ðsP !!!!$                      ¼( tipalibRRRRRRRRRttypesR t ipalib.cliR R R t ipapython.dnR RHt in_servertcontexttipaserver.dcerpcReRWRdt ImportErrorRXRR°R0R1tregister(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbactest.pyts$"($     «  ÿfreeipa-3.3.4/ipalib/plugins/krbtpolicy.pyc0000664000175000017500000001276712271707517020350 0ustar mkosekmkosekó †fçRc@sðddlmZddlmZmZddlTddlmZedƒZidd6dd 6Zd efd „ƒYZ ej e ƒd e fd „ƒYZ ej e ƒde fd„ƒYZej eƒdefd„ƒYZej eƒdS(iÿÿÿÿ(tapi(tInttStr(t*(t_s Kerberos ticket policy There is a single Kerberos ticket policy. This policy defines the maximum ticket lifetime and the maximum renewal age, the period during which the ticket is renewable. You can also create a per-user ticket policy by specifying the user login. For changes to the global policy to take effect, restarting the KDC service is required, which can be achieved using: service krb5kdc restart Changes to per-user policies take effect immediately for newly requested tickets (e.g. when the user next runs kinit). EXAMPLES: Display the current Kerberos ticket policy: ipa krbtpolicy-show Reset the policy to the default: ipa krbtpolicy-reset Modify the policy to 8 hours max life, 1-day max renewal: ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400 Display effective Kerberos ticket policy for user 'admin': ipa krbtpolicy-show admin Reset per-user policy for user 'admin': ipa krbtpolicy-reset admin Modify per-user policy for user 'admin': ipa krbtpolicy-mod admin --maxlife=3600 i€Qtkrbmaxticketlifei€: tkrbmaxrenewableaget krbtpolicyc BsøeZdZedejjfdƒZedƒZ ddgZ dgZ edƒZ edƒZ edd d d ed ƒd edƒdeƒedd dd edƒd edƒddƒedd dd edƒd edƒddƒfZd„ZRS(s' Kerberos Ticket Policy object tcntkerberosskerberos ticket policy settingsRRtkrbticketpolicyauxsKerberos Ticket Policysuid?tcli_nametusertlabels User nametdocs&Manage ticket policy for specific usert primary_keyskrbmaxticketlife?tmaxlifesMax lifesMaximum ticket life (seconds)tminvalueiskrbmaxrenewableage?tmaxrenews Max renewsMaximum renewable age (seconds)cOs?|ddk r)|jjjj||ŽSt|jtjjƒS(Niÿÿÿÿ( tNoneRtObjectR tget_dntDNt container_dntenvtbasedn(tselftkeystkwargs((s7/home/mkosek/freeipa-clean/ipalib/plugins/krbtpolicy.pyRgs(scnskerberos(t__name__t __module__t__doc__RRRtrealmRRt object_nametdefault_attributestlimit_object_classesR tlabel_singularRtTrueRt takes_paramsR(((s7/home/mkosek/freeipa-clean/ipalib/plugins/krbtpolicy.pyRFs.               tkrbtpolicy_modcBseZedƒZd„ZRS(sModify Kerberos ticket policy.cOs5t|tƒst‚|jdƒr1t|dt LDAPObjectRtregistert LDAPUpdateR't LDAPRetrieveR3t LDAPQueryR;(((s7/home/mkosek/freeipa-clean/ipalib/plugins/krbtpolicy.pyts  $  &   #freeipa-3.3.4/ipalib/plugins/sudocmdgroup.py0000664000175000017500000000755512271663206020531 0ustar mkosekmkosek# Authors: # Jr Aquino # # Copyright (C) 2010 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 . from ipalib import api from ipalib import Str from ipalib.plugins.baseldap import * from ipalib import _, ngettext __doc__ = _(""" Groups of Sudo Commands Manage groups of Sudo Commands. EXAMPLES: Add a new Sudo Command Group: ipa sudocmdgroup-add --desc='administrators commands' admincmds Remove a Sudo Command Group: ipa sudocmdgroup-del admincmds Manage Sudo Command Group membership, commands: ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/vim admincmds Manage Sudo Command Group membership, commands: ipa group-remove-member --sudocmds=/usr/bin/less admincmds Show a Sudo Command Group: ipa group-show localadmins """) topic = ('sudo', _('commands for controlling sudo configuration')) class sudocmdgroup(LDAPObject): """ Sudo Command Group object. """ container_dn = api.env.container_sudocmdgroup object_name = _('sudo command group') object_name_plural = _('sudo command groups') object_class = ['ipaobject', 'ipasudocmdgrp'] default_attributes = [ 'cn', 'description', 'member', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['sudocmd'], } label = _('Sudo Command Groups') label_singular = _('Sudo Command Group') takes_params = ( Str('cn', cli_name='sudocmdgroup_name', label=_('Sudo Command Group'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description', cli_name='desc', label=_('Description'), doc=_('Group description'), ), Str('membercmd_sudocmd?', label=_('Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str('membercmd_sudocmdgroup?', label=_('Sudo Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), ) api.register(sudocmdgroup) class sudocmdgroup_add(LDAPCreate): __doc__ = _('Create new Sudo Command Group.') msg_summary = _('Added Sudo Command Group "%(value)s"') api.register(sudocmdgroup_add) class sudocmdgroup_del(LDAPDelete): __doc__ = _('Delete Sudo Command Group.') msg_summary = _('Deleted Sudo Command Group "%(value)s"') api.register(sudocmdgroup_del) class sudocmdgroup_mod(LDAPUpdate): __doc__ = _('Modify Sudo Command Group.') msg_summary = _('Modified Sudo Command Group "%(value)s"') api.register(sudocmdgroup_mod) class sudocmdgroup_find(LDAPSearch): __doc__ = _('Search for Sudo Command Groups.') msg_summary = ngettext( '%(count)d Sudo Command Group matched', '%(count)d Sudo Command Groups matched', 0 ) api.register(sudocmdgroup_find) class sudocmdgroup_show(LDAPRetrieve): __doc__ = _('Display Sudo Command Group.') api.register(sudocmdgroup_show) class sudocmdgroup_add_member(LDAPAddMember): __doc__ = _('Add members to Sudo Command Group.') api.register(sudocmdgroup_add_member) class sudocmdgroup_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from Sudo Command Group.') api.register(sudocmdgroup_remove_member) freeipa-3.3.4/ipalib/plugins/trust.pyc0000664000175000017500000012374212271707517017343 0ustar mkosekmkosekó †fçRc @séddlTddlmZddlmZddlmZmZmZm Z m Z m Z m Z ddlm Z ddlmZddlmZddlmZydd lZeZWnek rÏZeZnXydd lZeZWnek rZeZnXejjo#ejjd d gkrYydd lZeZ Wne!k rUeZ nXne d ƒZ"ed de dƒƒedde dƒƒedde dƒƒfZ#ie dƒd6e dƒd6e dƒd6Z$ie dƒd6e dƒd6e dƒd6Z%ie dƒe6e dƒe6Z&e dƒZ'ed d!d"de d#ƒd$d%fd&d%d'eƒZ(d(Z)d)„Z*d*„Z+d+„Z,d,„Z-d-„Z.d.e/fd/„ƒYZ0d0e1fd1„ƒYZ2d2e3fd3„ƒYZ4d4e5fd5„ƒYZ6d6e7fd7„ƒYZ8d8e9fd9„ƒYZ:ej;e0ƒej;e2ƒej;e6ƒej;e4ƒej;e8ƒej;e:ƒie<d:ejj=fejj>ejj?ƒd%6Z@d;e/fd<„ƒYZAej;eAƒd=e5fd>„ƒYZBej;eBƒd?e9fd@„ƒYZCej;eCƒer8idAejD6dBejE6dCejF6ZGdD„ZHndEe fdF„ƒYZIej;eIƒdGe fdH„ƒYZJej;eJƒdIe fdJ„ƒYZKej;eKƒdKe fdL„ƒYZLej;eLƒdMe/fdN„ƒYZMej;eMƒdOe7fdP„ƒYZNej;eNƒdQe5fdR„ƒYZOej;eOƒdSe1fdT„ƒYZPej;ePƒdUe3fdV„ƒYZQej;eQƒdW„ZRdXe9fdY„ƒYZSej;eSƒdZeTfd[„ƒYZUej;eUƒd\eTfd]„ƒYZVej;eVƒd S(^iÿÿÿÿ(t*(tdns_container_exists(trealm_to_suffix(tapitStrtStrEnumtPasswordtBoolt_tngettext(tCommand(terrors(t SCOPE_SUBTREE(tsleepNtlitetservers\ Cross-realm trusts Manage trust relationship between IPA and Active Directory domains. In order to allow users from a remote domain to access resources in IPA domain, trust relationship needs to be established. Currently IPA supports only trusts between IPA and Active Directory domains under control of Windows Server 2008 or later, with functional level 2008 or later. Please note that DNS on both IPA and Active Directory domain sides should be configured properly to discover each other. Trust relationship relies on ability to discover special resources in the other domain via DNS records. Examples: 1. Establish cross-realm trust with Active Directory using AD administrator credentials: ipa trust-add --type=ad --admin --password 2. List all existing trust relationships: ipa trust-find 3. Show details of the specific trust relationship: ipa trust-show 4. Delete existing trust relationship: ipa trust-del Once trust relationship is established, remote users will need to be mapped to local POSIX groups in order to actually use IPA resources. The mapping should be done via use of external membership of non-POSIX group and then this group should be included into one of local POSIX groups. Example: 1. Create group for the trusted domain admins' mapping and their local POSIX group: ipa group-add --desc=' admins external map' ad_admins_external --external ipa group-add --desc=' admins' ad_admins 2. Add security identifier of Domain Admins of the to the ad_admins_external group: ipa group-add-member ad_admins_external --external 'AD\Domain Admins' 3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group: ipa group-add-member ad_admins --groups ad_admins_external 4. List members of external members of ad_admins_external group to see their SIDs: ipa group-show ad_admins_external GLOBAL TRUST CONFIGURATION When IPA AD trust subpackage is installed and ipa-adtrust-install is run, a local domain configuration (SID, GUID, NetBIOS name) is generated. These identifiers are then used when communicating with a trusted domain of the particular type. 1. Show global trust configuration for Active Directory type of trusts: ipa trustconfig-show --type ad 2. Modify global configuration for all trusts of Active Directory type and set a different fallback primary group (fallback primary group GID is used as a primary user GID if user authenticating to IPA domain does not have any other primary GID already set): ipa trustconfig-mod --type ad --fallback-primary-group "alternative AD group" 3. Change primary fallback group back to default hidden group (any group with posixGroup object class is allowed): ipa trustconfig-mod --type ad --fallback-primary-group "Default SMB Group" ttrustdirectiontlabelsTrust directiont trusttypes Trust typet truststatuss Trust statussNon-Active Directory domainisActive Directory domainis RFC4120-compliant Kerberos realmisTrusting forestsTrusted forests Two-way trustsEstablished and verifieds'Waiting for confirmation by remote sidetUnknownt trust_typetcli_namettypes-Trust type (ad for Active Directory, default)tvaluesuadtdefaulttautofilli@ cCs"tjt|ƒtƒ}t|ƒS(sä Returns a string representing a type of the trust. The original field is an enum: LSA_TRUST_TYPE_DOWNLEVEL = 0x00000001, LSA_TRUST_TYPE_UPLEVEL = 0x00000002, LSA_TRUST_TYPE_MIT = 0x00000003 (t_trust_type_dicttgettintt_trust_type_dict_unknowntunicode(tleveltstring((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyttrust_type_string¡scCs"tjt|ƒtƒ}t|ƒS(sÙ Returns a string representing a direction of the trust. The original field is a bitmask taking two bits in use LSA_TRUST_DIRECTION_INBOUND = 0x00000001, LSA_TRUST_DIRECTION_OUTBOUND = 0x00000002 (t_trust_direction_dictRRRR(R R!((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyttrust_direction_string«scCstj|tƒ}t|ƒS(N(t_trust_status_dictRRR(R R!((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyttrust_status_string´scCsJt|tƒst‚|rFtd|f|j|jƒ}t||ƒS|S(Ntcn(t isinstancetDNtAssertionErrortcontainer_truststbasedn(tenvRtdnt container_dn((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyt make_trust_dn¸s  c s³d}d}d}|jddƒd kr±|d}t|ƒ} d} tdƒ| } tjj|jƒ} | jƒs’t j dt dƒƒ‚nxVt dƒD]H} | j || dtd | d tƒ}|rÝ|d ‰PqŸtd ƒqŸWd dg}|s|jjdƒq±t‡fd†|Dƒƒr±|jjdƒd}ˆjd ƒ}ˆjddƒ}tt||ƒd ƒ}tˆjdƒd ƒ}d||tt}q±n|jddƒrØ|jddƒ}n|sçd}n|jddƒr|jddƒ}n|st}n|jddƒrD|jddƒ}n0|stttj|t|ƒdƒdt}n|jjd|d|d|dd d|d|ƒ|||fS(!sb First, we try to derive the parameters of the ID range based on the information contained in the Active Directory. If that was not successful, we go for our usual defaults (random base, range size 200 000, ipa-ad-trust range type). Any of these can be overriden by passing appropriate CLI options to the trust-add command. t range_typeuipa-ad-trust-posixiÿÿÿÿs(objectClass=msSFU30DomainInfo)s1CN=ypservers,CN=ypServ30,CN=RpcServices,CN=Systemtreasons‚Cannot search in trusted domains without own domain configured. Make sure you have run ipa-adtrust-install on the IPA server firsti R,tquietiitmsSFU30MaxUidNumbertmsSFU30OrderNumbers%Unable to gain POSIX info from the ADc3s|]}|ˆkVqdS(N((t.0tattr(tinfo(s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pys ýss#Able to gain POSIX info from the ADtmsSFU30MaxGidNumberiu ipa-ad-trustt range_sizetbase_idlï>[=i't idrange_addt ipabaseidtipaidrangesizet ipabaseridt iparangetypetipanttrusteddomainsidN(Nuipa-ad-trust-posix(tNoneRRR)t ipaservertdcerpctDomainValidatorRt is_configuredR tNotFoundRtranget search_in_dcR tTrueR tlogtdebugtallRtmaxtDEFAULT_RANGE_SIZEt pysss_murmurt murmurhash3tlenR (tselft range_nametdom_sidtkeystoptionsR:R1R;tdomainR,t info_filtertinfo_dntdomain_validatortretryt info_listtrequired_msSFU_attrstmax_uidtmax_gidtmax_id((R8s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyt add_range¿sx              ttrustcBsveZdZd+ZejjZedƒZ edƒZ dgZ dddd d d d d ddddg Z dddd ddgZ edƒZedƒZeddddedƒdeƒeddddedƒdddgƒeddd ded!ƒdddgƒed"d#edd$ded%ƒddgƒed&d#edd'ded(ƒddgƒfZd)„Zd*„ZRS(,s Trust object. tadtipaRcttruststipaNTTrustedDomainR't ipantflatnameRAtipanttrusttypetipanttrustattributestipanttrustdirectiontipanttrustpartnertipantauthtrustoutgoingtipanttrustauthincomingtipanttrustforesttrustinfotipanttrustposixoffsettipantsupportedencryptiontypestipantsidblacklistincomingtipantsidblacklistoutgoingtTruststTrustRtrealmRs Realm namet primary_keyt flat_namesDomain NetBIOS nametflagst no_createt no_updatetsidsDomain Security Identifiersipantsidblacklistincoming*tcsvtsid_blacklist_incomingsSID blacklist incomingsipantsidblacklistoutgoing*tsid_blacklist_outgoingsSID blacklist outgoingc Cs‹ts dSxzdD]r}|j|ƒ}|s2qnxN|D]F}tjj|ƒs9tjd|dtdƒtd|ƒƒ‚q9q9WqWdS(NRrRstnameterrorsinvalid SID: %(value)stvalue(RrRs( t_bindings_installedRRCRDt is_sid_validR tValidationErrorRtdict(RSt entry_attrsR7RR‚((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pytvalidate_sid_blacklistsYs  c Ostd„|ƒ}|jƒ|jdƒ}|dkrð|j}|jidgd6|dgd6d|jƒ}|j|dfd|jƒ}|jt |j |j j ƒ|j |d gƒ}t|ƒd kråtjd d ƒ‚n|d jSt|j |t |Œƒ}|S(NcSs d|fS(NR'((tx((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pytisRRgt objectclassiÿÿÿÿR'trulessipaNTSIDBlacklistIncoming=*tiR7s trust domaini(tmaptreverseRRBtbackendt make_filtert MATCH_ALLtcombine_filterst get_entriesR)R/R-R,R RRR tOnlyOneValueAllowedR.R0( RSRVtkwargstsdnRtldaptfiltertresultR.((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pytget_dnhs   $  (sadsipa(t__name__t __module__t__doc__t trust_typesRR-R+R/Rt object_nametobject_name_pluralt object_classtdefault_attributestsearch_display_attributesRtlabel_singularRRJt takes_paramsRˆR›(((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyRc+sN                         t trust_addcBseZedƒZieedƒƒd6eedƒƒd6Zejee dddded ƒƒe d dd ded ƒd e ƒe ddddedƒƒe ddddedƒd e ƒe ddddedƒƒe ddddedƒƒe ddedƒdddedjdd jejƒƒƒƒd!eejƒƒƒfZed"ƒZejeZd#„Zd$„Zd%„Zd&„ZRS('s Add new trust to use. This command establishes trust relationship to another domain which becomes 'trusted'. As result, users of the trusted domain may access resources of this domain. Only trusts to Active Directory domains are supported right now. The command can be safely run multiple times against the same domain, this will cause change to trust relationship credentials on both sides. sActive Directory domain rangeu ipa-ad-trusts2Active Directory trust range with POSIX attributesuipa-ad-trust-posixs realm_admin?RtadminRs%Active Directory domain administrators realm_passwd?tpasswords0Active directory domain administrator's passwordtconfirms realm_server?Rs<Domain controller for the Active Directory domain (optional)s trust_secret?t trust_secretsShared secret for the trustsbase_id?R;s;First Posix ID of the range reserved for the trusted domains range_size?R:s4Size of the ID range reserved for the trusted domains range_type?s Range typeR1tdocs.Type of trusted domain ID range, one of {vals}tvalss, Rs2Added Active Directory trust for realm "%(value)s"c OsA|j||Ž}|j||Ž\}}}|j|||Ž}|slt|||||Ž\}} } n|ddd}d|d} |jj} | jdttj j tj j ƒd| ƒ\} } t | dd||d<|j d ƒd krÕ|d krÕt||j|d|}|rÕt|ƒdkrÕx”|D]‰}|d djƒd }|dd}|}|jd|ƒd|krš|d=nyt|||||ŽWqBtjk rÊqBXqBWqÕnt|dddƒg|ddRemove infromation about the domain associated with the trust.s8Removed information about the trusted domain "%(value)s"cOs¶x}|dD]q}|djƒ|krHtjdddtdƒƒ‚nytjj|d|ƒ}Wq tjk r{q Xq Wtt |ƒj ||Ž}dj |dƒ|d<|S( NiiR€RXRsPcannot delete root domain of the trust, use trust-del to delete the trust itselfu,R‚( RÎR R…RRR ttrustdomain_enablet AlreadyActiveRRSRÄRì(RSRVRWRXtresRš((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyRÄÎs(RœRRRžRÜRÄ(((s2/home/mkosek/freeipa-clean/ipalib/plugins/trust.pyRSÉs  cKsþ|dd}d}|jddƒ}|r|jdƒ}|jdƒ}t|ƒdkry|jd|jjdƒndjddj|ƒd |ƒ}nt j j |j |j |d |ƒ} g} | sÑ| S|jƒd } t jj| d tƒd } | d} xð| D]è}d|dsÐ 4      $    Q                lOÿh      .h       &  ) ) /      .( & &freeipa-3.3.4/ipalib/plugins/aci.pyc0000664000175000017500000006657212271707517016725 0ustar mkosekmkosekó †fçRc @sßdZddlmZddlmZmZmZddlmZmZddlm Z m Z m Z m Z ddl mZddlmZddlmZmZdd lmZdd lTdd lmZd Zid eedIejjejjƒƒd6d eedJejjejjƒƒd6d eedKejjejjƒƒd6d eedLejjejjƒƒd6d eedMejjejjƒƒd6d eedNejj ejjƒƒd6d eedOejj!ejjƒƒd6Z"ddddd gZ#dPZ$d%ej%fd&„ƒYZ&ej%d'e'd(ƒej(ej)fZ*d)„Z+d*„Z,d+„Z-d,„Z.e/e/d-„Z0d.„Z1d/„Z2d0„Z3d1„Z4e d2d3d4d5ed6ƒd7ed8ƒd9e$ƒZ5d:efd;„ƒYZ6ej7e6ƒd<ej8fd=„ƒYZ9ej7e9ƒd>ej:fd?„ƒYZ;ej7e;ƒd@ej<fdA„ƒYZ=ej7e=ƒdBej>fdC„ƒYZ?ej7e?ƒdDej@fdE„ƒYZAej7eAƒdFej<fdG„ƒYZBej7eBƒdHS(Qs° Directory Server Access Control Instructions (ACIs) ACIs are used to allow or deny access to information. This module is currently designed to allow, not deny, access. The aci commands are designed to grant permissions that allow updating existing entries or adding or deleting new ones. The goal of the ACIs that ship with IPA is to provide a set of low-level permissions that grant access to special groups called taskgroups. These low-level permissions can be combined into roles that grant broader access. These roles are another type of group, roles. For example, if you have taskgroups that allow adding and modifying users you could create a role, useradmin. You would assign users to the useradmin role to allow them to do the operations defined by the taskgroups. You can create ACIs that delegate permission so users in group A can write attributes on group B. The type option is a map that applies to all entries in the users, groups or host location. It is primarily designed to be used when granting add permissions (to write new entries). An ACI consists of three parts: 1. target 2. permissions 3. bind rules The target is a set of rules that define which LDAP objects are being targeted. This can include a list of attributes, an area of that LDAP tree or an LDAP filter. The targets include: - attrs: list of attributes affected - type: an object type (user, group, host, service, etc) - memberof: members of a group - targetgroup: grant access to modify a specific group. This is primarily designed to enable users to add or remove members of a specific group. - filter: A legal LDAP filter used to narrow the scope of the target. - subtree: Used to apply a rule across an entire set of objects. For example, to allow adding users you need to grant "add" permission to the subtree ldap://uid=*,cn=users,cn=accounts,dc=example,dc=com. The subtree option is a fail-safe for objects that may not be covered by the type option. The permissions define what the ACI is allowed to do, and are one or more of: 1. write - write one or more attributes 2. read - read one or more attributes 3. add - add a new entry to the tree 4. delete - delete an existing entry 5. all - all permissions are granted Note the distinction between attributes and entries. The permissions are independent, so being able to add a user does not mean that the user will be editable. The bind rule defines who this ACI grants permissions to. The LDAP server allows this to be any valid LDAP entry but we encourage the use of taskgroups so that the rights can be easily shared through roles. For a more thorough description of access controls see http://www.redhat.com/docs/manuals/dir-server/ag/8.0/Managing_Access_Control.html EXAMPLES: NOTE: ACIs are now added via the permission plugin. These examples are to demonstrate how the various options work but this is done via the permission command-line now (see last example). Add an ACI so that the group "secretaries" can update the address on any user: ipa group-add --desc="Office secretaries" secretaries ipa aci-add --attrs=streetAddress --memberof=ipausers --group=secretaries --permissions=write --prefix=none "Secretaries write addresses" Show the new ACI: ipa aci-show --prefix=none "Secretaries write addresses" Add an ACI that allows members of the "addusers" permission to add new users: ipa aci-add --type=user --permission=addusers --permissions=add --prefix=none "Add new users" Add an ACI that allows members of the editors manage members of the admins group: ipa aci-add --permissions=write --attrs=member --targetgroup=admins --group=editors --prefix=none "Editors manage admins" Add an ACI that allows members of the admins group to manage the street and zip code of those in the editors group: ipa aci-add --permissions=write --memberof=editors --group=admins --attrs=street --attrs=postalcode --prefix=none "admins edit the address of editors" Add an ACI that allows the admins group manage the street and zipcode of those who work for the boss: ipa aci-add --permissions=write --group=admins --attrs=street --attrs=postalcode --filter="(manager=uid=boss,cn=users,cn=accounts,dc=example,dc=com)" --prefix=none "Edit the address of those who work for the boss" Add an entirely new kind of record to IPA that isn't covered by any of the --type options, creating a permission: ipa permission-add --permissions=add --subtree="cn=*,cn=orange,cn=accounts,dc=example,dc=com" --desc="Add Orange Entries" add_orange The show command shows the raw 389-ds ACI. IMPORTANT: When modifying the target attributes of an existing ACI you must include all existing attributes as well. When doing an aci-mod the targetattr REPLACES the current attributes, it does not add to them. iÿÿÿÿ(tdeepcopy(tapitcrudterrors(tObjecttCommand(tFlagtInttStrtStrEnum(tACI(toutput(t_tngettext(tgen_pkey_only_option(t*(tDNt:sldap:///tuidRtusertcntgrouptfqdnthostt hostgrouptkrbprincipalnametservicet ipauniqueidtnetgrouptidnsnamet dnsrecordureaduwriteuaddudeleteuallu permissionu delegationu selfserviceunonet ListOfACIcBs)eZeefZedƒZd„ZRS(sA list of ACI valuesc Cs…t||jƒst‚xft|ƒD]X\}}t|tƒs%ttj|j|j j |j|tt|ƒ|fƒ‚q%q%WdS(N( t isinstancettypetAssertionErrort enumeratetunicodet TypeErrorR temsgtnamet __class__t__name__(tselftcmdtentriestitentry((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pytvalidateœs  (R)t __module__tlistttupleR!R tdocR/(((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyR˜s  tresultsA string representing the ACIcCs|dkr|S|t|S(s: Given a name and a prefix construct an ACI name. unone(tACI_NAME_PREFIX_SEP(t aciprefixtaciname((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyt_make_aci_name¬s cCs9|jtƒ}|ds'd|dfS|d|dfS(sj Parse the raw ACI name and return a tuple containing the ACI prefix and the actual ACI name. iunonei(t partitionR5(R7taciparts((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyt_parse_aci_nameµs cCsP|jdƒ}|dkr/tjdj|ƒS|jd|ƒ}||d|!S(s6 Pull the group name out of a memberOf filter s memberOf=iÿÿÿÿRt)i (tfindRRtget_dn(tmemberoftstten((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyt_group_from_memberofÁs  c Cs^ddddddg}i}x;|D]3}||krN||d(k || Given a name and a set of keywords construct an ACI. R!tfiltertsubtreet targetgrouptattrsR?iR'ttargetterrors<type, filter, subtree and targetgroup are mutually exclusiveR6sACI prefix is requiredisSat least one of: type, filter, subtree, targetgroup, attrs or memberof are requireds*filter and memberof are mutually exclusiveRt permissiontselfacis1group, permission and self are mutually exclusives,One of group, permission or self is requiredtpermission_showR4ttestRtdntreasonsGroup '%s' does not existt permissionssuserdn = "ldap:///self"sgroupdn = "ldap:///%s"s memberOf=%stutinfos empty filters ldap:///%ssldap:///sSyntax Error: %(error)sN(RPNu(#tNonetFalseRtValidationErrorR tsumt itervaluestTrueRRtNotFoundtgetRtenvtcontainer_permissiontbasednRtget_dn_if_existsR R8R'ROt set_bindruletset_target_attrthandle_not_foundRBtset_target_filtertBadSearchFiltert find_entriest _type_mapt set_targett startswitht SyntaxErrortdicttstr(tldaptcurrentR7tkwt checked_argstvalidtargRRIRJt entry_attrstetgroup_dntaRMtgroupdnR,RG((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyt _make_aciÌsš  (! !!!  !! #'            5cCs¸i}t|jƒ\|d<|d<|r-|St|jƒ|dt jƒD]0} t | |krwt| ƒ|dƒeddddedƒd edƒdd?ƒededddedƒd edƒdede dd@ƒeddddedƒd edƒdeddAƒe ddddedƒd ed ƒd!dBddCƒed)dd*ded+ƒd ed,ƒddDƒed-dd.ded/ƒd ed0ƒddEƒed1dd2ded3ƒd ed4ƒddFƒed5dd6ded7ƒd ed8ƒddGƒe d9dd:ded;ƒd ed<ƒddHƒf Z RS(Is ACI object. tACIsR7RžR'R sACI namet primary_keytflagstvirtual_attributes permission?RIt PermissionR3sPermission ACI grants access tosgroup?Rs User groupsUser group ACI grants access tos permissions+ROt Permissionss3Permissions to grant(read, write, add, delete, all)tcsvt normalizersattrs*RFs*Attributes to which the permission appliest Attributesstype?R!tTypesDtype of IPA object (user, group, host, hostgroup, service, netgroup)R¡uuserugroupuhostuserviceu hostgroupunetgroupu dnsrecords memberof?R?s Member ofsMember of a groupsfilter?RCtFilters'Legal LDAP filter (e.g. ou=Engineering)ssubtree?RDtSubtreesSubtree to apply ACI tos targetgroup?REs Target groupsGroup to apply ACI tosselfaci?R*sTarget your own entry (self)s"Apply ACI to your own entry (self)(svirtual_attribute(svirtual_attribute(svirtual_attribute(svirtual_attribute(svirtual_attribute(uuserugroupuhostuserviceu hostgroupunetgroupu dnsrecord(svirtual_attribute(svirtual_attribute(svirtual_attribute(svirtual_attribute(svirtual_attribute(svirtual_attribute( R)R0t__doc__RWtNO_CLIR R RR™RR Rt takes_params(((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyR¢¦s|                                 taci_addcBsMeZdZeZedƒZeeddedƒde ƒfZ d„Z RS(s Create new ACI. sCreated ACI "%(value)s"stest?R3s,Test the ACI syntax but don't write anythingtdefaultc KsPd|kst‚|jjj}t|d||ƒ}|j|jjjdgƒ\}}t |j dgƒƒ}x>|D]6}|j |ƒs |j |j kryt jƒ‚qyqyWt|ƒ} |dj| ƒ|j dtƒsõ|j||ƒn|j dtƒrtdt| ƒƒ} nt|||j dtƒƒ} td| d|ƒS(së Execute the aci-create operation. Returns the entry as it will be created in LDAP. :param aciname: The name of the ACI being added. :param kw: Keyword arguments for the other LDAP attributes. R7R¢RLtrawR4tvalueN(R"RtBackendtldap2RuRRR†RZR\R’RYtisequalR'RtDuplicateEntryR$RRSt update_entryRhRŒ( R*R7RlRjtnewaciRMRpR‘Rst newaci_strR4((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pytexecute s$ $ ! ( R)R0R¯RWR°R t msg_summaryt_prefix_optionRRSt takes_optionsR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyR²ús    taci_delcBs;eZdZeZejZedƒZ e fZ d„Z RS(s Delete ACI. sDeleted ACI "%(value)s"c KsÍ|jjj}|j|jjjdgƒ\}}|jdgƒ}t|ƒ}t|||ƒ} x:|D]2} t | ƒ} | j | ƒrj|j | ƒPqjqjW||d<|j ||ƒt dtd|ƒS(s™ Execute the aci-delete operation. :param aciname: The name of the ACI being deleted. :param aciprefix: The ACI prefix. R¢R4Rµ(RR¶R·R†RZR\RYR’R”R R¸tremoveRºRhRW( R*R7R6toptionsRjRMRpRR‘R¢Rst candidate((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyR½;s$     ( R)R0R¯RWR°R tstandard_booleant has_outputR R¾R¿RÀR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/aci.pyRÁ1s    taci_modcBsVeZdZeZeddedƒƒfZefZ dgZ edƒZ d„Z RS(s Modify ACI. R¢R R trenamesModified ACI "%(value)s"cKsÚ|d}|jjj}|j|jjjdgƒ\}}t|jdgƒƒ}t|||ƒ}t ||ƒ} t | ƒ} | jdt ƒr¡t |dtjƒD]0}t||krˆ|d|krˆt}PqˆqˆW|s<y|j|ƒWqêtk ræqêXq<q<Wn|jdtƒtkrXxL|D]A}|jddkry|j|ƒWqQtk rMqQXqqWn|jdƒrx¬|D]¡}|jd}t|jddƒƒ}y|dd}Wnt t!fk rÊd}nX|dksç||dkrny|j|ƒWqtk r qXqnqnWn|jdƒr xø|D]í}t}d|jkrë|jdd}t|jddƒƒ}ttjj#tjjƒ}|j$|ƒrëy|dd}Wnt t!fk rËd}nX||dkrèt}qèqën|s,y|j|ƒWqtk rqXq,q,Wn|jdƒrÁ|dj%dƒsat&d|ddƒ|dwsj" )))))),  iK       R 4 ' B Ë ' <freeipa-3.3.4/ipalib/plugins/baseldap.pyc0000664000175000017500000020635012271707517017732 0ustar mkosekmkosekó †fçRc3@sËdZddlZddlZddlmZddlZddlmZmZm Z ddlm Z m Z m Z ddlm Z mZmZddlmZddlmZdd lmZdd lmZmZdd lmZmZdZe d d edƒƒedd edƒƒedd edƒƒedd edƒƒedd edƒƒedd edƒƒedd edƒƒedd edƒƒedd edƒƒedd d ƒed!d ed"ƒƒed#d ed$ƒƒed%d d&ƒed'd ed(ƒƒed)d ed*ƒƒed+d ed,ƒƒed-d ed.ƒƒed/d ed0ƒƒed1d d2ƒed3d ed4ƒƒed5d ed6ƒƒed7d d8ƒed9d d:ƒed;d d<ƒed=d d>ƒed?d ed@ƒƒedAd edBƒƒedCd edDƒƒedEd edFƒƒedGd edHƒƒedId edJƒƒedKd edLƒƒedMd edNƒƒedOd edPƒƒedQd dRƒedSd dTƒedUd dVƒedWd dXƒedYd dZƒed[d d\ƒed]d ed^ƒƒed_d ed`ƒƒedad edbƒƒedcd eddƒƒeded edfƒdgdhgƒedid edjƒƒedkd edlƒƒf/Zdm„Zdn„Zdo„Zdp„Z ddq„Z"dr„Z#ds„Z$dt„Z%du„Z&edve&d edwƒdgdxgƒZ'dy„Z(dz„Z)d{„Z*d|„Z+d}e fd~„ƒYZ,d„Z-d€„Z.d„Z/d‚e fdƒ„ƒYZ0d„e0e fd…„ƒYZ1d†e1ej2fd‡„ƒYZ3dˆe1ej4fd‰„ƒYZ5dŠe5fd‹„ƒYZ6dŒe5fd„ƒYZ7dŽe5ej8fd„ƒYZ9de6fd‘„ƒYZ:d’e5fd“„ƒYZ;d”e;fd•„ƒYZ<d–e;fd—„ƒYZ=d˜„Z>d™e1ej?fdš„ƒYZ@d›e5fdœ„ƒYZAdeAfdž„ƒYZBdŸeAfd „ƒYZCdS(¡s Base classes for LDAP plugins. iÿÿÿÿN(tdeepcopy(tapitcrudterrors(tMethodtObjecttCommand(tFlagtInttStr(tto_cli(toutput(t_(tjson_serializetvalidate_hostname(tDNtRDNt has_passwordtlabeltPasswordtmembersFailed memberss member_user?s Member userss member_group?s Member groupssmemberof_group?sMember of groupss member_host?s Member hostssmember_hostgroup?sMember host-groupssmemberof_hostgroup?sMember of host-groupssmemberof_permission?t Permissionssmemberof_privilege?t Privilegessmemberof_role?tRolessmemberof_sudocmdgroup?sSudo Command Groupssmember_privilege?sGranted to Privileges member_role?sGranting privilege to rolessmember_netgroup?sMember netgroupssmemberof_netgroup?sMember of netgroupssmember_service?sMember servicessmember_servicegroup?sMember service groupssmemberof_servicegroup?sMember of service groupssmember_hbacsvc?sMember HBAC servicesmember_hbacsvcgroup?sMember HBAC service groupssmemberof_hbacsvcgroup?sMember of HBAC service groupssmember_sudocmd?sMember Sudo commandssmemberof_sudorule?sMember of Sudo rulesmemberof_hbacrule?sMember of HBAC rulesmemberindirect_user?sIndirect Member userssmemberindirect_group?sIndirect Member groupssmemberindirect_host?sIndirect Member hostssmemberindirect_hostgroup?sIndirect Member host-groupssmemberindirect_role?sIndirect Member of rolessmemberindirect_permission?sIndirect Member permissionssmemberindirect_hbacsvc?sIndirect Member HBAC servicesmemberindirect_hbacsvcgrp?s"Indirect Member HBAC service groupsmemberindirect_netgroup?sIndirect Member netgroupssmemberofindirect_group?sIndirect Member of groupsmemberofindirect_netgroup?sIndirect Member of netgroupsmemberofindirect_hostgroup?sIndirect Member of host-groupsmemberofindirect_role?sIndirect Member of rolesmemberofindirect_sudorule?sIndirect Member of Sudo rulesmemberofindirect_hbacrule?sIndirect Member of HBAC rulet sourcehostsFailed source hosts/hostgroupst memberhostsFailed hosts/hostgroupst memberusersFailed users/groupst memberservicesFailed service/service groupstfailedsFailed to removetflagstsuppress_emptyt ipasudorunass Failed RunAstipasudorunasgroupsFailed RunAsGroupcCst|d|ƒdS(Ntaddattr(tvalidate_attribute(tugettexttattr((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytvalidate_add_attribute¹scCst|d|ƒdS(Ntsetattr(R"(R#R$((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytvalidate_set_attribute¼scCst|d|ƒdS(Ntdelattr(R"(R#R$((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytvalidate_del_attribute¿scCsVtjd|ƒ}| s1t|jƒƒdkrRtjd|dtdƒƒ‚ndS(Ns\s*(.*?)\s*=\s*(.*?)\s*$itnameterrors$Invalid format. Should be name=value(tretmatchtlentgroupsRtValidationErrorR (R#R*R$tm((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR"Âs cCs¿t|tƒst‚|dkr3dddg}n|j||ƒ}i}d|dkr»|dd}|djdƒ}x<|D]1}|jdƒ\}}|||jƒjƒîstallR?(tgettFalsetdictt iteritemsR?(RGtoptionstresult((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt entry_to_dictês cCsÆd}x¹|dkrÁtjdƒ|d}|j|dgƒ\}}||kr t||ttfƒr›td„||ƒ}|jƒ|kr»Pq»q¾|jƒ||jƒkr¾Pq¾q q W|S(s? 389-ds postoperation plugins are executed after the data has been returned to a client. This means that plugins that add data in a postop are not included in data returned to the user. The downside of waiting is that this increases the time of the command. The updated entry is returned. iig333333Ó?iR2cSs |jƒS(N(R=(ty((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt s(ttimetsleept get_entryR7tlistttupletmapR=(R>R?R$tvaluetxt entry_attrstvalues((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytwait_for_valueós     cCs;yt|dtdtƒWntk r6}t|ƒSXdS(Nt check_fqdntallow_underscore(RROtTruet ValueErrortunicode(R#thostnameRI((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytvalidate_externalhostss externalhost*s External hostt no_optionc CsÚt|tƒst‚d„}|j|ƒrÖ|dkrB|}ntj|j}x||D]r}y||ƒWq]tjk r¤}tjd|d|j ƒ‚q]t k rÎ}tjd|d|ƒ‚q]Xq]Wn|S(s™ Pre callback to validate external members. This should be called by a command pre callback directly. membertype is the type of member cSst|dtdtƒdS(NRbRc(RRORd(Rg((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt validate_host.sthostR*R+( R7RR8RNRRt primary_keyRR0R+Re( t membertypeR>R?RFRRRjt validatorR]RI((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytadd_external_pre_callback#s   #cOsMt|tƒst‚d} | jdtƒ} ||kr?|||kr?|j||gƒ\}} t|tƒsyt‚|j|gƒ} | j|gƒ}td„|Dƒƒ}g}x-|||D]}|djƒ}tj |j |ƒ}t|tƒs t‚||krb|| krb| r7|j |ƒn|j |dƒ|j |ƒ| d7} qÈ||krØ|| krØt tjƒjƒ}|d|f}|||j|ƒ}|||||<|j |ƒqÈ|j |ƒqÈW| r?y|j|i||6ƒWntjk r nX||||<|||Ssi(R7RR8RNRdRYtsetR=RRtget_dntappendtaddRfRtAlreadyGroupMembertmessagetindext update_entryt EmptyModlist(t memberattrRmt externalattrR>t completedRR?R_RFRRtcompleted_externalt normalizet entry_attrs_tmemberstexternal_entriestlc_external_entriestfailed_entriesRGt membernamet member_dntmsgtnewerrortind((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytadd_external_post_callback?sJ       cOs±t|tƒst‚||kr£|||kr£|j||gƒ\}} | j|gƒ} g} d} xà|||D]Ð}|djƒ}|| ks«|d| krîy| j|ƒWn"tk rà| j|dƒnX| d7} qytt j ƒj ƒ}|d|f}|||j |ƒ}|||||<| j |ƒqyW| r£y|j|i| |6ƒWnt jk r„nX| |||<| ||R|RR?R_RFRRRRRƒR}RGR„R†R‡Rˆ((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytremove_external_post_callbackxs6  cCs}td|fd d d tjjƒ}y=|j|dgƒ\}}tjdddtd ƒƒ‚Wntjk rxd SXd S(sq Check to see if this host is a master. Raises an exception if a master, otherwise returns nothing. tcntmasterstipatetct objectclassR*RgR+s0An IPA master host cannot be deleted or disabledN(scnRŽ(scnsipa(scnsetc( RRtenvtbasednRYRR0R tNotFound(R>tfqdnt master_dnR?R_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pythost_is_masteršs $"t LDAPObjectcBsheZdZdZdZdZedƒZedƒZgZ d4Z gZ gZ gZgZd4ZgZgZddgZdZdZiZeZgZeZid5d 6d6d 6d7d6d8d6ZedƒZedƒZedƒZedƒZedƒZ edƒZ!d„Z"d„Z#d„Z$d„Z%d„Z&d„Z'd„Z(d „Z)d!„Z*d9Z+d3„Z,RS(:s+ Object representing a LDAP entry. tldap2tRGtentriesR‘tacitMembertno_Rs Member Oftin_tnot_in_tmemberofsIndirect Membert no_indirect_tmemberindirectsIndirect Member Oftnot_in_indirect_tmemberofindirecttEntrys)container entry (%(container)s) not founds%(parent)s: %(oname)s not founds%(pkey)s: %(oname)s not founds-%(oname)s with name "%(pkey)s" already existscOs|jr,|jj|jj|d Œ}nt|jtjjƒ}|jrµyJ|j j |j j |d|j dgt|jtjjƒƒ\}}Wntjk r­qµX|Sn|j rî|ddk rî|j j|j j |d|ƒSt|tƒst‚|S(NiÿÿÿÿRš(t parent_objectRRRrRt container_dnR’R“t rdn_attributetbackendtfind_entry_by_attrRlR*t object_classRR”R9tmake_dn_from_attrR7R8(tselfRFtkwargst parent_dnR?R_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRrÚs  #  % cOs1|j||Ž}|jj|dgƒ}|jS(NRš(RrRªRYR?(R®RFR¯R?RG((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytget_dn_if_existsðscCsÂt|tƒst‚ye|jry|jj||jjgƒ\}}y||jjdSWqytt fk rudSXnWnt j k rnXy||jjSWntk r½t |ƒSXdS(NiRš( R7RR8R©RªRYRlR*tKeyErrort IndexErrorRR”Rf(R®R?R_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytget_primary_key_from_dnõs    c csŠ|jr†|jj|j}x|jƒD] }|Vq)W|jr†|j}|j|j|jdtdtd|jd|jƒVq†ndS(Ntrequiredtquerytcli_nameR( R§RRtget_ancestor_primary_keysRlt __class__R*RdR(R®t parent_objtkeytpkey((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR¸ s    cCs"td„|ƒ}|jƒ|kS(NcSs |jƒS(N(R=(R^((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRVs(R\R=(R®tclassesR‘toc((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pythas_objectclasssc OsÙ|jdtƒrdSx¼|jD]±}x¡|j|gƒD]}x„|j|D]u}|jj|}t|jtjj ƒ}|j |ƒrMd||j f} |j| gƒj |j |ƒƒqMqMWq9W||=q WdS(NRKs%s_%s(RNROtattribute_memberst setdefaultRRRR¨R’R“tendswithR*RsR´( R®R_RFRRR$Rt ldap_obj_nametldap_objR¨tnew_attr((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytconvert_attribute_memberssc Cs{xt|jD]i\}}d|}y2|j||g||jƒ\}}t||R?R_tpwattrR$t search_filterR›t truncated((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytget_password_attributes+s  cGsJd}|jr|d}ntjd|ji|d6|jd6ƒ‚dS(NRšiÿÿÿÿtreasonR¼toname(RlRR”tobject_not_found_msgt object_name(R®RFR¼((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pythandle_not_found>s     cGsJd}|jr|d}ntjd|ji|d6|jd6ƒ‚dS(NRšiÿÿÿÿRvR¼RÏ(RlRtDuplicateEntrytalready_exists_msgRÑ(R®RFR¼((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pythandle_duplicate_entryHs     R§R¨RÑtobject_name_pluralR¬tobject_class_configtdefault_attributesRtlabel_singularthidden_attributestuuid_attributeRÀR*t takes_paramsR©tbindablet relationshipsc sZˆj}t‡fd†ˆjDƒƒ}ˆjrDˆjj|d]sRliitaciattrstmethods(RªRPtjson_friendly_attributesRlR*R¬R×tget_ipa_configRNtpossible_objectclassesRtBackendR™tschematattribute_typesRQRstnamesR=tsortRâ( R®R>t json_dictt objectclassestconfigR@tattrlisttoidR$R1((R®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt__json__Zs*        N(RRšRž(s Member OfRŸR (sIndirect MemberNR¢(sIndirect Member OfNR¤(s parent_objects container_dns object_namesobject_name_plurals object_classsobject_class_configsdefault_attributesslabelslabel_singularshidden_attributessuuid_attributesattribute_memberssnames takes_paramss rdn_attributesbindables relationships(-t__name__t __module__t__doc__t backend_nameR§R¨R RÑRÖR¬R9R×Råtlimit_object_classestdisallow_object_classestsearch_attributestsearch_attributes_configRØtsearch_display_attributesRÚR©RÛRÀROtrdn_is_primary_keyRÇRÝRÞRRÙtcontainer_not_found_msgtparent_not_found_msgRÐRÔRrR±R´R¸R¿RÆRÍRÒRÕRãRð(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR˜©s^                 cCszxs|jƒD]e\}}t|ttfƒr t|ƒdkr ||krr||j rrtjd|ƒ‚qrq q WdS(NiR$(RQR7RZR[R.t multivalueRtOnlyOneValueAllowed(tparamsR_RàRE((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt_check_single_value_attrszs'cCsxx|jƒD]j\}}|dksFt|tƒr t|ƒdkr ||krw||jrwtjd|ƒ‚qwq q WdS(NiR*(RQR9R7t basestringR.RµRtRequirementError(RÿR_RàRE((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt_check_empty_attrs‚s-c Cs¨t|dƒdkr0t|dƒdkr0dSt|ƒ}x|djƒD]}\}}|jdjƒ|krM|s­tjdtdƒtd|jdjƒƒƒ‚n|j |jdjƒƒqMqMWx|djƒD]}\}}|jdjƒ|krß|s?tjdtdƒtd|jdjƒƒƒ‚n|j |jdjƒƒqßqßWt|ƒdkr¤|r¤tjdtdƒtd|dƒƒ‚ndS(s+ If the set of objectclasses is limited enforce that only those are updated in entry_attrs (plus dn) allow_only tells us what mode to check in: If True then we enforce that the attributes must be in the list of allowed. If False then those attributes are not allowed. iiNtinfos%attribute "%(attribute)s" not allowedt attribute( R.RRQRéR=RtObjectclassViolationR RPRŠ(t attributesR@t allow_onlyt limitattrsRïR$((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt_check_limit_object_class‰s* ,  ! ! tCallbackInterfacecBs8eZdZeƒZed„ƒZeed„ƒZRS(s•Callback registration interface This class's subclasses allow different types of callbacks to be added and removed to them. Registering a callback is done either by ``register_callback``, or by defining a ``_callback`` method. Subclasses should define the `_callback_registry` attribute as a dictionary mapping allowed callback types to (initially) empty dictionaries. ccso|j|j|dgƒ}xL|D]D}|dkrbyt|d|ƒVWqgtk r^qgXq#|Vq#WdS(s!Yield callbacks of the given types %s_callbackN(t_callback_registryRNR9RßtAttributeError(tclst callback_typet callbackstcallback((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt get_callbacks¼s   cCs}t|ƒst‚y|j||}Wn)tk rRdg}|j||R@tnewdictRàR1R$R]((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt_convert_2_dictûs,    !   cs}t‡fd†dDƒƒr dS|jj}|j|ˆjdgƒƒ}|j|ˆjdgƒƒ}|j|ˆjdgƒƒ}t|jƒƒ} t|jƒƒ} t|jƒƒ} |dkrÝ| } | } g}n=t|t ƒsòt ‚| | @} | | @} t | | B| ƒ}x$|j ƒD]\}}|||:sR&R!R(NR$R]css|]}|jƒVqdS(N(R=(RLtn((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pys ssR*R+sNo such attribute on this entryii(ssetattrsaddattrsdelattr(&RMR#RªR%RNRqRFR9R7RR8RZRQR²R[textendRŠReRtAttrValueNotFoundt _exc_wrapperRYR”RÒR0tpopR R!Rftbase64t b64encodeRÿRRýR.RþR+tConversionError(R®R_R?RFRRR>tadddicttsetdicttdeldicttsetattrstaddattrstdelattrst direct_addt direct_delt needldapattrsR$tvaltdelvalt old_entryRétdel_nonexistingt changedattrstparamR]terr((RRs5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytprocess_attr_options!s¢           $    '       3  /cCs|jd||ƒdS(s*Shortcut for register_callback('pre', ...)RN(R(RRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytregister_pre_callback¦scCs|jd||ƒdS(s+Shortcut for register_callback('post', ...)RN(R(RRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytregister_post_callback«scCs|jd||ƒdS(s*Shortcut for register_callback('exc', ...)RN(R(RRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytregister_exc_callback°scCs|jd||ƒdS(s9Shortcut for register_callback('interactive_prompt', ...)RN(R(RRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt$register_interactive_prompt_callbackµscs‡‡‡‡fd†}|S(s=Function wrapper that automatically calls exception callbackscs•ˆ}tˆjdƒƒ}xstry|||ŽSWqtjk rŒ‰|sV‚n|jdƒ‰‡‡‡‡‡‡fd†}|}qXqWdS(NRicsˆˆˆˆˆˆ||ŽS(N((targsR¯(t call_funcRRIRFRRR®(s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytexc_funcÈs(RZRRdRtExecutionErrorR*(t call_argst call_kwargstfuncRRE(RDRFRRR®(RRIs5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytwrapped¼s ((R®RFRRRDRJ((RDRFRRR®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR)ºsc cs”x"tt|ƒjƒD] }|VqW|jjrx\|jD]N}t|tjtj fƒr;t ddt dƒdddddgƒVPq;q;WndS( Nt no_membersRs-Suppress processing of membership attributes.RRRRit no_output( tsuperRt get_optionsR#RÀt has_outputR7R R¦t ListOfEntriesRR (R®R<to((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRNÎs    (RñRòRóR R'R tsetattr_optionR%taddattr_optionR)tdelattr_optionRPR R%R>RROR?R@RARBR)RN(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRâs:         ! & … t LDAPCreatecBskeZdZejejfZd„ZeZ d„Z d„Z d„Z d„Z d„Zd Zd„ZRS( s% Create a new entry in LDAP. ccsqx|jjƒD] }|VqW|jjrE|jjjdtƒVnx%ttj|ƒjƒD] }|Vq^WdS(NR( R#R¸RltcloneRdRMRtCreatetget_args(R®R»targ((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRXás   c OsX|jj}|j||Ž}|jtƒ|ƒ}|j|d||ƒt|jjƒ|d<|jj rž|j ƒd}|j |jj |dƒ|dd|d|dƒSt>d|ddƒS(NR‘it autogenerateiRMR2RKRRRÎiþÿÿÿtparentRÏt containeriÿÿÿÿRR?RSR]u(?R#Rªtargs_options_2_entryt make_entryRR>R9RR¬R×RäRNRÛRrR7R8R©R$R³R²RlR*RÕtmake_dnR¨RR’R“RORØRqtupdateRFtdifference_updateRÀRZRRRÿR RæR™RçRèRõRdRöR)t add_entryRR”R§RüRRÑRûRÓR«RYRÒRÆRTRP( R®RFRRR>R_RíR?tdn_attrt attrs_listRR[R¬((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytexecuteìs”      ! 44#        $ cOst|tƒst‚|S(N(R7RR8(R®R>R?R_RdRFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt pre_callbackSscOst|tƒst‚|S(N(R7RR8(R®R>R?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt post_callbackWscOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt exc_callback[scCsdS(N((R®tkw((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytinteractive_prompt_callback^st takes_argscs9t‡fd†ˆjDƒƒ}tˆjƒƒ|d<|S(Nc3s$|]}|tˆ|ƒfVqdS(N(Rß(RLRà(R®(s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pys hst takes_options(RPRãRZtget_json_options(R®Rë((R®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRðfs(s takes_args(RñRòRóRRRRSRlRXtglobal_output_paramsthas_output_paramsReRfRgRhRjRãRð(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRUÛs  g    t LDAPQuerycBs&eZdZd„ZdZd„ZRS(sJ Base class for commands that need to retrieve an existing entry. ccswx|jjƒD] }|VqW|jjrK|jjjdtdtƒVnx%ttj|ƒjƒD] }|VqdWdS(NRR¶( R#R¸RlRVRdRMRtPKQueryRX(R®R»RY((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRXqs    Rkcs9t‡fd†ˆjDƒƒ}tˆjƒƒ|d<|S(Nc3s$|]}|tˆ|ƒfVqdS(N(Rß(RLRà(R®(s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pys sRl(RPRãRZRm(R®Rë((R®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRðs(s takes_args(RñRòRóRXRãRð(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRpms tLDAPMultiQuerycBs8eZdZeddddedƒƒfZd„ZRS(sU Base class for commands that need to retrieve one or more existing entries. tcontinueR·Rs&Continuous mode: Don't stop on errors.ccs}x|jjƒD] }|VqW|jjrQ|jjjdtdtdtƒVnx%ttj|ƒjƒD] }|VqjWdS(NRR¶Rý( R#R¸RlRVRdRMRRqRX(R®R»RY((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRX‘s  (RñRòRóRR RlRX(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRr†s  t LDAPRetrievecBsqeZdZejZeZedde dƒde dƒƒfZ d„Z d„Z d„Z d „Zd „ZRS( s! Retrieve an LDAP entry. RARtRightsRsWDisplay the access rights of this entry (requires --all). See ipa man page for details.c Osc|jj}|jj||Ž}t|tƒs6t‚|jdtƒr^dg|jj}nFt |jjƒ}|jdtƒr˜|j |jj ƒnt |ƒ}xG|j dƒD]6}|||||||Ž}t|tƒs´t‚q´Wy@|j|||jƒ||ƒ\}}t|tƒs-t‚Wn$tjk rT|jj|ŒnX|jdtƒr|jdtƒrt||ƒ|dR?RdRR_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRe«s<  $ cOst|tƒst‚|S(N(R7RR8(R®R>R?RdRFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRfÖscOst|tƒst‚|S(N(R7RR8(R®R>R?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRgÚscOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhÞscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjás(RñRòRóR tstandard_entryRORnRoRR RlReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRts    +   t LDAPUpdatec BsŒeZdZejejejeddedƒdedƒƒfZ e Z d„Z d„Z d„Zd „Zd „Zd „Zd „ZRS( s Update an LDAP entry. RARRuRsWDisplay the access rights of this entry (requires --all). See ipa man page for details.c Csbt|jj|jjjƒ}|jddddtdtdƒdtdƒtd|jj ƒƒS( NtrenameR·RµRtRenameRs#Rename the %(ldap_obj_name)s objectRÃ( RßR#RÿRlR*t clone_renameROR RPRÑ(R®trdnparam((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyt_get_rename_optionös  ccsCx"tt|ƒjƒD] }|VqW|jjr?|jƒVndS(N(RMRwRNR#RúR|(R®toption((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRNÿs  c OsÚ|jj}t|ƒdkr-tjƒ‚n|jj||Ž}t|tƒsWt‚|j |}|j ||ƒ}|j ||||ƒ|j dt ƒr¶dg|jj}nYt|jjƒ}|j|jƒƒ|j dt ƒr|j|jjƒnt|ƒ}t|j|ƒt|jj|ƒxJ|jdƒD]9}||||||||Ž}t|tƒsBt‚qBWt|jjjjj|jjƒ|jƒdt ƒt|jjjjj|jj!ƒ|jƒdt ƒt }yY|jj"rGd|krG|ds-tj#ddd d ƒ‚n|d||jj$j%RNRORØRqR`RFRaRÀRZRRÿRRR RRæR™RçRèRõRdRöRúR0RlR*R)tupdate_entry_rdnRRxR”RÒRYtMidairCollisionR R:RÆRTR9RP( R®RFRRR>R?R_RdRR~trdnkeysRI((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyResz  44 !)  #  $cOst|tƒst‚|S(N(R7RR8(R®R>R?R_RdRFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRf]scOst|tƒst‚|S(N(R7RR8(R®R>R?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRgascOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhescCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjhs(RñRòRóRRRRSRTRR RlRnRoR|RNReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRwås    X   t LDAPDeletecBsJeZdZejZeZd„Zd„Z d„Z d„Z d„Z RS(s@ Delete an LDAP entry and all of its direct subentries. c sPˆjj‰‡‡‡‡fd†}ˆjj sKtˆdttfƒ r[ˆdf}n ˆd}g}g}t}xp|D]h}y||ƒsœt}nWn9tj k r؈j dtƒsÈ‚n|j |ƒq~X|j |ƒq~Wˆjjr4|ddk r4t dt ddj|ƒƒddj|ƒƒSt dt dd ƒdd ƒS( Ncs7ˆd |f‰ˆjjˆˆŽ}t|tƒs;t‚xDˆjdƒD]3}|ˆˆ|ˆˆŽ}t|tƒsKt‚qKW‡‡‡‡‡fd†‰y ˆjˆˆˆjƒ|ƒWnAtj k rãˆjj ˆŒntj k rˆ|ƒnXx/ˆjdƒD]}|ˆˆ|ˆˆŽ}qW|S(NiÿÿÿÿRcsÔt|tƒst‚t}xk|rˆy(ˆjddg|ˆjƒ\}}Wntjk rcPqXx|D]\}}ˆ|ƒqkWqWy ˆj ˆˆˆj ƒ|ƒWn$tjk rψj j ˆŒnXdS(NRš( R7RR8RdRÈR9tSCOPE_ONELEVELRR”R)t delete_entryR#RÒ(tbase_dnRÌt subentriestdn_R_(tdelete_subtreeR>tnkeysRRR®(s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR‰€s " R( R#RrR7RR8RR)R…RR”RÒtNotAllowedOnNonLeaf(R¼R?RRS(RFR>RRR®(R‰RŠs5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR…ws  iÿÿÿÿRsiRSRu,R]u(R#RªRlR7RZR[RdRORRFRNRsR9RPtjoin( R®RFRRR…tpkeyitertdeletedRRSR¼((RFR>RRR®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRets( ('    .cOst|tƒst‚|S(N(R7RR8(R®R>R?RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRf¶scOst|tƒst‚tS(N(R7RR8Rd(R®R>R?RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRgºscOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRh¾scCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjÁs( RñRòRóR tstandard_deleteRORnRoReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRƒls  B   t LDAPModMembercBs;eZdZdgZedƒZdZd„Zd„ZRS(s- Base class for member manipulation. Rs%ss%i member processed.s%i members processed.ccsÂx"tt|ƒjƒD] }|VqWx–|jD]‹}x‚|jj|D]p}|jj|}t|ƒ}|j |j }t d|dd|d|dt dƒ|j dtdtƒVqFWq/WdS( Ns%s*R·s%ssRRs member %stcsvt alwaysask(RMRRNtmember_attributesR#RÀRRR tmember_param_docRÖR R RÑRd(R®R}R$RÃRÄR*R((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRNÍs  c Ks"i}i}x |jD]þ}i||t member_dnsRR?RR|R$tobjsRÃtm_dnRIRÄRdR_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRes^      cOst|tƒst‚|S(N(R7RR8(R®R>R?tfoundt not_foundRFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRfFscOst|tƒst‚||fS(N(R7RR8(R®R>R|RR?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRgJscOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhNscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjQs(s%i member added.s%i members added.(RñRòRóR R”R˜RORšR R¦tOutputRPtintRORnRoReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR™ðs"      @   tLDAPRemoveMemberc Bs¡eZdZedƒZdZejdƒejdde dedƒƒejd de ded ƒƒfZ e Z d „Zd „Zd „Zd„Zd„ZRS(s+ Remove LDAP entries from members. s %s to removes%i member removed.s%i members removed.RSRR Rs!Members that could not be removedR|sNumber of members removedc Os|jj}|j|\}}|jj||Ž}t|tƒsKt‚xJ|jdƒD]9}||||||||Ž}t|tƒs[t‚q[Wd}xÝ|jƒD]Ï\} } xÀ| jƒD]²\} } x£| D]›} t| tƒsòt‚| sþq×ny|j | || ƒWnPt j k rg}|j j | }|| | j|j| ƒt|ƒfƒq×X|d7}q×WqÄWq«W|jdtƒr¦dg|jj}nYt|jjƒ}|j|jƒƒ|jdtƒró|j|jjƒnt|ƒ}tjdƒy+|j|||jƒ||ƒ\}}Wn$t jk r]|jj|ŒnXxS|jdƒD]B}|||||||||Ž\}}t|tƒsnt‚qnW|jj |||Žt|tƒsßt‚t!||}||d RœRR?RR|R$RRÃtm_dnsRžRIRÄRdR_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRejs`      cOst|tƒst‚|S(N(R7RR8(R®R>R?RŸR RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRf­scOst|tƒst‚||fS(N(R7RR8(R®R>R|RR?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRg±scOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhµscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRj¸s(s%i member removed.s%i members removed.(RñRòRóR R”R˜R R¦R¡RPR¢RORnRoReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR£Us       C   cCs,tddtdƒdtdƒt|ƒƒS(Ns pkey_only?RsPrimary key onlyRs8Results should contain primary key attribute only ("%s")(RR R (R·((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytgen_pkey_only_option¼s   t LDAPSearchc Bs eZdZgZedƒZedƒZeZe ddedƒdedƒdd gd d d e ƒe d dedƒdedƒdd gd d d e ƒfZ d„Z d„Z d„Zd„ZeZd„Zd„Zd„Zd„Zd„ZdZd„ZRS(s@ Retrieve all LDAP entries matching the given criteria. sKSearch for %(searched_object)s with these %(relationship)s %(ldap_object)s.sNSearch for %(searched_object)s without these %(relationship)s %(ldap_object)s.s timelimit?Rs Time LimitRsTime limit of search in secondsRt no_displaytminvalueitautofills sizelimit?s Size Limits"Maximum number of entries returnedccshx|jjƒD] }|VqWtddtdtdƒƒVx%ttj|ƒjƒD] }|VqUWdS(Ns criteria?tnoextrawhitespaceRs3A string searched in all relevant object attributes( R#R¸R ROR RMRtSearchRX(R®R»RY((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRXàs  c csJxC|jj|D]1}|jj|}|jjj|dddgƒ}|jtd|jjd|dj ƒd|jƒ}d|d t |ƒf}t d |d d |d |d|j dt ƒV|jtd|jjd|dj ƒd|jƒ}d|dt |ƒf}t d |d d |d |d|j dt ƒVqWdS(NRRšRžtsearched_objectt relationshipit ldap_objects%s%sis%s*R·s%ssRRR‘i(R#RÀRRRÞRNtmember_param_incl_docRPRÖR=R R RÑRdtmember_param_excl_doc(R®R$RÃRÄR®RR*((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytget_member_optionsês(       ccs”x"tt|ƒjƒD] }|VqW|jjr]d|jjjkr]t|jjjƒVnx0|jD]%}x|j |ƒD] }|Vq}WqgWdS(NRL( RMR§RNR#RlRR¦R·R“R²(R®R}R$((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRNs  cKs/d}x"|jD]}x|jj|D]ü}|jj|}|jjj|dddgƒ}|d}|j|jf} x¦t || ƒD]•\} } d| t |ƒf} |j| ƒrŠg} x(|| D]}| j |j |ƒƒqÌW|j || | ƒ}|j||f|jƒ}qŠqŠWq'WqW|S(NRšRRžis%s%s(R“R#RÀRRRÞRNt MATCH_ALLt MATCH_NONEtzipR RsRrtmake_filter_from_attrtcombine_filters(R®R>RRtfilterR$RÃRÄR®tparam_prefixestrulest param_prefixtrulet param_nameR–R¼tflt((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pytget_member_filters$  $c s^ˆjj}|d}ˆjjrHˆjjˆjjj|d Œ}ntˆjjtjj ƒ}t |tƒsxt ‚ˆj |}ˆjj r¢ˆjj }n ˆjj}|jdtƒrÕˆjjjg}nu|jdtƒr÷dg|}nSt|ƒ}|j|jƒƒ|jdtƒr>|jˆjjƒnt|ƒ}ˆjjreˆjj} n ˆjj} ˆjjrã|jƒd} | jˆjjgƒ} t| ƒdkrãt | dtƒrã| djdƒ} qãnˆjj|d <|j |d |j!ƒ} i}x| D]} ||| t.|ƒD]0\}}t/||||<|j0||dttermR†t search_kwtdefattrsRdt search_attrsRít config_attrst attr_filterRàt term_filtert member_filterR¸tscopeRR›RÌRÇRIti((R®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRe)s„   &         '   ! cOs"t|tƒst‚|||fS(N(R7RR8(R®R>tfiltersRdR†RÔRCRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRf…scOs|S(N((R®R>R›RÌRCRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRg‰scOs |‚dS(N((R®RCRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhŒscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjsRkcs9t‡fd†ˆjDƒƒ}tˆjƒƒ|d<|S(Nc3s$|]}|tˆ|ƒfVqdS(N(Rß(RLRà(R®(s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pys ™sRl(RPRãRZRm(R®Rë((R®s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRð—s(s takes_args(RñRòRóR“R R°R±RdRÊRRORlRXR²RNR¿RnRoReRfRgRhRjRãRð(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyR§Âs:              \    tLDAPModReverseMembercBs8eZdZdgZedƒZdZeZd„Z RS(s5 Base class for reverse member manipulation. Rs%ss%i member processed.s%i members processed.ccs¸x"tt|ƒjƒD] }|VqWxŒ|jD]}xx|jj|D]f}|jj|}t|ƒ}|j |j }t d|dd|d|d|j dt dt ƒVqFWq/WdS(Ns%s*R·s%ssRRR‘R’(RMR×RNtreverse_attributesR#treverse_membersRRR treverse_param_docRÖR RÑRd(R®R}R$RÃRÄR*R((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRN¨s  (s%i member processed.s%i members processed.( RñRòRóRØR RÚtreverse_count_outRnRoRN(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRמs   tLDAPAddReverseMemberc Bs¹eZdZedƒZdZdZdZdZ dZ e j dƒe j ddededƒƒe j d deded ƒƒfZeZd „Zd „Zd „Zd„Zd„ZRS(sŸ Add other LDAP entries to members in reverse. The call looks like "add A to B" but in fact executes add B to A to handle reverse membership. s %s to adds%i member added.s%i members added.RSRR RsMembers that could not be addedR|sNumber of members addedc Osq|jj}|jj|j|dƒd}|d}t|tƒsLt‚xD|jdƒD]3}||||||Ž}t|tƒs\t‚q\W|j dt ƒr»dg|jj }nFt |jj ƒ}|j dt ƒrõ|j |jjƒnt|ƒ}|jj|j|dƒd}d} iig|j6d 6} xa|j |jƒpWgD]G} yi|dd |j6}y|j|||jj|jƒ| |}|d d krÄ| d } n5| d |jj| |d d |jdd fƒWndtjk r`} t| ƒ} | jdd ƒ\} } | d |jj| t| jƒƒfƒnXWqXtjk rž} | d |jj| t| ƒfƒqXXqXW|j|dgƒ\}}|jj|||ŽxS|jdƒD]B}|||| | ||||Ž\} }t|tƒsät‚qäWt|tƒs?t‚t||}||dRSR?RRdt entry_startR|RR$RIR†R_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyReÒsX !  !+ 9 2, cOst|tƒst‚|S(N(R7RR8(R®R>R?RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRfscOst|tƒst‚||fS(N(R7RR8(R®R>R|RR?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRgscOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRjs(s%i member added.s%i members added.N(RñRòRóR R”R˜R9RÝRàRÞRßR R¦R¡RPR¢RORnRoReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRܵs(      >   tLDAPRemoveReverseMemberc Bs¹eZdZedƒZdZdZdZdZ dZ e j dƒe j ddededƒƒe j d deded ƒƒfZeZd „Zd „Zd „Zd„Zd„ZRS(s® Remove other LDAP entries from members in reverse. The call looks like "remove A from B" but in fact executes remove B from A to handle reverse membership. s %s to removes%i member removed.s%i members removed.RSRR Rs!Members that could not be removedR|sNumber of members removedc Osq|jj}|jj|j|dƒd}|d}t|tƒsLt‚xD|jdƒD]3}||||||Ž}t|tƒs\t‚q\W|j dt ƒr»dg|jj }nFt |jj ƒ}|j dt ƒrõ|j |jjƒnt|ƒ}|jj|j|dƒd}d} iig|j6d 6} xa|j |jƒpWgD]G} yi|dd |j6}y|j|||jj|jƒ| |}|d d krÄ| d } n5| d |jj| |d d |jdd fƒWndtjk r`} t| ƒ} | jdd ƒ\} } | d |jj| t| jƒƒfƒnXWqXtjk rž} | d |jj| t| ƒfƒqXXqXW|j|dgƒ\}}|jj|||ŽxS|jdƒD]B}|||| | ||||Ž\} }t|tƒsät‚qäWt|tƒs?t‚t||}||dRSR?RRdRáR|RR$RIR†R_((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRe;sX !  !+ 9 2, cOst|tƒst‚|S(N(R7RR8(R®R>R?RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRfyscOst|tƒst‚||fS(N(R7RR8(R®R>R|RR?R_RFRR((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRg}scOs |‚dS(N((R®RFRRRRDRGRH((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRhscCsdS(N((R®Ri((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRj„s(s%i member removed.s%i members removed.N(RñRòRóR R”R˜R9RÝRàRÞRßR R¦R¡RPR¢RORnRoReRfRgRhRj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyRâs(      >   (DRóR,RWtcopyRR+tipalibRRRRRRRRR t ipalib.cliR R t ipalib.textR t ipalib.utilR Rt ipapython.dnRRt DNA_MAGICRnR%R'R)R"R9R:RJRTRaRhtexternal_host_paramRoR‰RŒR—R˜RRR R RRWRURqRpRrRttUpdateRwRƒRR™R£R¦R¬R§R×RÜRâ(((s5/home/mkosek/freeipa-clean/ipalib/plugins/baseldap.pyts                                                                                            #      9 " Ñ   %4ù’H‡Y+eg Üifreeipa-3.3.4/ipalib/plugins/permission.py0000664000175000017500000004471012271663206020200 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib.plugins.baseldap import * from ipalib import api, _, ngettext from ipalib import Flag, Str, StrEnum from ipalib.request import context from ipalib import errors from ipapython.dn import DN, EditableDN __doc__ = _(""" Permissions A permission enables fine-grained delegation of rights. A permission is a human-readable form of a 389-ds Access Control Rule, or instruction (ACI). A permission grants the right to perform a specific task such as adding a user, modifying a group, etc. A permission may not contain other permissions. * A permission grants access to read, write, add or delete. * A privilege combines similar permissions (for example all the permissions needed to add a user). * A role grants a set of privileges to users, groups, hosts or hostgroups. A permission is made up of a number of different parts: 1. The name of the permission. 2. The target of the permission. 3. The rights granted by the permission. Rights define what operations are allowed, and may be one or more of the following: 1. write - write one or more attributes 2. read - read one or more attributes 3. add - add a new entry to the tree 4. delete - delete an existing entry 5. all - all permissions are granted Read permission is granted for most attributes by default so the read permission is not expected to be used very often. Note the distinction between attributes and entries. The permissions are independent, so being able to add a user does not mean that the user will be editable. There are a number of allowed targets: 1. type: a type of object (user, group, etc). 2. memberof: a member of a group or hostgroup 3. filter: an LDAP filter 4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a super-set of the "type" target. 5. targetgroup: grant access to modify a specific group (such as granting the rights to manage group membership) EXAMPLES: Add a permission that grants the creation of users: ipa permission-add --type=user --permissions=add "Add Users" Add a permission that grants the ability to manage group membership: ipa permission-add --attrs=member --permissions=write --type=group "Manage Group Members" """) ACI_PREFIX=u"permission" output_params = ( Str('ipapermissiontype', label=_('Permission Type'), ), Str('aci', label=_('ACI'), ), ) def filter_options(options, keys): """Return a dict that includes entries from `options` that are in `keys` example: >>> filtered = filter_options({'a': 1, 'b': 2, 'c': 3}, ['a', 'c']) >>> filtered == {'a': 1, 'c': 3} True """ return dict((k, options[k]) for k in keys if k in options) class permission(LDAPObject): """ Permission object. """ container_dn = api.env.container_permission object_name = _('permission') object_name_plural = _('permissions') object_class = ['groupofnames', 'ipapermission'] default_attributes = ['cn', 'member', 'memberof', 'memberindirect', 'ipapermissiontype', ] aci_attributes = ['aci', 'group', 'permissions', 'attrs', 'type', 'filter', 'subtree', 'targetgroup', 'memberof', ] attribute_members = { 'member': ['privilege'], 'memberindirect': ['role'], } rdn_is_primary_key = True label = _('Permissions') label_singular = _('Permission') takes_params = ( Str('cn', cli_name='name', label=_('Permission name'), primary_key=True, pattern='^[-_ a-zA-Z0-9]+$', pattern_errmsg="May only contain letters, numbers, -, _, and space", ), Str('permissions+', cli_name='permissions', label=_('Permissions'), doc=_('Permissions to grant ' \ '(read, write, add, delete, all)'), csv=True, ), Str('attrs*', cli_name='attrs', label=_('Attributes'), doc=_('Attributes to which the permission applies'), csv=True, normalizer=lambda value: value.lower(), flags=('ask_create'), ), StrEnum('type?', cli_name='type', label=_('Type'), doc=_('Type of IPA object (user, group, host, hostgroup, service, netgroup, dns)'), values=(u'user', u'group', u'host', u'service', u'hostgroup', u'netgroup', u'dnsrecord',), flags=('ask_create'), ), Str('memberof?', cli_name='memberof', label=_('Member of group'), # FIXME: Does this label make sense? doc=_('Target members of a group'), flags=('ask_create'), ), Str('filter?', cli_name='filter', label=_('Filter'), doc=_('Legal LDAP filter (e.g. ou=Engineering)'), flags=('ask_create'), ), Str('subtree?', cli_name='subtree', label=_('Subtree'), doc=_('Subtree to apply permissions to'), flags=('ask_create'), ), Str('targetgroup?', cli_name='targetgroup', label=_('Target group'), doc=_('User group to apply permissions to'), flags=('ask_create'), ), ) # Don't allow SYSTEM permissions to be modified or removed def check_system(self, ldap, dn, *keys): try: (dn, entry_attrs) = ldap.get_entry(dn, ['ipapermissiontype']) except errors.NotFound: self.handle_not_found(*keys) if 'ipapermissiontype' in entry_attrs: if 'SYSTEM' in entry_attrs['ipapermissiontype']: return False return True def filter_aci_attributes(self, options): """Return option dictionary that only includes ACI attributes""" return dict((k, v) for k, v in options.items() if k in self.aci_attributes) api.register(permission) class permission_add(LDAPCreate): __doc__ = _('Add a new permission.') msg_summary = _('Added permission "%(value)s"') has_output_params = LDAPCreate.has_output_params + output_params def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Test the ACI before going any further opts = self.obj.filter_aci_attributes(options) opts['test'] = True opts['permission'] = keys[-1] opts['aciprefix'] = ACI_PREFIX self.api.Command.aci_add(keys[-1], **opts) # Clear the aci attributes out of the permission entry for o in options: try: if o not in ['objectclass']: del entry_attrs[o] except: pass return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # Now actually add the aci. opts = self.obj.filter_aci_attributes(options) opts['test'] = False opts['permission'] = keys[-1] opts['aciprefix'] = ACI_PREFIX try: result = self.api.Command.aci_add(keys[-1], **opts)['result'] for attr in self.obj.aci_attributes: if attr in result: entry_attrs[attr] = result[attr] except errors.InvalidSyntax, e: # A syntax error slipped past our attempt at validation, clean up self.api.Command.permission_del(keys[-1]) raise e except Exception, e: # Something bad happened, clean up as much as we can and return # that error try: self.api.Command.permission_del(keys[-1]) except Exception, ignore: pass try: self.api.Command.aci_del(keys[-1], aciprefix=ACI_PREFIX) except Exception, ignore: pass raise e return dn api.register(permission_add) class permission_add_noaci(LDAPCreate): __doc__ = _('Add a system permission without an ACI') msg_summary = _('Added permission "%(value)s"') has_output_params = LDAPCreate.has_output_params + output_params NO_CLI = True takes_options = ( StrEnum('permissiontype?', label=_('Permission type'), values=(u'SYSTEM',), ), ) def get_args(self): # do not validate system permission names yield self.obj.primary_key.clone(pattern=None, pattern_errmsg=None) def get_options(self): for option in super(permission_add_noaci, self).get_options(): # filter out ACI options if option.name in self.obj.aci_attributes: continue yield option def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) permission_type = options.get('permissiontype') if permission_type: entry_attrs['ipapermissiontype'] = [ permission_type ] return dn api.register(permission_add_noaci) class permission_del(LDAPDelete): __doc__ = _('Delete a permission.') msg_summary = _('Deleted permission "%(value)s"') takes_options = LDAPDelete.takes_options + ( Flag('force', label=_('Force'), flags=['no_option', 'no_output'], doc=_('force delete of SYSTEM permissions'), ), ) def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) if not options.get('force') and not self.obj.check_system(ldap, dn, *keys): raise errors.ACIError( info=_('A SYSTEM permission may not be removed')) # remove permission even when the underlying ACI is missing try: self.api.Command.aci_del(keys[-1], aciprefix=ACI_PREFIX) except errors.NotFound: pass return dn api.register(permission_del) class permission_mod(LDAPUpdate): __doc__ = _('Modify a permission.') msg_summary = _('Modified permission "%(value)s"') has_output_params = LDAPUpdate.has_output_params + output_params def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if not self.obj.check_system(ldap, dn, *keys): raise errors.ACIError( info=_('A SYSTEM permission may not be modified')) # check if permission is in LDAP try: (dn, attrs) = ldap.get_entry(dn, attrs_list) except errors.NotFound: self.obj.handle_not_found(*keys) # when renaming permission, check if the target permission does not # exists already. Then, make changes to underlying ACI if 'rename' in options: if options['rename']: try: try: new_dn = EditableDN(dn) new_dn[0]['cn'] # assure the first RDN has cn as it's type except (IndexError, KeyError), e: raise ValueError("expected dn starting with 'cn=' but got '%s'" % dn) new_dn[0].value = options['rename'] (new_dn, attrs) = ldap.get_entry(new_dn, attrs_list) raise errors.DuplicateEntry() except errors.NotFound: pass # permission may be renamed, continue else: raise errors.ValidationError( name='rename', error=_('New name can not be empty')) opts = self.obj.filter_aci_attributes(options) setattr(context, 'aciupdate', False) # If there are no options left we don't need to do anything to the # underlying ACI. if len(opts) > 0: opts['permission'] = keys[-1] opts['aciprefix'] = ACI_PREFIX self.api.Command.aci_mod(keys[-1], **opts) setattr(context, 'aciupdate', True) # Clear the aci attributes out of the permission entry for o in self.obj.aci_attributes: try: del entry_attrs[o] except: pass return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): if call_func.func_name == 'update_entry': if isinstance(exc, errors.EmptyModlist): aciupdate = getattr(context, 'aciupdate') if aciupdate: return raise exc def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # rename the underlying ACI after the change to permission cn = keys[-1] if 'rename' in options: self.api.Command.aci_mod(cn,aciprefix=ACI_PREFIX, permission=options['rename']) self.api.Command.aci_rename(cn, aciprefix=ACI_PREFIX, newname=options['rename']) cn = options['rename'] # rename finished # all common options to permission-mod and show need to be listed here common_options = filter_options(options, ['all', 'raw', 'rights']) result = self.api.Command.permission_show(cn, **common_options)['result'] for r in result: if not r.startswith('member_'): entry_attrs[r] = result[r] return dn api.register(permission_mod) class permission_find(LDAPSearch): __doc__ = _('Search for permissions.') msg_summary = ngettext( '%(count)d permission matched', '%(count)d permissions matched', 0 ) has_output_params = LDAPSearch.has_output_params + output_params def post_callback(self, ldap, entries, truncated, *args, **options): # There is an option/param overlap: "cn" must be passed as "aciname" # to aci-find. Besides that we don't need cn anymore so pop it aciname = options.pop('cn', None) pkey_only = options.pop('pkey_only', False) if not pkey_only: for entry in entries: (dn, attrs) = entry try: common_options = filter_options(options, ['all', 'raw']) aci = self.api.Command.aci_show(attrs['cn'][0], aciprefix=ACI_PREFIX, **common_options)['result'] # copy information from respective ACI to permission entry for attr in self.obj.aci_attributes: if attr in aci: attrs[attr] = aci[attr] except errors.NotFound: self.debug('ACI not found for %s' % attrs['cn'][0]) if truncated: # size/time limit met, no need to search acis return truncated if 'sizelimit' in options: max_entries = options['sizelimit'] else: config = ldap.get_ipa_config()[1] max_entries = config['ipasearchrecordslimit'] # Now find all the ACIs that match. Once we find them, add any that # aren't already in the list along with their permission info. opts = self.obj.filter_aci_attributes(options) if aciname: opts['aciname'] = aciname opts['aciprefix'] = ACI_PREFIX # permission ACI attribute is needed aciresults = self.api.Command.aci_find(*args, **opts) truncated = truncated or aciresults['truncated'] results = aciresults['result'] for aci in results: found = False if 'permission' in aci: for entry in entries: (dn, attrs) = entry if aci['permission'] == attrs['cn'][0]: found = True break if not found: common_options = filter_options(options, ['all', 'raw']) permission = self.api.Command.permission_show( aci['permission'], **common_options)['result'] dn = permission['dn'] del permission['dn'] if pkey_only: pk = self.obj.primary_key.name new_entry = ldap.make_entry(dn, {pk: permission[pk]}) else: new_entry = ldap.make_entry(dn, permission) if (dn, permission) not in entries: if len(entries) < max_entries: entries.append(new_entry) else: truncated = True break return truncated api.register(permission_find) class permission_show(LDAPRetrieve): __doc__ = _('Display information about a permission.') has_output_params = LDAPRetrieve.has_output_params + output_params def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) try: common_options = filter_options(options, ['all', 'raw']) aci = self.api.Command.aci_show(keys[-1], aciprefix=ACI_PREFIX, **common_options)['result'] for attr in self.obj.aci_attributes: if attr in aci: entry_attrs[attr] = aci[attr] except errors.NotFound: self.debug('ACI not found for %s' % entry_attrs['cn'][0]) if options.get('rights', False) and options.get('all', False): # The ACI attributes are just broken-out components of aci so # the rights should all match it. for attr in self.obj.aci_attributes: entry_attrs['attributelevelrights'][attr] = entry_attrs['attributelevelrights']['aci'] return dn api.register(permission_show) class permission_add_member(LDAPAddMember): """ Add members to a permission. """ NO_CLI = True api.register(permission_add_member) class permission_remove_member(LDAPRemoveMember): """ Remove members from a permission. """ NO_CLI = True api.register(permission_remove_member) freeipa-3.3.4/ipalib/plugins/dns.pyc0000664000175000017500000030213312271707517016737 0ustar mkosekmkosekó †fçRc"@@sP ddlmZddlZddlZddlZddlZddlmZddl m Z m Z m Z ddl m Z ddlmZmZmZmZmZmZmZmZddlTddl mZmZdd lmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%dd l&m'Z'm(Z(m)Z)ed ƒZ*d d ddddddddddddddddddd d!d"d#d$d%d&d'd(d)d*d+d,d-f"Z+d.Z,d/d0fZ-d1fZ.d2d3d4fZ/ge+D]Z0e1d5e0j2ƒƒ^qçZ3d6d7d8d9fZ4d:„Z5d;„Z6d<„Z7e8d=„Z9d>„Z:d?„Z;d@„Z<dA„Z=dB„Z>dC„Z?dD„Z@dE„ZAdF„ZBdG„ZCdH„ZDdI„ZEdJ„ZFe8dK„ZGeHeHdL„ZIeHeHdM„ZJdNefdO„ƒYZKdPeKfdQ„ƒYZLdReLfdS„ƒYZMdTeKfdU„ƒYZNdVeLfdW„ƒYZOdXeKfdY„ƒYZPdZeKfd[„ƒYZQd\eKfd]„ƒYZRd^eKfd_„ƒYZSd`eKfda„ƒYZTdbeKfdc„ƒYZUddeKfde„ƒYZVdfeKfdg„ƒYZWdheKfdi„ƒYZXdjeKfdk„ƒYZYdleKfdm„ƒYZZdneKfdo„ƒYZ[dpeKfdq„ƒYZ\dreKfds„ƒYZ]dteKfdu„ƒYZ^dveKfdw„ƒYZ_dxeKfdy„ƒYZ`dzeKfd{„ƒYZad|eKfd}„ƒYZbd~„ZcdeKfd€„ƒYZddeKfd‚„ƒYZedƒeKfd„„ƒYZfd…„Zgd†eKfd‡„ƒYZhdˆ„Zid‰eKfdŠ„ƒYZjd‹eKfdŒ„ƒYZkdejfdŽ„ƒYZldeKfd„ƒYZmd‘eKfd’„ƒYZnd“eKfd”„ƒYZod•eKfd–„ƒYZpd—eKfd˜„ƒYZqeMƒeOƒeNƒePƒeQƒeRƒeSƒeTƒeUƒeVƒeWƒeXƒeYƒe[ƒeZƒe\ƒe]ƒe^ƒedƒe_ƒe`ƒeaƒebƒeeƒelƒefƒejƒekƒehƒemƒenƒeoƒepƒeqƒf"Zrd™„ZsetesƒƒZuetdš„erDƒƒZvd›„Zwdœ„Zxd„ZyedždŸed ƒƒfZzd¡e{fd¢„ƒYZ|e j}e|ƒd£e~fd¤„ƒYZe j}eƒd¥e€fd¦„ƒYZe j}eƒd§e‚fd¨„ƒYZƒe j}eƒƒd©e„fdª„ƒYZ…e j}e…ƒd«e†fd¬„ƒYZ‡e j}e‡ƒd­eˆfd®„ƒYZ‰e j}e‰ƒd¯eˆfd°„ƒYZŠe j}eŠƒd±eˆfd²„ƒYZ‹e j}e‹ƒd³eˆfd´„ƒYZŒe j}eŒƒdµe{fd¶„ƒYZe j}eƒd·e~fd¸„ƒYZŽe j}eŽƒd¹e‚fdº„ƒYZe j}eƒd»e€fd¼„ƒYZe j}eƒd½e‚fd¾„ƒYZ‘e j}e‘ƒd¿e†fdÀ„ƒYZ’e j}e’ƒdÁe„fd„ƒYZ“e j}e“ƒdÃe fdÄ„ƒYZ”e j}e”ƒdÅe fdÆ„ƒYZ•e j}e•ƒdÇe{fdÈ„ƒYZ–e j}e–ƒdÉe‚fdÊ„ƒYZ—e j}e—ƒdËe†fdÌ„ƒYZ˜e j}e˜ƒdS(Íi(tabsolute_importN(tcontext(tapiterrorstoutput(tCommand(tFlagtBooltInttDecimaltStrtStrEnumtAnytDeprecatedParam(t*(t_tngettext( tvalidate_zonemgrtnormalize_zonemgrtnormalize_zonetvalidate_hostnametvalidate_dns_labeltvalidate_domain_namet"get_dns_forward_zone_update_policyt"get_dns_reverse_zone_update_policytget_reverse_zone_defaulttzone_is_reversetREVERSE_DNS_ZONES(tvalid_iptCheckedIPAddresstis_host_resolvables‡ Domain Name System (DNS) Manage DNS zone and resource records. USING STRUCTURED PER-TYPE OPTIONS There are many structured DNS RR types where DNS data stored in LDAP server is not just a scalar value, for example an IP address or a domain name, but a data structure which may be often complex. A good example is a LOC record [RFC1876] which consists of many mandatory and optional parts (degrees, minutes, seconds of latitude and longitude, altitude or precision). It may be difficult to manipulate such DNS records without making a mistake and entering an invalid value. DNS module provides an abstraction over these raw records and allows to manipulate each RR type with specific options. For each supported RR type, DNS module provides a standard option to manipulate a raw records with format ---rec, e.g. --mx-rec, and special options for every part of the RR structure with format ---, e.g. --mx-preference and --mx-exchanger. When adding a record, either RR specific options or standard option for a raw value can be used, they just should not be combined in one add operation. When modifying an existing entry, new RR specific options can be used to change one part of a DNS record, where the standard option for raw value is used to specify the modified value. The following example demonstrates a modification of MX record preference from 0 to 1 in a record without modifying the exchanger: ipa dnsrecord-mod --mx-rec="0 mx.example.com." --mx-preference=1 EXAMPLES: Add new zone: ipa dnszone-add example.com --name-server=ns \ --admin-email=admin@example.com \ --ip-address=10.0.0.1 Add system permission that can be used for per-zone privilege delegation: ipa dnszone-add-permission example.com Modify the zone to allow dynamic updates for hosts own records in realm EXAMPLE.COM: ipa dnszone-mod example.com --dynamic-update=TRUE This is the equivalent of: ipa dnszone-mod example.com --dynamic-update=TRUE \ --update-policy="grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;" Modify the zone to allow zone transfers for local network only: ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8 Add new reverse zone specified by network IP address: ipa dnszone-add --name-from-ip=80.142.15.0/24 \ --name-server=ns.example.com. Add second nameserver for example.com: ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com Add a mail server for example.com: ipa dnsrecord-add example.com @ --mx-rec="10 mail1" Add another record using MX record specific options: ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2 Add another record using interactive mode (started when dnsrecord-add, dnsrecord-mod, or dnsrecord-del are executed with no options): ipa dnsrecord-add example.com @ Please choose a type of DNS resource record to be added The most common types for this type of zone are: NS, MX, LOC DNS resource record type: MX MX Preference: 30 MX Exchanger: mail3 Record name: example.com MX record: 10 mail1, 20 mail2, 30 mail3 NS record: nameserver.example.com., nameserver2.example.com. Delete previously added nameserver from example.com: ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com. Add LOC record for example.com: ipa dnsrecord-add example.com @ --loc-rec="49 11 42.4 N 16 36 29.6 E 227.64m" Add new A record for www.example.com. Create a reverse record in appropriate reverse zone as well. In this case a PTR record "2" pointing to www.example.com will be created in zone 15.142.80.in-addr.arpa. ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse Add new PTR record for www.example.com ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com. Add new SRV records for LDAP servers. Three quarters of the requests should go to fast.example.com, one quarter to slow.example.com. If neither is available, switch to backup.example.com. ipa dnsrecord-add example.com _ldap._tcp --srv-rec="0 3 389 fast.example.com" ipa dnsrecord-add example.com _ldap._tcp --srv-rec="0 1 389 slow.example.com" ipa dnsrecord-add example.com _ldap._tcp --srv-rec="1 1 389 backup.example.com" The interactive mode can be used for easy modification: ipa dnsrecord-mod example.com _ldap._tcp No option to modify specific record provided. Current DNS record contents: SRV record: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 backup.example.com Modify SRV record '0 3 389 fast.example.com'? Yes/No (default No): Modify SRV record '0 1 389 slow.example.com'? Yes/No (default No): y SRV Priority [0]: (keep the default value) SRV Weight [1]: 2 (modified value) SRV Port [389]: (keep the default value) SRV Target [slow.example.com]: (keep the default value) 1 SRV record skipped. Only one value per DNS record type can be modified at one time. Record name: _ldap._tcp SRV record: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 389 slow.example.com After this modification, three fifths of the requests should go to fast.example.com and two fifths to slow.example.com. An example of the interactive mode for dnsrecord-del command: ipa dnsrecord-del example.com www No option to delete specific record provided. Delete all? Yes/No (default No): (do not delete all records) Current DNS record contents: A record: 1.2.3.4, 11.22.33.44 Delete A record '1.2.3.4'? Yes/No (default No): Delete A record '11.22.33.44'? Yes/No (default No): y Record name: www A record: 1.2.3.4 (A record 11.22.33.44 has been deleted) Show zone example.com: ipa dnszone-show example.com Find zone with "example" in its domain name: ipa dnszone-find example Find records for resources with "www" in their name in zone example.com: ipa dnsrecord-find example.com www Find A records with value 10.10.0.1 in zone example.com ipa dnsrecord-find example.com --a-rec=10.10.0.1 Show records for resource www in zone example.com ipa dnsrecord-show example.com www Delegate zone sub.example to another nameserver: ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5 ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com. If global forwarder is configured, all requests to sub.example.com will be routed through the global forwarder. To change the behavior for example.com zone only and forward the request directly to ns.sub.example.com., global forwarding may be disabled per-zone: ipa dnszone-mod example.com --forward-policy=none Forward all requests for the zone external.com to another nameserver using a "first" policy (it will send the queries to the selected forwarder and if not answered it will use global resolvers): ipa dnszone-add external.com ipa dnszone-mod external.com --forwarder=10.20.0.1 \ --forward-policy=first Delete zone example.com with all resource records: ipa dnszone-del example.com Resolve a host name to see if it exists (will add default IPA domain if one is not included): ipa dns-resolve www.example.com ipa dns-resolve www GLOBAL DNS CONFIGURATION DNS configuration passed to command line install script is stored in a local configuration file on each IPA server where DNS service is configured. These local settings can be overridden with a common configuration stored in LDAP server: Show global DNS configuration: ipa dnsconfig-show Modify global DNS configuration and set a list of global forwarders: ipa dnsconfig-mod --forwarder=10.0.0.1 uAuAAAAuA6uAFSDBuAPLuCERTuCNAMEuDHCIDuDLVuDNAMEuDNSKEYuDSuHIPuIPSECKEYuKEYuKXuLOCuMXuNAPTRuNSuNSECuNSEC3u NSEC3PARAMuPTRuRRSIGuRPuSIGuSPFuSRVuSSHFPuTAuTKEYuTSIGuTXTu@tAtAAAAtPTRtNStMXtLOCs%srecorduINuCSuCHuHScC@s/yt|ƒWntk r*}t|ƒSXdS(N(Rt ValueErrortunicodetNone(tugettexttzonemgrte((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_rname_validatorûs  cC@sttjƒƒS(s1 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. (tintttime(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_create_zone_serials cC@sÆytjt|ƒƒWntjtfk r3nXtt|ƒƒStj|ƒ}|jj j dƒ}|j dkr“dj |d|j dƒS|j dkr¾dj |d|j dƒSdSdS(Nt.iu.iii (tnetaddrt IPAddresststrtAddrFormatErrorR%R&Rt IPNetworktipt reverse_dnstsplittversiontjoint prefixlenR'(tnetstrtnettitems((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_reverse_zone_name scC@sˆy`tjt|ƒdtjƒ}|dk r_|j|kr_tdƒtd|jd|ƒSnWn!tjt fk rƒtdƒSXdS(NtflagssFinvalid IP address version (is %(value)d, must be %(required_value)d)!tvaluetrequired_valuesinvalid IP address format( R0R1R2t INET_PTONR'R8RtdictR3R%(R(tipaddrt ip_versionR5((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_ipaddrs   cC@st||dƒS(Ni(RF(R(RD((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_ip4addr+scC@st||dƒS(Ni(RF(R(RD((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_ip6addr.scC@s>ytj|ƒ}Wn$tjttfk r9tdƒSXdS(Nsinvalid IP network format(R0R4R3R%tUnboundLocalErrorRR'(R(tipnetR<((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_ipnet1s  c C@sÜ|s dS|jdƒ}|dr-tdƒS|jdƒx›|D]“}|dkrYqAn|jdƒru|d }ny"t|d td td tƒ}WqAtjtfk r¼}t |ƒSt k rÓtd ƒSXqAWdS(Nt;iÿÿÿÿs4each ACL element must be terminated with a semicolontanytnonet localhostt localnetst!it parse_netmaskt allow_networktallow_loopbackuinvalid address format(sanysnones localhostRP( R7Rtpopt startswithRtTrueR0R3R%R&RI(R(t bind_acistbind_aciR5R*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_bind_aci8s$        c C@s!|s dS|jdƒ}g}xâ|D]Ú}|s8q&n|dkrW|j|ƒq&nd}|jdƒr|d}d}nygt|d td td tƒ}d |kr¼d |j}nd}|jd|t|ƒ|fƒw&Wq&|j|ƒq&q&Xq&Wdj|ƒ}|d7}|S(NRLRMRNRORPtRQiRRRSRTt/s/%su%s%s%su;(sanysnones localhosts localnets(R7tappendRVRRWR:R2R9(RXt normalizedRYtprefixR5tnetmasktacis((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_normalize_bind_aciQs8          cC@sU|tkrdSyt|dtdtƒWn$tk rP}tdƒt|ƒSXdS(Nt check_fqdntallow_underscoresinvalid domain-name: %s(t_dns_zone_recordRtFalseRWR%RR&R'(R(R@R*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_bind_hostname_validatorss   cC@sN|tkrdSytd„|jdƒƒWntk rI}t|ƒSXdS(NcS@st|dtƒS(NRd(RRW(tlabel((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt…su.(RetmapR7R%R&(R(R@R*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_dns_record_name_validator€s  cC@s |jdƒ\}}}t||ƒ}|dk r7|S|rœy4t|ƒ}|dksd|dkrptƒ‚nWqœtk r˜tdtd|ƒƒSXndS(Nu port iiÿÿs%(port)s is not a valid porttport(t partitionRFR'R,R%RRC(R(t forwardert ip_addresstsepRltip_address_validation((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_bind_forwarderŠs   cC@s/yt|ƒWntk r*}t|ƒSXdS(N(RR%R&(R(R@R*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_domain_name_validatorœscC@s9yt|ƒWn$tk r4}tdƒt|ƒSXdS(Nsinvalid domain-name: %s(RR%RR&R'(R(R@R*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_hostname_validator¢s   cC@s |ddkr|dS|SdS(sMake it fully-qualifiediÿÿÿÿR/N((t domain_name((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_normalize_hostname«scC@stj|ƒ}|jdkr:tjd|d|ƒ}n7|jdkretjd|d|ƒ}n tdƒ‚|ddkS( Nitdnsrecord_findtarecordit aaaarecordsInvalid address familytcounti(R0R1R8RRR%(tzonet str_addresstaddrtresult((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytis_forward_record²s cC@s’tj|ƒ}yh|jdkr>tjd||d|ƒn8|jdkrjtjd||d|ƒn tdƒ‚Wntjk rnXdS(Nit dnsrecord_addRxiRysInvalid address family(R0R1R8RRR%Rt EmptyModlist(R{tnameR|R}((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytadd_forward_record½sc C@sŒtjt|ƒƒ}t|jƒ}|dkrœd}tjdƒd}xæ|D]D}|dd}|j|ƒrQt |ƒt |ƒkrQ|}qQqQWn—|j dkr¼d|d}n |j dkrÜd |d}n|jj d ƒ} d j | |ƒ}ytjd |ƒWnt jk r2d}nXt |ƒdkrmt jd tdƒtd|ƒƒ‚n|t |ƒ d } || fS(Nut dnszone_findR~tidnsnameiiiii R/u.t dnszone_showtreasons2DNS reverse zone for IP address %(addr)s not foundR}i(R0R1R2R&R6R'RRtendswithtlenR8R7R9RtNotFoundRRC( RDR:R5trevdnstrevzoneR~R{tzonenametposR=trevname((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_reverse_zoneÉs0  '  c C@sØytjd|ƒdWn9tjk rTtjdtdƒtd|ƒƒ‚nXt|ttfƒsv|g}nx[|D]S}yt |dt ƒ}Wn1t k rÌ}tj d|dt |ƒƒ‚nX|rt|t |ƒƒrtjd td ƒtd t|ƒd |ƒƒ‚qn|r}y‘d} |jsC|j} nt|| ƒ\} } tjd | d| ƒ} | ddkrµtjd tdƒtd t|ƒd| ƒƒ‚nWqÐtjk rÌqÐXq}q}WdS(NR†R~R‡sDNS zone %(zone)s not foundR{t match_localR‚terrortmessageu;IP address %(ip)s is already assigned in domain %(domain)s.R5tdomainRwR…RziuMReverse record for IP address %(ip)s already exists in reverse zone %(zone)s.(RRRRŠRRCt isinstancettupletlistRRft ExceptiontValidationErrorR&RtDuplicateEntryR2R't defaultnetR:R( t option_namethostR”t ip_addressest check_forwardt check_reverseRoR5R*R:RŒRtreverse((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytadd_records_for_host_validationës<    "  %    &c C@sçt|ttfƒs!|g}nx¿|D]·}t|dtƒ}|r_t||t|ƒƒn|r(y`d}|jsƒ|j }nt ||ƒ\}} i|d|d6} t j d|| | Wqßt jk rÛqßXq(q(WdS(NR‘R/t ptrrecordR€(R•R–R—RRfRƒR&R'R›R:RRRRR( RR”Ržt add_forwardt add_reverseRoR5R:RŒRtaddkw((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytadd_records_for_hosts     t DNSRecordcB@sMeZdZdZeZedƒZdZ edƒZ edƒZ edƒZ dZ dZdZdZejdeefd eeffZdZdZdd „Zd „Zd „Zed „Zd„Zdd„Zd„Zd„Zd„Zd„Zd„Z d„Z!d„Z"dd„Z#dd„Z$e%d„Z&d„Z'd„Z(RS(s %s records%s %ssRaw %s recordss %s Records(see RFC %s for details)s %s_part_%ss %s_extra_%ss%s_%st validatednst normalizednscO@s|jtkr:tdt|jƒdjtƒfƒ‚n|sVd|jjƒ}n|jdd|jjƒƒ|jd|j|jƒ|jd|j|jƒ|jd|j |jƒt |d <|j sád |d [s(t_validate_partsR9(RºR¾RÃ((RÃRºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_part_values_to_stringYs c@sét‡fd†ˆjDƒƒ}t‡fd†|Dƒƒ}td„|DƒƒrUdS|råx‡t|ƒD]v\}}|dkrhˆj|jrhˆjˆjjƒˆj|j f}t j dˆj dt dƒ|ƒ‚qhqhWn|S(Nc3@s.|]$}ˆjˆjjƒ|jfVqdS(N(tpart_name_formatR°R²R‚(RÁtpart(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys _sc3@s|]}ˆj|ƒVqdS(N(tget(RÁt part_name(R¼(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ascs@s|]}|dkVqdS(N(R'(RÁtval((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys csR‚R’s%'%s' is a required part of DNS record( R–R½tallt enumerateR'trequiredtcli_name_formatR°R²R‚RtConversionErrorR(RºR¼t raise_on_nonet part_namestvalstval_idRÊR«((R¼Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_parts_from_kw^s&cC@sCt|ƒt|jƒkr?tjd|jdtdƒƒ‚ndS(NR‚R’sInvalid number of parts!(R‰R½RR™R‚R(RºR½((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÄoscC@s>t|ttfƒr%|j||ƒStt|ƒj||ƒS(N(R•R–R—RÅR¸R¨RÀ(RºR@RÃ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÀtsc@swˆjrat|ttfƒr=t‡fd†|Dƒƒ}qa|dk raˆj|ƒf}qanttˆƒj|ƒS(Nc3@s*|] }|dk rˆj|ƒVqdS(N(R't_normalize_parts(RÁRÂ(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys }s( RªR•R–R—R'RÕR¸R¨t normalize(RºR@((Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÖys  cC@s×|jdkr|Sy¬|j|ƒ}|s/|Sgt|jƒD]5\}}||dk rn|j||ƒnd^q?}gt|jƒD]\}}|j||ƒ^qŠ}|j|ƒ}Wntk rÒnX|S(sO Normalize a DNS record value using normalizers for its parts. N(R½R'R¿RÌRÀRÖR˜(RºR@R¾tpart_idRÇtconverted_valuest new_values((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÕ…sH2 c C@sF|js dS|dkrdS|dkr-dS|jsG|dƒ|jS|jdkrZdS|j|ƒ}|só|jség|jD]}|jjƒ^q‚}|j r½d|j |j }nd}|dƒt ddj |ƒd|ƒS|jSnxLt |jƒD];\}}|j||ƒ}|j|ƒ}|j|ƒqWdS(Ns;DNS RR type "%s" is not supported by bind-dyndb-ldap plugint R[s1format must be specified as "%(format)s" %(rfcs)stformattrfcs(R©R'R·R°R½R¿tformat_error_msgR‚tuppertrfct see_rfc_msgRCR9RÌRÖtconverttvalidate( RºRR@R¾RÇRÑRàR×RÊ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_rule_validatednsžs4      %   cC@sÓ|j|jjƒ|jf}|j|jjƒ|jf}|j|jt|jƒf}|j|j}t |j ƒddg}|j sŸ|j dƒn|j |d|d|dtd|d|d |jƒS( sñ All parts of DNSRecord need to be processed and modified before they can be added to global DNS API. For example a prefix need to be added before part name so that the name is unique in the global namespace. tdnsrecord_parttvirtual_attributetdnsrecord_optionalR«RhRÍR­R?thint(RÆR°R²R‚RÎtpart_label_formatR&RhR¶R—R?RÍR]t clone_renameRf(RºRÇR‚R«RhR­R?((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_convert_dnsrecord_partÅs  cC@sº|j|jjƒ|jf}|j|jjƒ|jf}|j|jt|jƒf}|j|j}t |j ƒddg}|j |d|d|dt d|d|d|jƒS( s• Parameters for special per-type behavior need to be processed in the same way as record parts in _convert_dnsrecord_part(). tdnsrecord_extraRåR«RhRÍR­R?Rç( textra_name_formatR°R²R‚RÎRèR&RhR¶R—R?RéRf(RºtextraR‚R«RhR­R?((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_convert_dnsrecord_extraÜs c@s3ˆjdkrtƒSt‡fd†ˆjDƒƒS(Nc3@s|]}ˆj|ƒVqdS(N(Rê(RÁRÇ(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ós(R½R'R–(Rº((Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt get_partsïsc@s3ˆjdkrtƒSt‡fd†ˆjDƒƒS(Nc3@s|]}ˆj|ƒVqdS(N(Rî(RÁRí(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ùs(RíR'R–(Rº((Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt get_extraõscC@sk|j|jjƒ|jf}|j|jt|jƒf}|j }|j|d|d|ƒ||eZdZdZedededƒdedƒƒfZRS(tCNAMEi R#RhR$R¬s.A hostname which this alias hostname points to(R R R°RßR RgRR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR.©s  t DHCIDRecordcB@seZdZdZeZRS(tDHCIDi](R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR0´st DLVRecordcB@seZdZdZeZRS(tDLViO(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR2¹st DNAMERecordcB@s2eZdZdZedededƒƒfZRS(tDNAMEip ttargetRhtTarget(R R R°RßR RgRR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR4¾s t DNSKEYRecordcB@seZdZdZeZRS(tDNSKEYiÂ(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR8ÈstDSRecordc B@s’eZdZdZeddedƒddddƒed ded ƒdddd ƒed ded ƒdddd ƒeddedƒƒfZRS(tDSiÂR*RhsKey TagR!iR"iÿÿR+R,iÿt digest_types Digest TypetdigesttDigest(R R R°RßRRR R½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR:Ís        t HIPRecordcB@seZdZdZeZRS(tHIPiU(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR?åst KEYRecordc B@s’eZdZdZeddedƒddddƒed ded ƒdddd ƒed ded ƒdddd ƒeddedƒƒfZRS(tKEYiç R?RhtFlagsR!iR"iÿÿtprotocoltProtocoliÿR+R,t public_keys Public Key(R R R°RßRRR R½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRAês        tIPSECKEYRecordcB@seZdZdZeZRS(tIPSECKEYi¹(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRGstKXRecordc B@skeZdZdZeddedƒdedƒddd d ƒed eded ƒded ƒƒfZRS(tKXi¶t preferenceRht PreferenceR¬sCPreference given to this exchanger. Lower values are more preferredR!iR"iÿÿt exchangert Exchangers(A host willing to act as a key exchanger( R R R°RßRRR RgR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRIs    t LOCRecordcB@sÜeZdZdZeddedƒddddƒed ded ƒdddd ƒed ded ƒddddddƒeddedƒdd1ƒeddedƒddddƒeddedƒdddd ƒeddedƒddddddƒeddedƒdd2ƒed"ded#ƒdd$dd%dd&ƒed'ded(ƒdddd)dd&ƒed*ded+ƒdddd)dd&ƒed,ded-ƒdddd)dd&ƒf Zed.ƒZ d/„Z d0„Z RS(3R$iTtlat_degRhsDegrees LatitudeR!iR"iZslat_min?sMinutes Latitudei;slat_sec?sSeconds Latitudes0.0s59.999t precisionitlat_dirsDirection LatitudeR¾uNuStlon_degsDegrees Longitudei´slon_min?sMinutes Longitudeslon_sec?sSeconds Longitudetlon_dirsDirection LongitudeuEuWtaltitudetAltitudes -100000.00s 42849672.95issize?tSizes 90000000.00s h_precision?sHorizontal Precisions v_precision?sVertical Precisionsformat must be specified as "d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]] {"E"|"W"} alt["m"] [siz["m"] [hp["m"] [vp["m"]]]]" where: d1: [0 .. 90] (degrees latitude) d2: [0 .. 180] (degrees longitude) m1, m2: [0 .. 59] (minutes latitude/longitude) s1, s2: [0 .. 59.999] (seconds latitude/longitude) alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters) siz, hp, vp: [0 .. 90000000.00] (size/precision in meters) See RFC 1876 for detailscC@sHtjdƒ}|j|ƒ}|dkr.dStd„|jƒDƒƒS(Ns.(?P\d{1,2}\s+)(?P\d{1,2}\s+)?(?P\d{1,2}\.?\d{1,3}?\s+)?(?P[N|S])\s+(?P\d{1,3}\s+)(?P\d{1,2}\s+)?(?P\d{1,2}\.?\d{1,3}?\s+)?(?P[W|E])\s+(?P-?\d{1,8}\.?\d{1,2}?)m?\s*(?P\d{1,8}\.?\d{1,2}?)?m?\s*(?P\d{1,8}\.?\d{1,2}?)?m?\s*(?P\d{1,8}\.?\d{1,2}?)?m?\s*$cs@s-|]#}|dk r!|jƒn|VqdS(N(R'tstrip(RÁtx((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys xs(tretcompiletmatchR'R–tgroups(RºR@tregextm((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¿is   c @s?tt|ƒjˆƒtd„t|jƒDƒƒ‰ddddf}xñ|D]é}|d }ˆˆ|dk rN|d }t‡‡fd †|Dƒƒr7|j|j j ƒ|d f}g|d D]"}|j|j j ƒ|f^qÆ}t d ƒtd dj |ƒd|ƒ} t jd|jd| ƒ‚q7qNqNWdS(Ncs@s$|]\}}|j|fVqdS(N(R‚(RÁR×RÇ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ~stlat_sectlat_mintlon_sectlon_mint h_precisiontsizet v_precisioniic3@s#|]}ˆˆ|dkVqdS(N(R'(RÁRÇ(t part_name_mapR½(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ‹ss7'%(required)s' must not be empty when '%(name)s' is setRÍs, R‚R’(R`Ra(RbRc(Rdssize(RfRdssize(R¸RORÄRCRÌR½R'RMRÎR°R²RR9RR™R‚( RºR½t requirementstreqt target_parttrequired_partsttarget_cli_nameRÇtrequired_cli_namesR’((RgR½s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÄzs&      0  (uNuS(uEuW( R R R°RßRRR R R½RÝR¿RÄ(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyROst                           tMXRecordc B@skeZdZdZeddedƒdedƒddd d ƒed eded ƒded ƒƒfZRS(R#i RKRhRLR¬sCPreference given to this exchanger. Lower values are more preferredR!iR"iÿÿRMRNs)A host willing to act as a mail exchanger( R R R°RßRRR RgR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRn”s    tNSRecordcB@s2eZdZdZedededƒƒfZRS(R"i R#RhR$(R R R°RßR RgRR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRo¥s t NSECRecordc B@s{eZdZdZedƒZd eZede dedƒƒe ddedƒd ed e ƒfZ d „Z d „ZRS(tNSECiÂsYformat must be specified as "NEXT TYPE1 [TYPE2 [TYPE3 [...]]]" (see RFC 4034 for details)uSOAtnextRhsNext Domain Namestypes+sType MapR¾R®cC@s:|jƒ}t|ƒdkr"dS|dt|dƒfS(Niii(R7R‰R'R–(RºR@R¾((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¿Ãs c@srˆj|ƒ|dg}|d}t|ttfƒsE|g}n|j|ƒdj‡‡fd†|DƒƒS(Niiu c3@s0|]&}|dk rtjˆ|ˆƒVqdS(N(R'R RÀ(RÁRÂ(RÃRº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys Òs(RÄR•R—R–textendR9(RºR¾RÃt values_flatttypes((RÃRºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÅËs     (uSOA(R R R°RßRRÝR±t_allowed_typesR RgR RWR½R¿RÅ(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRp°s       t NSEC3RecordcB@seZdZdZeZRS(tNSEC3i#(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRwÕstNSEC3PARAMRecordcB@seZdZdZeZRS(t NSEC3PARAMi#(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRyÚscC@sOd}|jddƒjddƒ}x$|D]}||kr+tdƒSq+WdS(NuSAUPt"R[s's*flags must be one of "S", "A", "U", or "P"(treplaceR(R(R?t allowed_flagstflag((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_validate_naptr_flagsßs   t NAPTRRecordc B@s¼eZdZdZeddedƒddddƒed ded ƒddddƒed eded ƒd d„ƒeddedƒƒeddedƒƒeddedƒƒfZRS(tNAPTRic torderRhtOrderR!iR"iÿÿRKRLR?RCt normalizercC@s |jƒS(N(RÞ(RY((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRiùstservicetServicetregexpsRegular Expressiont replacementt Replacement( R R R°RßRRR RR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR€çs(           t PTRRecordc B@sDeZdZdZededededƒdedƒƒfZRS(R!i R#R„RhR$R¬s*The hostname this reverse record points to( R R R°RßR RtRvRR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRŠs tRPRecordcB@seZdZdZeZRS(tRPiŸ(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR‹scC@s|dkrdSt||ƒS(Nu.(Rg(R(R@((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_srv_target_validators t SRVRecordc B@s¡eZdZdZeddedƒddddƒed ded ƒddddƒed ded ƒddddƒed ededƒdedƒƒfZRS(tSRViÞ tpriorityRhtPriorityR!iR"iÿÿtweighttWeightRltPortR6R7R¬sbThe domain name of the target host or '.' if the service is decidedly not available at this domain( R R R°RßRRR RR½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRŽs$       cC@s9d}ytj||ƒWntk r4tdƒSXdS(Ns %Y%m%d%H%M%Ss6the value does not follow "YYYYMMDDHHMMSS" time format(R-tstrptimeR%R(R(R@t time_format((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_sig_time_validator7s  t SIGRecordcB@s?eZdZdZedggeD]Zedkr"e^q"ƒZedde dƒdeƒe dde d ƒd d d d ƒe dde dƒd d d d ƒe dde dƒd d ƒe de de dƒƒe de de dƒƒe dde dƒd d d dƒe dde dƒƒe dde dƒƒf Z RS(tSIGiç uSOAuSIGt type_coveredRhs Type CoveredR¾R+R,R!iR"iÿtlabelstLabelst original_ttls Original TTLtsignature_expirationsSignature Expirationtsignature_inceptionsSignature InceptionR*sKey Tagiÿÿt signers_names Signer's Namet signaturet Signature(R R R°RßR–R±RYRvR RRR R—R½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR˜?s>2               t SPFRecordcB@seZdZdZeZRS(tSPFi8(R R R°RßRfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR£lst RRSIGRecordcB@seZdZdZRS(tRRSIGiÂ(R R R°Rß(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¥qst SSHFPRecordc B@sqeZdZdZeddedƒddddƒed ded ƒddddƒed ded ƒƒfZRS( tSSHFPiŸR+RhR,R!iR"iÿtfp_typesFingerprint Typet fingerprintt Fingerprint(R R R°RßRRR R½(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR§us     tTARecordcB@seZdZeZRS(tTA(R R R°RfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¬ˆst TKEYRecordcB@seZdZeZRS(tTKEY(R R R°RfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR®Œst TSIGRecordcB@seZdZeZRS(tTSIG(R R R°RfR·(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR°st TXTRecordcB@s8eZdZdZeddedƒƒfZd„ZRS(tTXTi RRhs Text DatacC@s|fS(N((RºR@((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¿s(R R R°RßR RR½R¿(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR²”s  c c@sÔxtddtdƒddddgƒtddtd ƒddddgƒtd dtd ƒddddgƒfD] }|VqsWxKtD]C}|Vx|jƒD] }|Vq¡Wx|jƒD] }|Vq½Wq‰WdS( Ns dnsrecords?RhtRecordsR?t no_createt no_searchRsdnstype?s Record typesdnsdata?s Record data(R RR t _dns_recordsRïRð(topttoptionRÇRí((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt__dns_record_options_iterÆs          cc@s!|]}|jr|jVqdS(N(R·R°(RÁR((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ÞscC@s°|tkrt|ƒ}nB|jdƒs]tjj|ƒ}ttjj|d|ƒƒ}nytjd|ƒSWn7t j k r«t j dt dƒi|d6ƒ‚nXdS(NR/torigint dns_resolveR‡sANameserver '%(host)s' does not have a corresponding A/AAAA recordR( ReRRˆtdnsR‚t from_textR&RRRRŠR(R{R‚((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytcheck_ns_rec_resolvableás ! cC@sEy)|jttjjtjjƒgƒWntjk r@tSXt S(N( t get_entryRÿRtenvt container_dnstbasednRRŠRfRW(R((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytdns_container_existsïs )cC@s3t|ƒrttjj|ƒSttjjƒSdS(N(RRRRÁtrealmR(R{((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytdefault_zone_update_policyös t managedbyRhsManagedby permissiontdnszonecB@sÈeZdZejjZedƒZedƒZ dddgZ dgZ ddd d d d d ddddddg e Z edƒZedƒZededddedƒdedƒdd„dd„d eƒed!eded"ƒded#ƒd$d|ƒed dd&ded'ƒded(ƒdd)„ƒed edd*ded+ƒded+ƒdd,„deƒed dd-ded.ƒded/ƒd0d1d2d3ded4eƒed dd5ded6ƒded7ƒd0d8d2d9d:d;d4eƒed dd<ded=ƒded>ƒd0d8d2d9d:d?d4eƒeddd@dedAƒdedBƒd:dCd0d8d2d9d4eƒedddDdedEƒdedFƒd:d;d0d8d2d9d4eƒedGddHdedIƒdedJƒd0d8d2d9ƒedKddLdedMƒdedNƒdOeƒedPddQdedRƒdedRƒddS„d4eƒedTddUdedVƒdedWƒd$dXdYgdZeƒed[dd\ded]ƒded^ƒdZed:ed4eƒed_ededd`dedaƒdedbƒd:dcd4eƒeddededdededfƒdedgƒd:dhd4eƒedieddjdedkƒdedlƒdmeƒednddodedpƒdedqƒdOd}ƒeduddvdedwƒdedxƒƒfZdy„Z dz„Z!d{„Z"RS(~s3 DNS Zone, container for resource records. sDNS zones DNS zonesttopt idnsrecordtidnszonet ipadnszoneR…tidnszoneactivet idnssoamnamet idnssoarnamet idnssoaserialtidnssoarefresht idnssoaretryt idnssoaexpiretidnssoaminimumtidnsallowquerytidnsallowtransfertidnsforwarderstidnsforwardpolicys DNS ZonessDNS ZoneR«R‚Rhs Zone nameR¬sZone name (FQDN)t default_fromcC@s t|ƒS(N(R>(t name_from_ip((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRisR„cC@s |jƒS(N(R²(R@((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRist primary_keys name_from_ip?sReverse zone IP networks+IP network to create reverse zone name fromR?Råt name_serversAuthoritative nameservers$Authoritative nameserver domain namecC@s |jƒS(N(R²(R@((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRi'st admin_emailsAdministrator e-mail addresscC@sd|S(Ns hostmaster.%s((R…((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRi.stserials SOA serialsSOA record serial numberR!iR"lÿÿtautofilltrefreshs SOA refreshsSOA record refresh timeiiÿÿÿRõitretrys SOA retrysSOA record retry timei„texpires SOA expiresSOA record expire timeiutminimums SOA minimums,How long should negative responses be cachedsdnsttl?tttlsSOA time to livesSOA record time to lives dnsclass?tclasss SOA classsSOA record classR¾sidnsupdatepolicy?t update_policysBIND update policycC@s t|ƒS(N(RÆ(R…((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRiossidnszoneactive?t zone_actives Active zonesIs zone active?RµRt attributesidnsallowdynupdate?tdynamic_updatesDynamic updatesAllow dynamic updates.sidnsallowquery?t allow_querys Allow querysWSemicolon separated list of IP addresses or networks which are allowed to issue queriesuany;sidnsallowtransfer?tallow_transfersAllow transfers[Semicolon separated list of IP addresses or networks which are allowed to transfer the zoneunone;sidnsforwarders*RnsZone forwarderssuPer-zone forwarders. A custom port can be specified for each forwarder using a standard format "IP_ADDRESS port PORT"R®sidnsforwardpolicy?tforward_policysForward policys©Per-zone conditional forwarding policy. Set to "none" to disable forwarding to global forwarder for this zone. In that case, conditional zone forwarders are disregarded.uonlyufirstunonesidnsallowsyncptr?tallow_sync_ptrsAllow PTR syncsPAllow synchronization of forward (A, AAAA) and reverse (PTR) records in the zonecO@sÔ|d}tt|ƒj||}y|jj|dgƒWnŽtjk rÏ|jdƒrn|d }n |d}tt|ƒj||}y"|jj|dgƒ\}}WqÐtjk rËqÐXnX|S(NiÿÿÿÿR[u.(R¸RÈtget_dntbackendRÀRRŠRˆ(RºRRR{Rttest_dnR((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRîªs   "cC@sd|S(NuManage DNS zone %s((RºR{((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytpermission_name½scC@sÏ|tkr|S|jdƒr,|d }n|jdƒrH|d }n|jdƒ}|jdƒ}t|ƒ}xCtt|ƒt|ƒƒD]&\}}||krªdS|jƒqŽW|sÂtSdj|ƒS(s  Get name of a record that is to be added to a new zone. I.e. when we want to add record "ipa.lab.example.com" in a zone "example.com", this function should return "ipa.lab". Returns None when record cannot be added to a zone u.iÿÿÿÿN( ReRˆR7R—tziptreversedR'RUR9(RºR{R#thostname_partst zone_partstdns_namet host_partt zone_part((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_name_in_zoneÀs"     (svirtual_attribute(uonlyufirstunone(#R R t__doc__RRÁRÂt container_dnRt object_nametobject_name_pluralt object_classtpossible_objectclassest_record_attributestdefault_attributesRhtlabel_singularR RsRWRKR+RRR.R t_record_classesRRfRZRbRrt takes_paramsRîRñRù(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÈs                                                                     t dnszone_addc B@sŽeZedƒZejeZejeddedƒdedƒƒe de dedƒdedƒƒfZd „Z d „Z d „Z RS( s!Create new DNS zone (SOA record).tforceRhtForceR¬s=Force DNS zone creation even if nameserver is not resolvable.s ip_address?s=Add forward record for nameserver located in the created zonesNameserver IP addresscC@sš|jddƒrdSt|dƒ}|d}|jdƒ }|jj||ƒ}t|ƒ r–|sn|r–|jjj t dƒƒ}||dR$R<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR?Ìs   tdnszone_add_permissioncB@s2eZedƒZejZedƒZd„ZRS(s0Add a permission for per-zone access delegation.s#Added system permission "%(value)s"c O@s|jj}|jj||Ž}y|j|dgƒ\}}Wn$tjk rf|jj|ŒnX|jj|dƒ}tj d|ddƒd}i} |j dƒ} | rÛ| j dƒt t | ƒƒ| dR$R<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR@às   tdnszone_remove_permissioncB@s2eZedƒZejZedƒZd„ZRS(s3Remove a permission for per-zone access delegation.s%Removed system permission "%(value)s"cO@s¶|jj}|jj||Ž}y|j|idd6ƒWn7tjk rb|jj|Œntjk runX|jj |dƒ}t j d|dt ƒt dt d|ƒS(NRÇiÿÿÿÿR!RR~R@(RRïRîR;R'RRŠRDRRñRRRWRC(RºRRRRRñ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR< s ( R R RRúRR=R>R$R<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRJs   t dnsrecordc B@sœeZdZdZejjZedƒZ edƒZ ddgZ dge Z eZedƒZedƒZeded d d ed ƒd ed ƒdeƒedd dd edƒd edƒƒedd dd edƒd edƒdeƒfeZedd edƒd edƒƒZd„Zd„Zd„Zd„Zd„Zd„Z d „Z!e"d!„Z#d"„Z$d#„Z%d$„Z&e"d%„Z'd&„Z(RS('s DNS record. RÈsDNS resource recordsDNS resource recordsRÉRÊR…sDNS Resource RecordssDNS Resource RecordR«R‚Rhs Record nameR¬RÛsdnsttl?Räs Time to lives dnsclass?RåtClasss DNS classR¾t structuredt Structureds=Parse all raw DNS records and return them in a structured waycO@slt|tƒst‚|jdƒ}|jdtƒsB|dkrFdSx|D]}t|d|ƒqMWdS(NRRi(R•RÿRRÈRfR'R¿(RºRRRRRt nsrecordsR((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_nsrecord_pre_callbackJs  c O@sut|tƒst‚|jdƒ}|dkr4dS|d}|j|ŒrVd}n |d}d} xBtD]:} |j| ƒrm|j| dƒ}| } t| } qmqmW| sëdj tƒ} t j ddd t t d ƒ| ƒƒ‚n|rt|jd ƒƒnd} | t|jd ƒƒ}|| krqt j ddd t t d ƒtd| d | d|ƒƒƒ‚ndS(NR£iþÿÿÿuiÿÿÿÿiR[s, R‚R’saReverse zone for PTR record should be a sub-zone of one the following fully qualified domains: %sR/s\Reverse zone %(name)s requires exactly %(count)d IP address components, %(user_count)d givenRzt user_count(R•RÿRRÈR'tis_pkey_zone_recordRRˆR|R9RR™R&RR‰R7RC(RºRRRRRt ptrrecordsR{R}tzone_lent valid_zonet zone_namet allowed_zonestaddr_lentip_addr_comp_count((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt_ptrrecord_pre_callbackRs0     !  cO@stt|tƒst‚|jjj}xI|jƒD];}t|d|dƒ}|r1||||||Žq1q1WdS(Ns_%s_pre_callback( R•RÿRRR RRRR'(RºRRRRRtrtypetrtype_cb((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytrun_precallback_validatorsos cG@s8|d}|ttƒks0|d|dkr4tStS(Niÿÿÿÿs%s.iþÿÿÿ(R2ReRWRf(RºRR…((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRRxs &cO@sÉ|j|Œr°|jj|jj|d |Ž}|jjj}y|j|gƒ\}}Wn/tj k rŽ|jjdj |dƒnX|jj|jj|d |ŽSt t |ƒj||ŽS(NiÿÿÿÿRÈiþÿÿÿ( RRRtObjectt parent_objectRîR RRÀRRŠRDR¸RK(RºRRRRRFR{((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRî~s#!cC@s9y|tdƒ jƒ}Wntk r4|}nX|S(NR(R‰RÞt IndexError(Rºtattrtcliname((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt attr_to_cliŠs   c C@sÞ|jjj}td d d |jjjƒ}d}g}y‰|jd|d|ƒd}xf|D]^}|d}t|tƒs„t‚y|d d}|j |ƒWq_t t fk r¼q_Xq_WWnt j k rÙgSX|S( Ntcntmasterstipatetcs((&(objectClass=ipaConfigObject)(cn=DNS))R2R3ii(scnsmasters(scnsipa(scnsetc(RR RRÿRÁRÃt find_entriesR•RR]R`tKeyErrorRRŠ( RºRR3t ldap_filtert dns_masterstentriestentryt master_dntmaster((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_dns_masters‘s"   c@s–t‡fd†dDƒƒr dSt}xQˆjƒD]C}||jkr3|j|j r3ˆ|si|rvt}Pqvq3q3W|s’tj|ƒ‚ndS(Nc3@s|]}|ˆkVqdS(N((RÁtk(R(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ¨sRtaddattrRtrename(ssetattrsaddattrsdelattrsrename(RMRfRR'RÛRWRt OptionError(RºRt no_option_msgtallow_empty_attrst has_optionsRa((Rs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pythas_cli_options§s  c@s t‡fd†|jƒDƒƒS(Nc3@sA|]7\}}|ˆjkrˆj|j r||fVqdS(N(R'RÛ(RÁRaRÊ(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ¶s (RCt iteritems(RºR((Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_record_entry_attrsµsc K@s5|jdtƒr1x|jƒD] }|jƒ}y|j|}Wntk rXqnXt|tƒsnqn|jƒ}x¦||D]š}it |j ƒd6|d6}|j |ƒ}|dkrÉq…nx:t |ƒD],\} } | dk rÖ| ||| jßsRäRë(sdnsrecord_partsdnsrecord_extraN(R'RMR'RçRitAttributeError(RºRÉtrrparam((R|s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytget_rrparam_from_partÕs  cc@s…g}xx|D]p}|j|ƒ}|dkr4q n|rVd|j|jkrVq n|j|kr |j|jƒ|Vq q WdS(s¯ Iterates through all DNSRecord instances that has at least one of its parts or extra options in given dictionary. It returns the DNSRecord instance only for the first occurence of part/extra option. :param kw Dictionary with DNS record parts or extra options :param skip_extra Skip DNS record extra options, yield only DNS records with a real record part RëN(RƒR'R'R?R‚R](RºR¼t skip_extrat processedR¸R‚((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytiterate_rrparams_by_partsës   c @s¼i}|dk rDt‡fd†|jƒDƒƒ}|j|ƒnt‡fd†|jƒDƒƒ}|j|ƒy|d}Wntk r”n€X|dk rt|ƒdkrÔtjdddtdƒƒ‚nt d„|jƒDƒƒrtjdddtd ƒƒ‚qny|d }Wntk r5nƒX|dk r¸t|ƒdkrutjdd dtd ƒƒ‚n|j d ƒr¸|dt kr¸tjdd dtd ƒƒ‚q¸ndS(Nc3@sF|]<\}}|ˆjkrtˆj|tƒr||fVqdS(N(R'R•R¨(RÁtkeyR@(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys  s c3@sF|]<\}}|ˆjkrtˆj|tƒr||fVqdS(N(R'R•R¨(RÁR‡R@(Rº(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys s t cnamerecordiR‚R’sConly one CNAME record is allowed per name (RFC 2136, section 1.1.5)cs@s-|]#\}}|dk o$|dkVqdS(RˆN(R'(RÁtrrattrtrrvalue((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys  ssVCNAME record is not allowed to coexist with any other record (RFC 1034, section 3.6.2)t dnamerecordsAonly one DNAME record is allowed per name (RFC 6672, section 2.4)RszDNAME record is not allowed to coexist with an NS record except when located in a zone root record (RFC 6672, section 2.3)( R'RCRyRHRiR‰RR™RRMRÈRe( RºRt old_entryRtrrattrst old_rrattrst new_rrattrstcnamestdnames((Rºs0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytcheck_record_type_collisions s: ""      ()R R RúR_RRÁRÂRûRRüRýRþRRRWtrdn_is_primary_keyRhRR RkRR Rt_dns_record_optionsRRtstructured_flagRPRZR]RRRîRcRpRfRxRzR€RƒR†R’(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRK!sT                            R€c B@s‡eZedƒZdZejeddedƒdddgded ƒƒej fZd „Z d „Z d „Z d „Z d„ZRS(sAdd new DNS resource record.skNo options to add a specific record provided. Command help may be consulted for all supported record types.RRhRR?R¯t no_outputR¬s;force NS record creation even if its hostname is not in DNScO@s/|jj||jƒtt|ƒj||ŽS(N(RRxRuR¸R€R*(RºRR((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR*D sc C@syy|jj||jƒi}xE|jj|dtƒD]+}|j||dtƒ}|j|ƒq8W|j|ƒdSWntj k rnX|dt kr²dj t ƒ}n1t |dƒrÔdj tƒ}ndj tƒ}|jjjtdƒƒ|jjjtdƒ|ƒt}xÕ|sö|jjjtdƒƒ}|dkrSdSyQd |jƒ}|j|} t| tƒsŽtƒ‚n| js£tƒ‚nWnFttfk rìdj tƒ} |jjjtd ƒ| ƒq"nXt}q"W| j|ƒ}|j|ƒdS( NR„RýR…u, tdnszoneidnsnameu7Please choose a type of DNS resource record to be addedu4The most common types for this type of zone are: %s uDNS resource record types%srecordu3Invalid or unsupported type. Allowed values are: %s(RRxRuR†RWRþRfRHRRtReR9t_zone_top_record_typesRt_rev_top_record_typest_top_record_typesR R t print_plainRR R'R²R'R•R¨R%R·Rit_dns_supported_record_typesRû( RºR¼tnew_kwR‚Rút common_typestokR°R‚R|t all_types((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRH sL        c O@sft|tƒst‚g}g}xY|D]Q} y|j| } Wntk rUq(nX|jj| ƒ} | dkrzq(nd| jkr7| j |kržq(n| j |krót j d| j pÅ| j dt dƒtd| j pæ| j ƒƒ‚n| j|ƒ} | j| ƒg} | || j <|j| j ƒq(nd| jkr(t| tƒrf||  rfq(n|j| j ƒq(q(W|jj||||Žx^|jƒD]P}y|j|} Wntk rÐq£nXt| tƒsæq£n|j|ƒq£Wtt|ƒƒ}xR|D]J}y|j|} Wntk r=qnX| j||||||ŽqWttd|ƒy|j|tƒ\}}Wnt jk r¦d}n¦Xx¢|jƒD]”}|tkrÌq´n||dkrég||Raw value of a DNS record was already set by "%(name)s" optionRëtdnsrecord_precallback_attrs(!R•RÿRR'RiRRƒR'R?R‚RR™R«RRCRÔRÀR]RR]RR¨R—RERRRRÀRRŠR–RÈR’(RºRRRRRRtprecallback_attrstprocessed_attrsR¹R|R‚R½R~RaRFRŒRÒ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR sv    "        *c O@sq|jdkrgt|tjƒrg|jj}|d}|jj|dƒ} |j|| |dSn|‚dS(Nt add_entryii(t func_nameR•RRšRRïRzR;( RºRRRt call_funct call_argst call_kwargsRRR((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt exc_callback× s  cO@sšt|tƒst‚x@ttdgƒD],}|j|}|j|||||Žq(W|jj|Œrƒt g||jj j 3 s("R•RÿRRÈRRRRR™RR†RWRÔRfR'R‚RR–R—R‰R]RÀRRŠRDR'R&RhR#tremoveR¿RÌRÀRER’(RºRRRRRRt updated_attrsR|R½t old_valueRFRŒRat old_dnsvaluet new_partst attr_nametmodified_partst new_dnsvalue((R«s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR sN!     %c O@sðtt|ƒj||Ž}|jj|Œsì|jdƒ}|dk r\|d |f}n|jj||Ž}|jj}|j |t ƒ\}}t } x(|j ƒD]} || r¨t } Pq¨q¨W| rì|jjjd|d|ŒSn|S(NRsiÿÿÿÿR8(R¸RªR<RRRRÈR'RîRïRÀRRWRRftmethodstdelentry( RºRRR~RsRRRFRŒtdel_allRa((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR<< s     cO@sWt|tƒst‚|jj|Œr@tg||jjjqn;ˆjdkrSqn&tˆtƒryˆjddƒVqnˆVqWdS(Nc3@s|]}|ˆjkVqdS(N(R?(RÁR~(R¹(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys ­ sRäRëRsR­(sdnsrecord_partsdnsrecord_extra(srename( R¸RÂt get_optionsRMR‚R•R¨tcloneR'(Rº((R¹s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRë s cO@sÆt|tƒst‚y|j|tƒ\}}Wn$tjk rW|jj|ŒnXx|j ƒD]ö} | tkr}qent|| t t fƒs¦|| g} n || } xŽ| D]†} y|| j | ƒWq·t tfk r<y)|j| } t| jp | jƒ} Wn | } nXtjd| d| ƒ‚q·Xq·Wt t|| ƒƒ|| RuRRfRKR•RRÃRR<RR*R(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR› s       +   R·cB@s0eZedƒZejejfZd„ZRS(sDisplay DNS resource.cO@sWt|tƒst‚|jj|Œr@tg||jjjqn&tˆtƒrdˆjddƒVqnˆVqWdS(Nc3@s|]}|ˆjkVqdS(N(R?(RÁR~(R¹(s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pys P sRäRëR­(sdnsrecord_partsdnsrecord_extra(R¸RwRÃRMR•R¨RÄR'(Rº((R¹s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÃN s cO@s%t|tƒst‚|||jfS(N(R•RÿRt SCOPE_SUBTREE(RºRR2RR3R4R)R((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRX sc O@s|rŒ|jj|jj}|j|dƒ}|dd|kratg|dd|jjR$R t takes_argsR<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR¼j s     tdns_is_enabledcB@sGeZdZeZejZeddd e j j ƒZ dZ d„ZRS( sC Checks if any of the servers has the DNS service enabled. RdReRfRgs((&(objectClass=ipaConfigObject)(cn=DNS))cO@su|jjj}t}y7|jd|jd|jƒ}t|ƒrKt}nWnt k ra}nXt d|ddƒS(NR2R3R~R@u( RR RRfRhR2R3R‰RWR˜RC(RºR)RRt dns_enabledtentR*((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR< s  (scnsmasters(scnsipa(scnsetc(R R RúRWRÁRR=R>RÿRRÁRÃR3R2R<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÒ† s  t dnsconfigc B@seZdZedƒZdddgZedƒZedƒZede ddd ed ƒd ed ƒd e ƒe dddd edƒd edƒdd ƒe dddd edƒd edƒƒe dddd edƒƒfZd„Zd„Zd„ZRS(!s) DNS global configuration object sDNS configuration optionsRØR×tidnsallowsyncptrsDNS Global Configurationsidnsforwarders*R«RnRhsGlobal forwardersR¬ssGlobal forwarders. A custom port can be specified for each forwarder using a standard format "IP_ADDRESS port PORT"R®sidnsforwardpolicy?RìsForward policysTGlobal forwarding policy. Set to "none" to disable any configured global forwarders.R¾uonlyufirstunonesidnsallowsyncptr?RísAllow PTR syncsDAllow synchronization of forward (A, AAAA) and reverse (PTR) recordssidnszonerefresh?t zone_refreshsZone refresh intervalcO@sttjjtjjƒS(N(RÿRRÁRÂRÃ(RºRR ((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRîÇ scC@s"|j|jƒdƒ\}}|S(N(RÀRîR'(RºRRRm((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyt get_dnsconfigÊ sc@s<t‡fd†|jDƒƒs8ttdƒƒˆdÐ ss!Global DNS configuration is emptytsummary(RMR'R&R(RºR~((R~s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytpostprocess_resultÏ s(uonlyufirstunone(R R RúRRüRRhRR RrRWR RR RRîRØRÚ(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÕ  s4              t dnsconfig_modcB@seZedƒZd„ZRS(s Modify global DNS configuration.cO@s/tt|ƒj||Ž}|jj|ƒ|S(N(R¸RÛR<RRÚ(RºRRR~((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR<Ù s(R R RRúR<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÛÖ s tdnsconfig_showcB@seZedƒZd„ZRS(s*Show the current global DNS configuration.cO@s/tt|ƒj||Ž}|jj|ƒ|S(N(R¸RÜR<RRÚ(RºRRR~((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyR<ä s(R R RRúR<(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pyRÜá s (™t __future__RR0R-RZtdns.nameR½tipalib.requestRtipalibRRRRtipalib.parametersRRRR R R R R tipalib.plugins.baseldapRRt ipalib.utilRRRRRRRRRRRtipapython.ipautilRRRRúR±ReRšR™R˜ttR2R²RRR+R.R>R'RFRGRHRKRZRbRgRkRrRsRtRvRRƒRRWR¢R§R¨R RRRRR%R'R.R0R2R4R8R:R?RARGRIRORnRoRpRwRyRR€RŠR‹RRŽR—R˜R£R¥R§R¬R®R°R²R·RºR–R”RœR¿RÄRÆRt LDAPObjectRÈtregisterRRt LDAPDeleteR R&R%R7R„R8R†t LDAPQueryR9R?R@RJRKR€RªRÀRÂR·RwR¼RÒRÕRÛRÜ(((s0/home/mkosek/freeipa-clean/ipalib/plugins/dns.pytsX    : L¹    )       "    "&ÿ *     | %    -      Þ j   +    "  ÿ » š  ˜  !   3  freeipa-3.3.4/ipalib/plugins/hostgroup.py0000664000175000017500000001613712271663206020044 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # Copyright (C) 2009 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 . from ipalib.plugins.baseldap import * from ipalib import api, Int, _, ngettext, errors from ipalib.plugins.netgroup import NETGROUP_PATTERN, NETGROUP_PATTERN_ERRMSG from ipapython.dn import DN __doc__ = _(""" Groups of hosts. Manage groups of hosts. This is useful for applying access control to a number of hosts by using Host-based Access Control. EXAMPLES: Add a new host group: ipa hostgroup-add --desc="Baltimore hosts" baltimore Add another new host group: ipa hostgroup-add --desc="Maryland hosts" maryland Add members to the hostgroup (using Bash brace expansion): ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore Add a hostgroup as a member of another hostgroup: ipa hostgroup-add-member --hostgroups=baltimore maryland Remove a host from the hostgroup: ipa hostgroup-remove-member --hosts=box2 baltimore Display a host group: ipa hostgroup-show baltimore Delete a hostgroup: ipa hostgroup-del baltimore """) class hostgroup(LDAPObject): """ Hostgroup object. """ container_dn = api.env.container_hostgroup object_name = _('host group') object_name_plural = _('host groups') object_class = ['ipaobject', 'ipahostgroup'] default_attributes = ['cn', 'description', 'member', 'memberof', 'memberindirect', 'memberofindirect', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['host', 'hostgroup'], 'memberof': ['hostgroup', 'netgroup', 'hbacrule', 'sudorule'], 'memberindirect': ['host', 'hostgroup'], 'memberofindirect': ['hostgroup', 'hbacrule', 'sudorule'], } label = _('Host Groups') label_singular = _('Host Group') takes_params = ( Str('cn', pattern=NETGROUP_PATTERN, pattern_errmsg=NETGROUP_PATTERN_ERRMSG, cli_name='hostgroup_name', label=_('Host-group'), doc=_('Name of host-group'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description', cli_name='desc', label=_('Description'), doc=_('A description of this host-group'), ), ) def suppress_netgroup_memberof(self, ldap, dn, entry_attrs): """ We don't want to show managed netgroups so remove them from the memberOf list. """ hgdn = DN(dn) for member in list(entry_attrs.get('memberof', [])): ngdn = DN(member) if ngdn['cn'] != hgdn['cn']: continue filter = ldap.make_filter({'objectclass': 'mepmanagedentry'}) try: ldap.get_entries(ngdn, ldap.SCOPE_BASE, filter, ['']) except errors.NotFound: pass else: entry_attrs['memberof'].remove(member) api.register(hostgroup) class hostgroup_add(LDAPCreate): __doc__ = _('Add a new hostgroup.') msg_summary = _('Added hostgroup "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: # check duplicity with hostgroups first to provide proper error api.Object['hostgroup'].get_dn_if_exists(keys[-1]) self.obj.handle_duplicate_entry(*keys) except errors.NotFound: pass try: # when enabled, a managed netgroup is created for every hostgroup # make sure that the netgroup can be created api.Object['netgroup'].get_dn_if_exists(keys[-1]) raise errors.DuplicateEntry(message=unicode(_(\ u'netgroup with name "%s" already exists. ' \ u'Hostgroups and netgroups share a common namespace'\ ) % keys[-1])) except errors.NotFound: pass return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # Always wait for the associated netgroup to be created so we can # be sure to ignore it in memberOf newentry = wait_for_value(ldap, dn, 'objectclass', 'mepOriginEntry') entry_from_entry(entry_attrs, newentry) self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return dn api.register(hostgroup_add) class hostgroup_del(LDAPDelete): __doc__ = _('Delete a hostgroup.') msg_summary = _('Deleted hostgroup "%(value)s"') api.register(hostgroup_del) class hostgroup_mod(LDAPUpdate): __doc__ = _('Modify a hostgroup.') msg_summary = _('Modified hostgroup "%(value)s"') def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return dn api.register(hostgroup_mod) class hostgroup_find(LDAPSearch): __doc__ = _('Search for hostgroups.') member_attributes = ['member', 'memberof'] msg_summary = ngettext( '%(count)d hostgroup matched', '%(count)d hostgroups matched', 0 ) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, entry_attrs) = entry self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return truncated api.register(hostgroup_find) class hostgroup_show(LDAPRetrieve): __doc__ = _('Display information about a hostgroup.') def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return dn api.register(hostgroup_show) class hostgroup_add_member(LDAPAddMember): __doc__ = _('Add members to a hostgroup.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return (completed, dn) api.register(hostgroup_add_member) class hostgroup_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from a hostgroup.') def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, dn, entry_attrs) return (completed, dn) api.register(hostgroup_remove_member) freeipa-3.3.4/ipalib/plugins/group.py0000664000175000017500000005431012271663206017141 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # Copyright (C) 2009 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 . from ipalib import api from ipalib import Int, Str from ipalib.plugins.baseldap import * from ipalib.plugins import baseldap from ipalib import _, ngettext if api.env.in_server and api.env.context in ['lite', 'server']: try: import ipaserver.dcerpc _dcerpc_bindings_installed = True except ImportError: _dcerpc_bindings_installed = False __doc__ = _(""" Groups of users Manage groups of users. By default, new groups are POSIX groups. You can add the --nonposix option to the group-add command to mark a new group as non-POSIX. You can use the --posix argument with the group-mod command to convert a non-POSIX group into a POSIX group. POSIX groups cannot be converted to non-POSIX groups. Every group must have a description. POSIX groups must have a Group ID (GID) number. Changing a GID is supported but can have an impact on your file permissions. It is not necessary to supply a GID when creating a group. IPA will generate one automatically if it is not provided. EXAMPLES: Add a new group: ipa group-add --desc='local administrators' localadmins Add a new non-POSIX group: ipa group-add --nonposix --desc='remote administrators' remoteadmins Convert a non-POSIX group to posix: ipa group-mod --posix remoteadmins Add a new POSIX group with a specific Group ID number: ipa group-add --gid=500 --desc='unix admins' unixadmins Add a new POSIX group and let IPA assign a Group ID number: ipa group-add --desc='printer admins' printeradmins Remove a group: ipa group-del unixadmins To add the "remoteadmins" group to the "localadmins" group: ipa group-add-member --groups=remoteadmins localadmins Add multiple users to the "localadmins" group: ipa group-add-member --users=test1 --users=test2 localadmins Remove a user from the "localadmins" group: ipa group-remove-member --users=test2 localadmins Display information about a named group. ipa group-show localadmins External group membership is designed to allow users from trusted domains to be mapped to local POSIX groups in order to actually use IPA resources. External members should be added to groups that specifically created as external and non-POSIX. Such group later should be included into one of POSIX groups. An external group member is currently a Security Identifier (SID) as defined by the trusted domain. When adding external group members, it is possible to specify them in either SID, or DOM\\name, or name@domain format. IPA will attempt to resolve passed name to SID with the use of Global Catalog of the trusted domain. Example: 1. Create group for the trusted domain admins' mapping and their local POSIX group: ipa group-add --desc=' admins external map' ad_admins_external --external ipa group-add --desc=' admins' ad_admins 2. Add security identifier of Domain Admins of the to the ad_admins_external group: ipa group-add-member ad_admins_external --external 'AD\\Domain Admins' 3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group: ipa group-add-member ad_admins --groups ad_admins_external 4. List members of external members of ad_admins_external group to see their SIDs: ipa group-show ad_admins_external """) PROTECTED_GROUPS = (u'admins', u'trust admins', u'default smb group') class group(LDAPObject): """ Group object. """ container_dn = api.env.container_group object_name = _('group') object_name_plural = _('groups') object_class = ['ipausergroup'] object_class_config = 'ipagroupobjectclasses' possible_objectclasses = ['posixGroup', 'mepManagedEntry', 'ipaExternalGroup'] search_attributes_config = 'ipagroupsearchfields' default_attributes = [ 'cn', 'description', 'gidnumber', 'member', 'memberof', 'memberindirect', 'memberofindirect', 'ipaexternalmember', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['user', 'group'], 'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], 'memberindirect': ['user', 'group'], 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], } rdn_is_primary_key = True label = _('User Groups') label_singular = _('User Group') takes_params = ( Str('cn', pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', maxlength=255, cli_name='group_name', label=_('Group name'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description', cli_name='desc', label=_('Description'), doc=_('Group description'), ), Int('gidnumber?', cli_name='gid', label=_('GID'), doc=_('GID (use this option to set it manually)'), minvalue=1, ), ) api.register(group) ipaexternalmember_param = Str('ipaexternalmember*', cli_name='external', label=_('External member'), doc=_('Members of a trusted domain in DOM\\name or name@domain form'), csv=True, flags=['no_create', 'no_update', 'no_search'], ) class group_add(LDAPCreate): __doc__ = _('Create a new group.') msg_summary = _('Added group "%(value)s"') takes_options = LDAPCreate.takes_options + ( Flag('nonposix', cli_name='nonposix', doc=_('Create as a non-POSIX group'), default=False, ), Flag('external', cli_name='external', doc=_('Allow adding external non-IPA members from trusted domains'), default=False, ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): # As both 'external' and 'nonposix' options have default= set for # them, they will always be present in options dict, thus we can # safely reference the values assert isinstance(dn, DN) if options['external']: entry_attrs['objectclass'].append('ipaexternalgroup') if 'gidnumber' in options: raise errors.RequirementError(name='gid') elif not options['nonposix']: entry_attrs['objectclass'].append('posixgroup') if not 'gidnumber' in options: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC return dn api.register(group_add) class group_del(LDAPDelete): __doc__ = _('Delete group.') msg_summary = _('Deleted group "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) config = ldap.get_ipa_config()[1] def_primary_group = config.get('ipadefaultprimarygroup', '') def_primary_group_dn = group_dn = self.obj.get_dn(def_primary_group) if dn == def_primary_group_dn: raise errors.DefaultGroupError() group_attrs = self.obj.methods.show( self.obj.get_primary_key_from_dn(dn), all=True )['result'] if keys[0] in PROTECTED_GROUPS: raise errors.ProtectedEntryError(label=_(u'group'), key=keys[0], reason=_(u'privileged group')) if 'mepmanagedby' in group_attrs: raise errors.ManagedGroupError() return dn def post_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) try: api.Command['pwpolicy_del'](keys[-1]) except errors.NotFound: pass return True api.register(group_del) class group_mod(LDAPUpdate): __doc__ = _('Modify a group.') msg_summary = _('Modified group "%(value)s"') takes_options = LDAPUpdate.takes_options + ( Flag('posix', cli_name='posix', doc=_('change to a POSIX group'), ), Flag('external', cli_name='external', doc=_('change to support external non-IPA members from trusted domains'), default=False, ), ) def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) is_protected_group = keys[-1] in PROTECTED_GROUPS if 'rename' in options or 'cn' in entry_attrs: if is_protected_group: raise errors.ProtectedEntryError(label=u'group', key=keys[-1], reason=u'Cannot be renamed') if ('posix' in options and options['posix']) or 'gidnumber' in options: (dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass']) if 'ipaexternalgroup' in old_entry_attrs['objectclass']: raise errors.ExternalGroupViolation() if 'posixgroup' in old_entry_attrs['objectclass']: if options['posix']: raise errors.AlreadyPosixGroup() else: old_entry_attrs['objectclass'].append('posixgroup') entry_attrs['objectclass'] = old_entry_attrs['objectclass'] if not 'gidnumber' in options: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC if options['external']: if is_protected_group: raise errors.ProtectedEntryError(label=u'group', key=keys[-1], reason=u'Cannot support external non-IPA members') (dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass']) if 'posixgroup' in old_entry_attrs['objectclass']: raise errors.PosixGroupViolation() if 'ipaexternalgroup' in old_entry_attrs['objectclass']: raise errors.AlreadyExternalGroup() else: old_entry_attrs['objectclass'].append('ipaexternalgroup') entry_attrs['objectclass'] = old_entry_attrs['objectclass'] # Can't check for this in a validator because we lack context if 'gidnumber' in options and options['gidnumber'] is None: raise errors.RequirementError(name='gid') return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): # Check again for GID requirement in case someone tried to clear it # using --setattr. if call_func.func_name == 'update_entry': if isinstance(exc, errors.ObjectclassViolation): if 'gidNumber' in exc.message and 'posixGroup' in exc.message: raise errors.RequirementError(name='gid') raise exc api.register(group_mod) class group_find(LDAPSearch): __doc__ = _('Search for groups.') member_attributes = ['member', 'memberof'] msg_summary = ngettext( '%(count)d group matched', '%(count)d groups matched', 0 ) takes_options = LDAPSearch.takes_options + ( Flag('private', cli_name='private', doc=_('search for private groups'), ), Flag('posix', cli_name='posix', doc=_('search for POSIX groups'), ), Flag('external', cli_name='external', doc=_('search for groups with support of external non-IPA members from trusted domains'), ), Flag('nonposix', cli_name='nonposix', doc=_('search for non-POSIX groups'), ), ) def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) # filter groups by pseudo type filters = [] if options['posix']: search_kw = {'objectclass': ['posixGroup']} filters.append(ldap.make_filter(search_kw, rules=ldap.MATCH_ALL)) if options['external']: search_kw = {'objectclass': ['ipaExternalGroup']} filters.append(ldap.make_filter(search_kw, rules=ldap.MATCH_ALL)) if options['nonposix']: search_kw = {'objectclass': ['posixGroup' , 'ipaExternalGroup']} filters.append(ldap.make_filter(search_kw, rules=ldap.MATCH_NONE)) # if looking for private groups, we need to create a new search filter, # because private groups have different object classes if options['private']: # filter based on options, oflt search_kw = self.args_options_2_entry(**options) search_kw['objectclass'] = ['posixGroup', 'mepManagedEntry'] oflt = ldap.make_filter(search_kw, rules=ldap.MATCH_ALL) # filter based on 'criteria' argument search_kw = {} config = ldap.get_ipa_config()[1] attrs = config.get(self.obj.search_attributes_config, []) if len(attrs) == 1 and isinstance(attrs[0], basestring): search_attrs = attrs[0].split(',') for a in search_attrs: search_kw[a] = args[-1] cflt = ldap.make_filter(search_kw, exact=False) filter = ldap.combine_filters((oflt, cflt), rules=ldap.MATCH_ALL) elif filters: filters.append(filter) filter = ldap.combine_filters(filters, rules=ldap.MATCH_ALL) return (filter, base_dn, scope) api.register(group_find) class group_show(LDAPRetrieve): __doc__ = _('Display information about a named group.') has_output_params = LDAPRetrieve.has_output_params + (ipaexternalmember_param,) def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if ('ipaexternalmember' in entry_attrs and len(entry_attrs['ipaexternalmember']) > 0 and 'trust_resolve' in self.Command and not options.get('raw', False)): sids = entry_attrs['ipaexternalmember'] result = self.Command.trust_resolve(sids=sids) for entry in result['result']: try: idx = sids.index(entry['sid'][0]) sids[idx] = entry['name'][0] except ValueError: pass return dn api.register(group_show) class group_add_member(LDAPAddMember): __doc__ = _('Add members to a group.') takes_options = (ipaexternalmember_param,) def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) result = (completed, dn) if 'ipaexternalmember' in options: if not _dcerpc_bindings_installed: raise errors.NotFound(reason=_('Cannot perform external member validation without ' 'Samba 4 support installed. Make sure you have installed ' 'server-trust-ad sub-package of IPA on the server')) domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound(reason=_('Cannot perform join operation without own domain configured. ' 'Make sure you have run ipa-adtrust-install on the IPA server first')) sids = [] failed_sids = [] for sid in options['ipaexternalmember']: if domain_validator.is_trusted_sid_valid(sid): sids.append(sid) else: try: actual_sid = domain_validator.get_trusted_domain_object_sid(sid) except errors.PublicError, e: failed_sids.append((sid, e.strerror)) else: sids.append(actual_sid) restore = [] if 'member' in failed and 'group' in failed['member']: restore = failed['member']['group'] failed['member']['group'] = list((id,id) for id in sids) result = add_external_post_callback('member', 'group', 'ipaexternalmember', ldap, completed, failed, dn, entry_attrs, keys, options, external_callback_normalize=False) failed['member']['group'] += restore + failed_sids return result api.register(group_add_member) class group_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from a group.') takes_options = (ipaexternalmember_param,) def pre_callback(self, ldap, dn, found, not_found, *keys, **options): assert isinstance(dn, DN) if keys[0] in PROTECTED_GROUPS: protected_group_name = keys[0] result = api.Command.group_show(protected_group_name) users_left = set(result['result'].get('member_user', [])) users_deleted = set(options['user']) if users_left.issubset(users_deleted): raise errors.LastMemberError(key=sorted(users_deleted)[0], label=_(u'group'), container=protected_group_name) return dn def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) result = (completed, dn) if 'ipaexternalmember' in options: if not _dcerpc_bindings_installed: raise errors.NotFound(reason=_('Cannot perform external member validation without ' 'Samba 4 support installed. Make sure you have installed ' 'server-trust-ad sub-package of IPA on the server')) domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound(reason=_('Cannot perform join operation without own domain configured. ' 'Make sure you have run ipa-adtrust-install on the IPA server first')) sids = [] failed_sids = [] for sid in options['ipaexternalmember']: if domain_validator.is_trusted_sid_valid(sid): sids.append(sid) else: try: actual_sid = domain_validator.get_trusted_domain_object_sid(sid) except errors.PublicError, e: failed_sids.append((sid, unicode(e))) else: sids.append(actual_sid) restore = [] if 'member' in failed and 'group' in failed['member']: restore = failed['member']['group'] failed['member']['group'] = list((id,id) for id in sids) result = remove_external_post_callback('member', 'group', 'ipaexternalmember', ldap, completed, failed, dn, entry_attrs, keys, options) failed['member']['group'] += restore + failed_sids return result api.register(group_remove_member) class group_detach(LDAPQuery): __doc__ = _('Detach a managed group from a user.') has_output = output.standard_value msg_summary = _('Detached group "%(value)s" from user "%(value)s"') def execute(self, *keys, **options): """ This requires updating both the user and the group. We first need to verify that both the user and group can be updated, then we go about our work. We don't want a situation where only the user or group can be modified and we're left in a bad state. """ ldap = self.obj.backend group_dn = self.obj.get_dn(*keys, **options) user_dn = self.api.Object['user'].get_dn(*keys) try: (user_dn, user_attrs) = ldap.get_entry(user_dn) except errors.NotFound: self.obj.handle_not_found(*keys) is_managed = self.obj.has_objectclass(user_attrs['objectclass'], 'mepmanagedentry') if (not ldap.can_write(user_dn, "objectclass") or not (ldap.can_write(user_dn, "mepManagedEntry")) and is_managed): raise errors.ACIError(info=_('not allowed to modify user entries')) (group_dn, group_attrs) = ldap.get_entry(group_dn) is_managed = self.obj.has_objectclass(group_attrs['objectclass'], 'mepmanagedby') if (not ldap.can_write(group_dn, "objectclass") or not (ldap.can_write(group_dn, "mepManagedBy")) and is_managed): raise errors.ACIError(info=_('not allowed to modify group entries')) objectclasses = user_attrs['objectclass'] try: i = objectclasses.index('mepOriginEntry') del objectclasses[i] update_attrs = {'objectclass': objectclasses, 'mepManagedEntry': None} ldap.update_entry(user_dn, update_attrs) except ValueError: # Somehow the user isn't managed, let it pass for now. We'll # let the group throw "Not managed". pass (group_dn, group_attrs) = ldap.get_entry(group_dn) objectclasses = group_attrs['objectclass'] try: i = objectclasses.index('mepManagedEntry') except ValueError: # this should never happen raise errors.NotFound(reason=_('Not a managed group')) del objectclasses[i] # Make sure the resulting group has the default group objectclasses config = ldap.get_ipa_config()[1] def_objectclass = config.get( self.obj.object_class_config, objectclasses ) objectclasses = list(set(def_objectclass + objectclasses)) update_attrs = {'objectclass': objectclasses, 'mepManagedBy': None} ldap.update_entry(group_dn, update_attrs) return dict( result=True, value=keys[0], ) api.register(group_detach) freeipa-3.3.4/ipalib/plugins/sudocmdgroup.pyc0000664000175000017500000001124012271707517020662 0ustar mkosekmkosekó †fçRc@szddlmZddlmZddlTddlmZmZedƒZdedƒfZdefd „ƒYZ ej e ƒd e fd „ƒYZ ej e ƒd e fd „ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdefd„ƒYZej eƒdS(iÿÿÿÿ(tapi(tStr(t*(t_tngettexts  Groups of Sudo Commands Manage groups of Sudo Commands. EXAMPLES: Add a new Sudo Command Group: ipa sudocmdgroup-add --desc='administrators commands' admincmds Remove a Sudo Command Group: ipa sudocmdgroup-del admincmds Manage Sudo Command Group membership, commands: ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/vim admincmds Manage Sudo Command Group membership, commands: ipa group-remove-member --sudocmds=/usr/bin/less admincmds Show a Sudo Command Group: ipa group-show localadmins tsudos+commands for controlling sudo configurationt sudocmdgroupc BseZdZejjZedƒZedƒZ ddgZ dddgZ dZ id gd6Z ed ƒZed ƒZedd d ded ƒdedd„ƒedd ddedƒdedƒƒeddedƒddddgƒedded ƒddddgƒfZRS(s$ Sudo Command Group object. ssudo command groupssudo command groupst ipaobjectt ipasudocmdgrptcnt descriptiontmembert ipauniqueidtsudocmdsSudo Command GroupssSudo Command Grouptcli_nametsudocmdgroup_nametlabelt primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pytJstdesct DescriptiontdocsGroup descriptionsmembercmd_sudocmd?tCommandstflagst no_createt no_updatet no_searchsmembercmd_sudocmdgroup?(t__name__t __module__t__doc__Rtenvtcontainer_sudocmdgroupt container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributetattribute_membersRtlabel_singularRtTruet takes_params(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR2s4                 tsudocmdgroup_addcBs eZedƒZedƒZRS(sCreate new Sudo Command Group.s$Added Sudo Command Group "%(value)s"(RRRR t msg_summary(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR-^s tsudocmdgroup_delcBs eZedƒZedƒZRS(sDelete Sudo Command Group.s&Deleted Sudo Command Group "%(value)s"(RRRR R.(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR/fs tsudocmdgroup_modcBs eZedƒZedƒZRS(sModify Sudo Command Group.s'Modified Sudo Command Group "%(value)s"(RRRR R.(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR0ns tsudocmdgroup_findcBs&eZedƒZedddƒZRS(sSearch for Sudo Command Groups.s$%(count)d Sudo Command Group matcheds%%(count)d Sudo Command Groups matchedi(RRRR RR.(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR1vs tsudocmdgroup_showcBseZedƒZRS(sDisplay Sudo Command Group.(RRRR (((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR2stsudocmdgroup_add_membercBseZedƒZRS(s"Add members to Sudo Command Group.(RRRR (((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR3‡stsudocmdgroup_remove_membercBseZedƒZRS(s'Remove members from Sudo Command Group.(RRRR (((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyR4sN(tipalibRRtipalib.plugins.baseldapRRR ttopict LDAPObjectRtregistert LDAPCreateR-t LDAPDeleteR/t LDAPUpdateR0t LDAPSearchR1t LDAPRetrieveR2t LDAPAddMemberR3tLDAPRemoveMemberR4(((s9/home/mkosek/freeipa-clean/ipalib/plugins/sudocmdgroup.pyts,  )       freeipa-3.3.4/ipalib/plugins/__init__.pyc0000664000175000017500000000031512271707517017707 0ustar mkosekmkosekó ­8 Rc@s dZdS(s* Sub-package containing all core plugins. N(t__doc__(((s5/home/mkosek/freeipa-clean/ipalib/plugins/__init__.pytsfreeipa-3.3.4/ipalib/plugins/group.pyc0000664000175000017500000004623112271707517017313 0ustar mkosekmkosekó †fçRc@s7ddlmZddlmZmZddlTddlmZddlmZmZej j r§ej j d+kr§yddl Z eZWq§ek r£eZq§Xned ƒZd,Zd efd„ƒYZejeƒeddddedƒdedƒdeddddgƒZdefd„ƒYZejeƒdefd„ƒYZejeƒdefd „ƒYZejeƒd!efd"„ƒYZejeƒd#e fd$„ƒYZ!eje!ƒd%e"fd&„ƒYZ#eje#ƒd'e$fd(„ƒYZ%eje%ƒd)e&fd*„ƒYZ'eje'ƒdS(-iÿÿÿÿ(tapi(tInttStr(t*(tbaseldap(t_tngettexttlitetserverNsH Groups of users Manage groups of users. By default, new groups are POSIX groups. You can add the --nonposix option to the group-add command to mark a new group as non-POSIX. You can use the --posix argument with the group-mod command to convert a non-POSIX group into a POSIX group. POSIX groups cannot be converted to non-POSIX groups. Every group must have a description. POSIX groups must have a Group ID (GID) number. Changing a GID is supported but can have an impact on your file permissions. It is not necessary to supply a GID when creating a group. IPA will generate one automatically if it is not provided. EXAMPLES: Add a new group: ipa group-add --desc='local administrators' localadmins Add a new non-POSIX group: ipa group-add --nonposix --desc='remote administrators' remoteadmins Convert a non-POSIX group to posix: ipa group-mod --posix remoteadmins Add a new POSIX group with a specific Group ID number: ipa group-add --gid=500 --desc='unix admins' unixadmins Add a new POSIX group and let IPA assign a Group ID number: ipa group-add --desc='printer admins' printeradmins Remove a group: ipa group-del unixadmins To add the "remoteadmins" group to the "localadmins" group: ipa group-add-member --groups=remoteadmins localadmins Add multiple users to the "localadmins" group: ipa group-add-member --users=test1 --users=test2 localadmins Remove a user from the "localadmins" group: ipa group-remove-member --users=test2 localadmins Display information about a named group. ipa group-show localadmins External group membership is designed to allow users from trusted domains to be mapped to local POSIX groups in order to actually use IPA resources. External members should be added to groups that specifically created as external and non-POSIX. Such group later should be included into one of POSIX groups. An external group member is currently a Security Identifier (SID) as defined by the trusted domain. When adding external group members, it is possible to specify them in either SID, or DOM\name, or name@domain format. IPA will attempt to resolve passed name to SID with the use of Global Catalog of the trusted domain. Example: 1. Create group for the trusted domain admins' mapping and their local POSIX group: ipa group-add --desc=' admins external map' ad_admins_external --external ipa group-add --desc=' admins' ad_admins 2. Add security identifier of Domain Admins of the to the ad_admins_external group: ipa group-add-member ad_admins_external --external 'AD\Domain Admins' 3. Allow members of ad_admins_external group to be associated with ad_admins POSIX group: ipa group-add-member ad_admins --groups ad_admins_external 4. List members of external members of ad_admins_external group to see their SIDs: ipa group-show ad_admins_external uadminsu trust adminsudefault smb grouptgroupcBszeZdZejjZedƒZedƒZ dgZ dZ dddgZ dZ d d d d d dddgZdZiddgd 6dddddgd 6ddgd6dddddgd6ZeZedƒZedƒZed dddddddd d!ed"ƒd#ed$d%„ƒed dd&d!ed'ƒd(ed)ƒƒed*dd+d!ed,ƒd(ed-ƒd.d/ƒfZRS(0s Group object. R tgroupst ipausergrouptipagroupobjectclassest posixGrouptmepManagedEntrytipaExternalGrouptipagroupsearchfieldstcnt descriptiont gidnumbertmembertmemberoftmemberindirecttmemberofindirecttipaexternalmembert ipauniqueidtusertnetgrouptrolethbacruletsudorules User Groupss User Grouptpatterns4^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$tpattern_errmsgs0may only include letters, numbers, _, -, . and $t maxlengthiÿtcli_namet group_nametlabels Group namet primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyt—stdesct DescriptiontdocsGroup descriptions gidnumber?tgidtGIDs(GID (use this option to set it manually)tminvaluei(t__name__t __module__t__doc__Rtenvtcontainer_groupt container_dnRt object_nametobject_name_pluralt object_classtobject_class_configtpossible_objectclassestsearch_attributes_configtdefault_attributestuuid_attributetattribute_memberstTruetrdn_is_primary_keyR$tlabel_singularRRt takes_params(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyR ssJ                   sipaexternalmember*R"texternalR$sExternal memberR,s;Members of a trusted domain in DOM\name or name@domain formtcsvtflagst no_createt no_updatet no_searcht group_addc BsxeZedƒZedƒZejeddddedƒdeƒeddddedƒdeƒfZd „Z RS( sCreate a new group.sAdded group "%(value)s"tnonposixR"R,sCreate as a non-POSIX grouptdefaultRCs:Allow adding external non-IPA members from trusted domainscOs’t|tƒst‚|drT|djdƒd|krŽtjddƒ‚qŽn:|dsŽ|djdƒd|krŽtj|d"    cOsd|jdkrZt|tjƒrZd|jkrWd|jkrWtjddƒ‚qWqZn|‚dS(Nt update_entryt gidNumberR RNR-(t func_nameRPRTtObjectclassViolationtmessageRU(RWR\R]texct call_funct call_argst call_kwargs((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyt exc_callback1s ( R0R1RR2R_t LDAPUpdateRaRbRcR^R”(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyR€÷s        )t group_findc Bs´eZedƒZddgZedddƒZeje dddded ƒƒe d dd ded ƒƒe d dd ded ƒƒe ddddedƒƒfZd„Z RS(sSearch for groups.RRs%(count)d group matcheds%(count)d groups matcheditprivateR"R,ssearch for private groupsRssearch for POSIX groupsRCsOsearch for groups with support of external non-IPA members from trusted domainsRJssearch for non-POSIX groupscOs t|tƒst‚g}|drWidgd6} |j|j| d|jƒƒn|dr“idgd6} |j|j| d|jƒƒn|drÒiddgd6} |j|j| d|jƒƒn|drÑ|j|} dd g| d<|j| d|jƒ} i} |jƒd } | j |j j gƒ} t | ƒd kr›t| d t ƒr›| d jd ƒ} x| D]}|d | |¸stexternal_callback_normalize(RPRQRRt_dcerpc_bindings_installedRTR~Rt ipaservertdcerpctDomainValidatorRt is_configuredtis_trusted_sid_validRStget_trusted_domain_object_sidt PublicErrortstrerrortlisttadd_external_post_callbackRc(RWRXt completedtfailedRYRZR\R]Rhtdomain_validatorR³t failed_sidsR´t actual_sidtetrestore((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyRs6    (R0R1RR2R»RaR(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyR¼˜s  tgroup_remove_membercBs/eZedƒZefZd„Zd„ZRS(sRemove members from a group.c Os´t|tƒst‚|dtkr°|d}tjj|ƒ}t|djdgƒƒ} t|dƒ} | j | ƒr°t j dt | ƒddt dƒd|ƒ‚q°n|S( NiRht member_userRRiR$ugroupt container(RPRQRRRtRR}R°tsetRmtissubsetRTtLastMemberErrortsortedR( RWRXRYtfoundt not_foundR\R]tprotected_group_nameRht users_leftt users_deleted((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyR^Çs c Os³t|tƒst‚||f}d|kr¯tsNtjdtdƒƒ‚ntjj |j ƒ} | j ƒsŠtjdtdƒƒ‚ng} g} xƒ|dD]w} | j | ƒrÆ| j | ƒq¡y| j| ƒ} Wn/tjk r }| j | t|ƒfƒq¡X| j | ƒq¡Wg}d|krOd|dkrO|dd}ntd„| Dƒƒ|ddîs(RPRQRRRÀRTR~RRÁRÂRÃRRÄRÅRSRÆRÇtunicodeRÉtremove_external_post_callback(RWRXRËRÌRYRZR\R]RhRÍR³RÎR´RÏRÐRÑ((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyRÓs6     (R0R1RR2R»RaR^R(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyRÒÂs   t group_detachcBs2eZedƒZejZedƒZd„ZRS(s#Detach a managed group from a user.s0Detached group "%(value)s" from user "%(value)s"c Os‰|jj}|jj||Ž}|jjdj|Œ}y|j|ƒ\}}Wn$tjk ry|jj|ŒnX|jj |ddƒ}|j |dƒ s¿|j |dƒ rÚ|rÚtj dt dƒƒ‚n|j|ƒ\}}|jj |ddƒ}|j |dƒ s4|j |dƒ rO|rOtj dt d ƒƒ‚n|d} y>| j d ƒ} | | =i| d6dd6} |j|| ƒWntk rªnX|j|ƒ\}}|d} y| j dƒ} Wn)tk rtjd t d ƒƒ‚nX| | =|jƒd } | j|jj| ƒ} tt| | ƒƒ} i| d6dd6} |j|| ƒtdtd|dƒS(s# This requires updating both the user and the group. We first need to verify that both the user and group can be updated, then we go about our work. We don't want a situation where only the user or group can be modified and we're left in a bad state. RRLtmepmanagedentryRtinfos"not allowed to modify user entriesRkt mepManagedBys#not allowed to modify group entriestmepOriginEntryRjsNot a managed groupiRhR(iN(RntbackendRoRtObjectRƒRTR~thandle_not_foundthas_objectclasst can_writetACIErrorRRµRˆR‹R¶RlRmR9RÉRÕtdictR?(RWR\R]RXRztuser_dnt user_attrst is_managedR{t objectclassestit update_attrsRwtdef_objectclass((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pytexecuteþsP     ( R0R1RR2toutputtstandard_valuet has_outputR_Ró(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pyRàøs   (slitesserver(uadminsu trust adminsudefault smb group((tipalibRRRtipalib.plugins.baseldaptipalib.pluginsRRRR3t in_servertcontexttipaserver.dcerpcRÁR?RÀt ImportErrorRcR2Rtt LDAPObjectR tregisterR»R`RIt LDAPDeleteRdR•R€R¯R–R¹R°t LDAPAddMemberR¼tLDAPRemoveMemberRÒt LDAPQueryRà(((s2/home/mkosek/freeipa-clean/ipalib/plugins/group.pytsJ     N 3    "  C C  ' 3 Dfreeipa-3.3.4/ipalib/plugins/hbacsvcgroup.py0000664000175000017500000000701312271663206020471 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib import api, errors from ipalib.plugins.baseldap import * from ipalib import _, ngettext __doc__ = _(""" HBAC Service Groups HBAC service groups can contain any number of individual services, or "members". Every group must have a description. EXAMPLES: Add a new HBAC service group: ipa hbacsvcgroup-add --desc="login services" login Add members to an HBAC service group: ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login Display information about a named group: ipa hbacsvcgroup-show login Delete an HBAC service group: ipa hbacsvcgroup-del login """) topic = ('hbac', _('Host based access control commands')) class hbacsvcgroup(LDAPObject): """ HBAC service group object. """ container_dn = api.env.container_hbacservicegroup object_name = _('HBAC service group') object_name_plural = _('HBAC service groups') object_class = ['ipaobject', 'ipahbacservicegroup'] default_attributes = [ 'cn', 'description', 'member' ] uuid_attribute = 'ipauniqueid' attribute_members = { 'member': ['hbacsvc'], } label = _('HBAC Service Groups') label_singular = _('HBAC Service Group') takes_params = ( Str('cn', cli_name='name', label=_('Service group name'), primary_key=True, normalizer=lambda value: value.lower(), ), Str('description', cli_name='desc', label=_('Description'), doc=_('HBAC service group description'), ), ) api.register(hbacsvcgroup) class hbacsvcgroup_add(LDAPCreate): __doc__ = _('Add a new HBAC service group.') msg_summary = _('Added HBAC service group "%(value)s"') api.register(hbacsvcgroup_add) class hbacsvcgroup_del(LDAPDelete): __doc__ = _('Delete an HBAC service group.') msg_summary = _('Deleted HBAC service group "%(value)s"') api.register(hbacsvcgroup_del) class hbacsvcgroup_mod(LDAPUpdate): __doc__ = _('Modify an HBAC service group.') msg_summary = _('Modified HBAC service group "%(value)s"') api.register(hbacsvcgroup_mod) class hbacsvcgroup_find(LDAPSearch): __doc__ = _('Search for an HBAC service group.') msg_summary = ngettext( '%(count)d HBAC service group matched', '%(count)d HBAC service groups matched', 0 ) api.register(hbacsvcgroup_find) class hbacsvcgroup_show(LDAPRetrieve): __doc__ = _('Display information about an HBAC service group.') api.register(hbacsvcgroup_show) class hbacsvcgroup_add_member(LDAPAddMember): __doc__ = _('Add members to an HBAC service group.') api.register(hbacsvcgroup_add_member) class hbacsvcgroup_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from an HBAC service group.') api.register(hbacsvcgroup_remove_member) freeipa-3.3.4/ipalib/plugins/role.py0000664000175000017500000001177312202434255016746 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # Copyright (C) 2009 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 . from ipalib.plugins.baseldap import * from ipalib import api, Str, _, ngettext from ipalib import Command from ipalib.plugins import privilege __doc__ = _(""" Roles A role is used for fine-grained delegation. A permission grants the ability to perform given low-level tasks (add a user, modify a group, etc.). A privilege combines one or more permissions into a higher-level abstraction such as useradmin. A useradmin would be able to add, delete and modify users. Privileges are assigned to Roles. Users, groups, hosts and hostgroups may be members of a Role. Roles can not contain other roles. EXAMPLES: Add a new role: ipa role-add --desc="Junior-level admin" junioradmin Add some privileges to this role: ipa role-add-privilege --privileges=addusers junioradmin ipa role-add-privilege --privileges=change_password junioradmin ipa role-add-privilege --privileges=add_user_to_default_group junioradmin Add a group of users to this role: ipa group-add --desc="User admins" useradmins ipa role-add-member --groups=useradmins junioradmin Display information about a role: ipa role-show junioradmin The result of this is that any users in the group 'junioradmin' can add users, reset passwords or add a user to the default IPA user group. """) class role(LDAPObject): """ Role object. """ container_dn = api.env.container_rolegroup object_name = _('role') object_name_plural = _('roles') object_class = ['groupofnames', 'nestedgroup'] default_attributes = ['cn', 'description', 'member', 'memberof', 'memberindirect', 'memberofindirect', ] attribute_members = { 'member': ['user', 'group', 'host', 'hostgroup'], 'memberof': ['privilege'], } reverse_members = { 'member': ['privilege'], } rdn_is_primary_key = True label = _('Roles') label_singular = _('Role') takes_params = ( Str('cn', cli_name='name', label=_('Role name'), primary_key=True, ), Str('description', cli_name='desc', label=_('Description'), doc=_('A description of this role-group'), ), ) api.register(role) class role_add(LDAPCreate): __doc__ = _('Add a new role.') msg_summary = _('Added role "%(value)s"') api.register(role_add) class role_del(LDAPDelete): __doc__ = _('Delete a role.') msg_summary = _('Deleted role "%(value)s"') api.register(role_del) class role_mod(LDAPUpdate): __doc__ = _('Modify a role.') msg_summary = _('Modified role "%(value)s"') api.register(role_mod) class role_find(LDAPSearch): __doc__ = _('Search for roles.') msg_summary = ngettext( '%(count)d role matched', '%(count)d roles matched', 0 ) api.register(role_find) class role_show(LDAPRetrieve): __doc__ = _('Display information about a role.') api.register(role_show) class role_add_member(LDAPAddMember): __doc__ = _('Add members to a role.') api.register(role_add_member) class role_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from a role.') api.register(role_remove_member) class role_add_privilege(LDAPAddReverseMember): __doc__ = _('Add privileges to a role.') show_command = 'role_show' member_command = 'privilege_add_member' reverse_attr = 'privilege' member_attr = 'role' has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of privileges added'), ), ) api.register(role_add_privilege) class role_remove_privilege(LDAPRemoveReverseMember): __doc__ = _('Remove privileges from a role.') show_command = 'role_show' member_command = 'privilege_remove_member' reverse_attr = 'privilege' member_attr = 'role' has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of privileges removed'), ), ) api.register(role_remove_privilege) freeipa-3.3.4/ipalib/plugins/kerberos.pyc0000664000175000017500000001050112271707517017762 0ustar mkosekmkosekó †fçRc@skdZddlZddlmZddlmZddlZdZdefd„ƒYZej eƒdS(sX Backend plugin for Kerberos. This wraps the python-kerberos and python-krbV bindings. iÿÿÿÿN(tapi(tBackendsUTF-8tkrbcBs_eZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z RS( sõ Kerberos backend plugin. This wraps the `krbV` bindings (and will eventually wrap the `kerberos` bindings also). Importantly, this plugin does correct Unicode encoding/decoding of values going-to/coming-from the bindings. cCstjƒjƒS(sN Return the ``krbV.CCache`` for the default credential cache. (tkrbVtdefault_contexttdefault_ccache(tself((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt__default_ccache+scCs|jƒjƒS(sQ Return the ``krb5.Principal`` for the default credential cache. (t_krb__default_ccachet principal(R((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt__default_principal1scCs tj|ƒS(sR Return the ``krbV.CCache`` for the ``ccname`` credential ccache. (RtCCache(Rtccname((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt __get_ccache7scCs|j|ƒjƒS(sU Return the ``krb5.Principal`` for the ``ccname`` credential ccache. (t_krb__get_ccacheR (RR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt__get_principal=scCs/|jƒ}dtd|jd|jƒ}|S(sî Return the default ccache file name (schema+name). This will return something like 'FILE:/tmp/krb5cc_500'. This cannot return anything meaningful if used in the server as a request is processed. s%(type)s:%(name)sttypetname(RtdictRR(RRR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pytdefault_ccnameCs  cCs|jƒjjtƒS(s? Return the principal name in default credential cache. This will return something like 'admin@EXAMPLE.COM'. If no credential cache exists for the invoking user, None is returned. This cannot return anything meaningful if used in the server as a request is processed. (t_krb__default_principalRtdecodetENCODING(R((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pytdefault_principalQs cCstjƒjjtƒS(s6 Return the realm from the default credential cache. This will return something like 'EXAMPLE.COM'. If no credential cache exists for the invoking user, None is returned. This cannot return anything meaningful if used in the server as a request is processed. (RRt default_realmRR(R((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyR]s cCs|j|ƒjjtƒS(sŽ Return the principal from credential cache file at ``ccname``. This will return something like 'admin@EXAMPLE.COM'. (t_krb__get_principalRRR(RR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt get_principaliscCs|j|ƒjjtƒS(s„ Return the realm from credential cache file at ``ccname``. This will return something like 'EXAMPLE.COM'. (RtrealmRR(RR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyt get_realmqs( t__name__t __module__t__doc__RRRRRRRRR(((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyR"s      ( RtsystipalibRtipalib.backendRRRRtregister(((s5/home/mkosek/freeipa-clean/ipalib/plugins/kerberos.pyts  Xfreeipa-3.3.4/ipalib/plugins/idrange.py0000664000175000017500000007251112271663206017421 0ustar mkosekmkosek# Authors: # Sumit Bose # # 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 . from ipalib.plugins.baseldap import (LDAPObject, LDAPCreate, LDAPDelete, LDAPRetrieve, LDAPSearch, LDAPUpdate) from ipalib import api, Int, Str, DeprecatedParam, StrEnum, _, ngettext from ipalib import errors from ipapython.dn import DN if api.env.in_server and api.env.context in ['lite', 'server']: try: import ipaserver.dcerpc _dcerpc_bindings_installed = True except ImportError: _dcerpc_bindings_installed = False __doc__ = _(""" ID ranges Manage ID ranges used to map Posix IDs to SIDs and back. There are two type of ID ranges which are both handled by this utility: - the ID ranges of the local domain - the ID ranges of trusted remote domains Both types have the following attributes in common: - base-id: the first ID of the Posix ID range - range-size: the size of the range With those two attributes a range object can reserve the Posix IDs starting with base-id up to but not including base-id+range-size exclusively. Additionally an ID range of the local domain may set - rid-base: the first RID(*) of the corresponding RID range - secondary-rid-base: first RID of the secondary RID range and an ID range of a trusted domain must set - rid-base: the first RID of the corresponding RID range - sid: domain SID of the trusted domain EXAMPLE: Add a new ID range for a trusted domain Since there might be more than one trusted domain the domain SID must be given while creating the ID range. ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\ --dom-sid=S-1-5-21-123-456-789 trusted_dom_range This ID range is then used by the IPA server and the SSSD IPA provider to assign Posix UIDs to users from the trusted domain. If e.g a range for a trusted domain is configured with the following values: base-id = 1200000 range-size = 200000 rid-base = 0 the RIDs 0 to 199999 are mapped to the Posix ID from 1200000 to 13999999. So RID 1000 <-> Posix ID 1201000 EXAMPLE: Add a new ID range for the local domain To create an ID range for the local domain it is not necessary to specify a domain SID. But since it is possible that a user and a group can have the same value as Posix ID a second RID interval is needed to handle conflicts. ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\ --secondary-rid-base=1000000 local_range The data from the ID ranges of the local domain are used by the IPA server internally to assign SIDs to IPA users and groups. The SID will then be stored in the user or group objects. If e.g. the ID range for the local domain is configured with the values from the example above then a new user with the UID 1200007 will get the RID 1007. If this RID is already used by a group the RID will be 1000007. This can only happen if a user or a group object was created with a fixed ID because the automatic assignment will not assign the same ID twice. Since there are only users and groups sharing the same ID namespace it is sufficient to have only one fallback range to handle conflicts. To find the Posix ID for a given RID from the local domain it has to be checked first if the RID falls in the primary or secondary RID range and the rid-base or the secondary-rid-base has to be subtracted, respectively, and the base-id has to be added to get the Posix ID. Typically the creation of ID ranges happens behind the scenes and this CLI must not be used at all. The ID range for the local domain will be created during installation or upgrade from an older version. The ID range for a trusted domain will be created together with the trust by 'ipa trust-add ...'. USE CASES: Add an ID range from a transitively trusted domain If the trusted domain (A) trusts another domain (B) as well and this trust is transitive 'ipa trust-add domain-A' will only create a range for domain A. The ID range for domain B must be added manually. Add an additional ID range for the local domain If the ID range of the local domain is exhausted, i.e. no new IDs can be assigned to Posix users or groups by the DNA plugin, a new range has to be created to allow new users and groups to be added. (Currently there is no connection between this range CLI and the DNA plugin, but a future version might be able to modify the configuration of the DNS plugin as well) In general it is not necessary to modify or delete ID ranges. If there is no other way to achieve a certain configuration than to modify or delete an ID range it should be done with great care. Because UIDs are stored in the file system and are used for access control it might be possible that users are allowed to access files of other users if an ID range got deleted and reused for a different domain. (*) The RID is typically the last integer of a user or group SID which follows the domain SID. E.g. if the domain SID is S-1-5-21-123-456-789 and a user from this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of the user. RIDs are unique in a domain, 32bit values and are used for users and groups. WARNING: DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands. Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range. """) class idrange(LDAPObject): """ Range object. """ range_type = ('domain', 'ad', 'ipa') container_dn = api.env.container_ranges object_name = ('range') object_name_plural = ('ranges') object_class = ['ipaIDrange'] possible_objectclasses = ['ipadomainidrange', 'ipatrustedaddomainrange'] default_attributes = ['cn', 'ipabaseid', 'ipaidrangesize', 'ipabaserid', 'ipasecondarybaserid', 'ipanttrusteddomainsid', 'iparangetype'] label = _('ID Ranges') label_singular = _('ID Range') range_types = { u'ipa-local': unicode(_('local domain range')), u'ipa-ad-winsync': unicode(_('Active Directory winsync range')), u'ipa-ad-trust': unicode(_('Active Directory domain range')), u'ipa-ad-trust-posix': unicode(_('Active Directory trust range with ' 'POSIX attributes')), u'ipa-ipa-trust': unicode(_('IPA trust range')), } takes_params = ( Str('cn', cli_name='name', label=_('Range name'), primary_key=True, ), Int('ipabaseid', cli_name='base_id', label=_("First Posix ID of the range"), ), Int('ipaidrangesize', cli_name='range_size', label=_("Number of IDs in the range"), ), Int('ipabaserid?', cli_name='rid_base', label=_('First RID of the corresponding RID range'), ), Int('ipasecondarybaserid?', cli_name='secondary_rid_base', label=_('First RID of the secondary RID range'), ), Str('ipanttrusteddomainsid?', cli_name='dom_sid', flags=('no_update',), label=_('Domain SID of the trusted domain'), ), Str('ipanttrusteddomainname?', cli_name='dom_name', flags=('no_search', 'virtual_attribute', 'no_update'), label=_('Name of the trusted domain'), ), StrEnum('iparangetype?', label=_('Range type'), cli_name='type', doc=(_('ID range type, one of {vals}' .format(vals=', '.join(range_types.keys())))), values=tuple(range_types.keys()), flags=['no_update'], ) ) def handle_iparangetype(self, entry_attrs, options, keep_objectclass=False): if not any((options.get('pkey_only', False), options.get('raw', False))): range_type = entry_attrs['iparangetype'][0] entry_attrs['iparangetype'] = [self.range_types.get(range_type, None)] # Remove the objectclass if not keep_objectclass: if not options.get('all', False) or options.get('pkey_only', False): entry_attrs.pop('objectclass', None) def check_ids_in_modified_range(self, old_base, old_size, new_base, new_size): if new_base is None and new_size is None: # nothing to check return if new_base is None: new_base = old_base if new_size is None: new_size = old_size old_interval = (old_base, old_base + old_size - 1) new_interval = (new_base, new_base + new_size - 1) checked_intervals = [] low_diff = new_interval[0] - old_interval[0] if low_diff > 0: checked_intervals.append((old_interval[0], min(old_interval[1], new_interval[0] - 1))) high_diff = old_interval[1] - new_interval[1] if high_diff > 0: checked_intervals.append((max(old_interval[0], new_interval[1] + 1), old_interval[1])) if not checked_intervals: # range is equal or covers the entire old range, nothing to check return ldap = self.backend id_filter_base = ["(objectclass=posixAccount)", "(objectclass=posixGroup)", "(objectclass=ipaIDObject)"] id_filter_ids = [] for id_low, id_high in checked_intervals: id_filter_ids.append("(&(uidNumber>=%(low)d)(uidNumber<=%(high)d))" % dict(low=id_low, high=id_high)) id_filter_ids.append("(&(gidNumber>=%(low)d)(gidNumber<=%(high)d))" % dict(low=id_low, high=id_high)) id_filter = ldap.combine_filters( [ldap.combine_filters(id_filter_base, "|"), ldap.combine_filters(id_filter_ids, "|")], "&") try: (objects, truncated) = ldap.find_entries(filter=id_filter, attrs_list=['uid', 'cn'], base_dn=DN(api.env.container_accounts, api.env.basedn)) except errors.NotFound: # no objects in this range found, allow the command pass else: raise errors.ValidationError(name="ipabaseid,ipaidrangesize", error=_('range modification leaving objects with ID out ' 'of the defined range is not allowed')) def get_domain_validator(self): if not _dcerpc_bindings_installed: raise errors.NotFound(reason=_('Cannot perform SID validation ' 'without Samba 4 support installed. Make sure you have ' 'installed server-trust-ad sub-package of IPA on the server')) domain_validator = ipaserver.dcerpc.DomainValidator(self.api) if not domain_validator.is_configured(): raise errors.NotFound(reason=_('Cross-realm trusts are not ' 'configured. Make sure you have run ipa-adtrust-install ' 'on the IPA server first')) return domain_validator def validate_trusted_domain_sid(self, sid): domain_validator = self.get_domain_validator() if not domain_validator.is_trusted_domain_sid_valid(sid): raise errors.ValidationError(name='domain SID', error=_('SID is not recognized as a valid SID for a ' 'trusted domain')) def get_trusted_domain_sid_from_name(self, name): """ Returns unicode string representation for given trusted domain name or None if SID forthe given trusted domain name could not be found.""" domain_validator = self.get_domain_validator() sid = domain_validator.get_sid_from_domain_name(name) if sid is not None: sid = unicode(sid) return sid # checks that primary and secondary rid ranges do not overlap def are_rid_ranges_overlapping(self, rid_base, secondary_rid_base, size): # if any of these is None, the check does not apply if any(attr is None for attr in (rid_base, secondary_rid_base, size)): return False # sort the bases if rid_base > secondary_rid_base: rid_base, secondary_rid_base = secondary_rid_base, rid_base # rid_base is now <= secondary_rid_base, # so the following check is sufficient if rid_base + size <= secondary_rid_base: return False else: return True class idrange_add(LDAPCreate): __doc__ = _(""" Add new ID range. To add a new ID range you always have to specify --base-id --range-size Additionally --rid-base --secondary-rid-base may be given for a new ID range for the local domain while --rid-base --dom-sid must be given to add a new range for a trusted AD domain. WARNING: DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands. Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range. """) msg_summary = _('Added ID range "%(value)s"') def interactive_prompt_callback(self, kw): """ Ensure that rid-base is prompted for when dom-sid is specified. Also ensure that secondary-rid-base is prompted for when rid-base is specified and vice versa, in case that dom-sid was not specified. Also ensure that rid-base and secondary-rid-base is prompted for if ipa-adtrust-install has been run on the system. """ # dom-sid can be specified using dom-sid or dom-name options # it can be also set using --setattr or --addattr, in these cases # we will not prompt, but raise an ValidationError later dom_sid_set = any(dom_id in kw for dom_id in ('ipanttrusteddomainname', 'ipanttrusteddomainsid')) rid_base = kw.get('ipabaserid', None) secondary_rid_base = kw.get('ipasecondarybaserid', None) def set_from_prompt(param): value = self.prompt_param(self.params[param]) update = {param: value} kw.update(update) if dom_sid_set: # This is a trusted range # Prompt for RID base if domain SID / name was given if rid_base is None: set_from_prompt('ipabaserid') else: # This is a local range # Find out whether ipa-adtrust-install has been ran adtrust_is_enabled = api.Command['adtrust_is_enabled']()['result'] if adtrust_is_enabled: # If ipa-adtrust-install has been ran, all local ranges # require both RID base and secondary RID base if rid_base is None: set_from_prompt('ipabaserid') if secondary_rid_base is None: set_from_prompt('ipasecondarybaserid') else: # This is a local range on a server with no adtrust support # Prompt for secondary RID base only if RID base was given if rid_base is not None and secondary_rid_base is None: set_from_prompt('ipasecondarybaserid') # Symetrically, prompt for RID base if secondary RID base was # given if rid_base is None and secondary_rid_base is not None: set_from_prompt('ipabaserid') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) is_set = lambda x: (x in entry_attrs) and (entry_attrs[x] is not None) # This needs to stay in options since there is no # ipanttrusteddomainname attribute in LDAP if 'ipanttrusteddomainname' in options: if is_set('ipanttrusteddomainsid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid and dom-name ' 'cannot be used together')) sid = self.obj.get_trusted_domain_sid_from_name( options['ipanttrusteddomainname']) if sid is not None: entry_attrs['ipanttrusteddomainsid'] = sid else: raise errors.ValidationError(name='ID Range setup', error=_('SID for the specified trusted domain name could ' 'not be found. Please specify the SID directly ' 'using dom-sid option.')) # ipaNTTrustedDomainSID attribute set, this is AD Trusted domain range if is_set('ipanttrusteddomainsid'): entry_attrs['objectclass'].append('ipatrustedaddomainrange') # Default to ipa-ad-trust if no type set if not is_set('iparangetype'): entry_attrs['iparangetype'] = u'ipa-ad-trust' if entry_attrs['iparangetype'] not in (u'ipa-ad-trust', u'ipa-ad-trust-posix'): raise errors.ValidationError(name='ID Range setup', error=_('IPA Range type must be one of ipa-ad-trust ' 'or ipa-ad-trust-posix when SID of the trusted ' 'domain is specified.')) if is_set('ipasecondarybaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid/dom-name and secondary-rid-base ' 'cannot be used together')) if not is_set('ipabaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid/dom-name and rid-base must ' 'be used together')) # Validate SID as the one of trusted domains self.obj.validate_trusted_domain_sid( entry_attrs['ipanttrusteddomainsid']) # ipaNTTrustedDomainSID attribute not set, this is local domain range else: entry_attrs['objectclass'].append('ipadomainidrange') # Default to ipa-local if no type set if 'iparangetype' not in entry_attrs: entry_attrs['iparangetype'] = 'ipa-local' # TODO: can also be ipa-ad-winsync here? if entry_attrs['iparangetype'] in (u'ipa-ad-trust', u'ipa-ad-trust-posix'): raise errors.ValidationError(name='ID Range setup', error=_('IPA Range type must not be one of ipa-ad-trust ' 'or ipa-ad-trust-posix when SID of the trusted ' 'domain is not specified.')) # secondary base rid must be set if and only if base rid is set if is_set('ipasecondarybaserid') != is_set('ipabaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options secondary-rid-base and rid-base must ' 'be used together')) # and they must not overlap if is_set('ipabaserid') and is_set('ipasecondarybaserid'): if self.obj.are_rid_ranges_overlapping( entry_attrs['ipabaserid'], entry_attrs['ipasecondarybaserid'], entry_attrs['ipaidrangesize']): raise errors.ValidationError(name='ID Range setup', error=_("Primary RID range and secondary RID range" " cannot overlap")) # rid-base and secondary-rid-base must be set if # ipa-adtrust-install has been run on the system adtrust_is_enabled = api.Command['adtrust_is_enabled']()['result'] if adtrust_is_enabled and not ( is_set('ipabaserid') and is_set('ipasecondarybaserid')): raise errors.ValidationError( name='ID Range setup', error=_( 'You must specify both rid-base and ' 'secondary-rid-base options, because ' 'ipa-adtrust-install has already been run.' ) ) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.handle_iparangetype(entry_attrs, options, keep_objectclass=True) return dn class idrange_del(LDAPDelete): __doc__ = _('Delete an ID range.') msg_summary = _('Deleted ID range "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): try: (old_dn, old_attrs) = ldap.get_entry(dn, ['ipabaseid', 'ipaidrangesize', 'ipanttrusteddomainsid']) except errors.NotFound: self.obj.handle_not_found(*keys) # Check whether we leave any object with id in deleted range old_base_id = int(old_attrs.get('ipabaseid', [0])[0]) old_range_size = int(old_attrs.get('ipaidrangesize', [0])[0]) self.obj.check_ids_in_modified_range( old_base_id, old_range_size, 0, 0) # Check whether the range does not belong to the active trust range_sid = old_attrs.get('ipanttrusteddomainsid') if range_sid is not None: range_sid = range_sid[0] result = api.Command['trust_find'](ipanttrusteddomainsid=range_sid) if result['count'] > 0: raise errors.DependentEntry( label='Active Trust', key=keys[0], dependent=result['result'][0]['cn'][0]) return dn class idrange_find(LDAPSearch): __doc__ = _('Search for ranges.') msg_summary = ngettext( '%(count)d range matched', '%(count)d ranges matched', 0 ) # 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): assert isinstance(base_dn, DN) 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 idrange_show(LDAPRetrieve): __doc__ = _('Display information about a range.') def pre_callback(self, ldap, dn, attrs_list, *keys, **options): assert isinstance(dn, DN) attrs_list.append('objectclass') return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.handle_iparangetype(entry_attrs, options) return dn class idrange_mod(LDAPUpdate): __doc__ = _('Modify ID range.') msg_summary = _('Modified ID range "%(value)s"') takes_options = LDAPUpdate.takes_options + ( DeprecatedParam('ipanttrusteddomainsid?'), DeprecatedParam('ipanttrusteddomainname?'), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) attrs_list.append('objectclass') try: (old_dn, old_attrs) = ldap.get_entry(dn, ['*']) except errors.NotFound: self.obj.handle_not_found(*keys) is_set = lambda x: (x in entry_attrs) and (entry_attrs[x] is not None) in_updated_attrs = lambda x:\ (x in entry_attrs and entry_attrs[x] is not None) or\ (x not in entry_attrs and x in old_attrs and old_attrs[x] is not None) # This needs to stay in options since there is no # ipanttrusteddomainname attribute in LDAP if 'ipanttrusteddomainname' in options: if is_set('ipanttrusteddomainsid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid and dom-name ' 'cannot be used together')) sid = self.obj.get_trusted_domain_sid_from_name( options['ipanttrusteddomainname']) # we translate the name into sid so further validation can rely # on ipanttrusteddomainsid attribute only if sid is not None: entry_attrs['ipanttrusteddomainsid'] = sid else: raise errors.ValidationError(name='ID Range setup', error=_('SID for the specified trusted domain name could ' 'not be found. Please specify the SID directly ' 'using dom-sid option.')) if in_updated_attrs('ipanttrusteddomainsid'): if in_updated_attrs('ipasecondarybaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid and secondary-rid-base cannot ' 'be used together')) if not in_updated_attrs('ipabaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options dom-sid and rid-base must ' 'be used together')) if is_set('ipanttrusteddomainsid'): # Validate SID as the one of trusted domains # perform this check only if the attribute was changed self.obj.validate_trusted_domain_sid( entry_attrs['ipanttrusteddomainsid']) # Add trusted AD domain range object class, if it wasn't there if not 'ipatrustedaddomainrange' in old_attrs['objectclass']: entry_attrs['objectclass'].append('ipatrustedaddomainrange') else: # secondary base rid must be set if and only if base rid is set if in_updated_attrs('ipasecondarybaserid') !=\ in_updated_attrs('ipabaserid'): raise errors.ValidationError(name='ID Range setup', error=_('Options secondary-rid-base and rid-base must ' 'be used together')) # ensure that primary and secondary rid ranges do not overlap if all(in_updated_attrs(base) for base in ('ipabaserid', 'ipasecondarybaserid')): # make sure we are working with updated attributes rid_range_attributes = ('ipabaserid', 'ipasecondarybaserid', 'ipaidrangesize') updated_values = dict() for attr in rid_range_attributes: if is_set(attr): updated_values[attr] = entry_attrs[attr] else: updated_values[attr] = int(old_attrs[attr][0]) if self.obj.are_rid_ranges_overlapping( updated_values['ipabaserid'], updated_values['ipasecondarybaserid'], updated_values['ipaidrangesize']): raise errors.ValidationError(name='ID Range setup', error=_("Primary RID range and secondary RID range" " cannot overlap")) # check whether ids are in modified range old_base_id = int(old_attrs.get('ipabaseid', [0])[0]) old_range_size = int(old_attrs.get('ipaidrangesize', [0])[0]) new_base_id = entry_attrs.get('ipabaseid') if new_base_id is not None: new_base_id = int(new_base_id) new_range_size = entry_attrs.get('ipaidrangesize') if new_range_size is not None: new_range_size = int(new_range_size) self.obj.check_ids_in_modified_range(old_base_id, old_range_size, new_base_id, new_range_size) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.handle_iparangetype(entry_attrs, options) return dn api.register(idrange) api.register(idrange_add) api.register(idrange_mod) api.register(idrange_del) api.register(idrange_find) api.register(idrange_show) freeipa-3.3.4/ipalib/plugins/cert.pyc0000664000175000017500000004652712271707517017124 0ustar mkosekmkosekó †fçRc @sÁddlmZmZejjek r:eddƒ‚nddlZddlZddlmZm Z m Z m Z m Z m Z ddlmZddlmZddlmZdd lmZdd lmZdd lTdd lmZddlZddlZdd lmZddlmZddlmZddlmZddljZddl m!Z!edƒZ"d„Z#d„Z$d„Z%d„Z&d„Z'd„Z(d„Z)d„Z*d„Z+de,fd„ƒYZ-ej.e-ƒde,fd„ƒYZ/ej.e/ƒe d e)d!ed"ƒd#ed$ƒd%e*ƒZ0d&e,fd'„ƒYZ1ej.e1ƒd(e,fd)„ƒYZ2ej.e2ƒd*e,fd+„ƒYZ3ej.e3ƒd,efd-„ƒYZ4ej.e4ƒdS(.iÿÿÿÿ(tapitSkipPluginModuletreasonsenv.enable_ra is not TrueN(tCommandtStrtInttBytestFlagtFile(terrors(tpkcs10(tx509(tutil(tngettext(t*(tsplit_principal(t_(tcontext(toutput(tvalidate_principal(t NSPRErrorsÒ IPA certificate operations Implements a set of commands for managing server SSL certificates. Certificate requests exist in the form of a Certificate Signing Request (CSR) in PEM format. The dogtag CA uses just the CN value of the CSR and forces the rest of the subject to values configured in the server. A certificate is stored with a service principal and a service principal needs a host. In order to request a certificate: * The host must exist * The service must exist (or you use the --add option to automatically add it) SEARCHING: Certificates may be searched on by certificate subject, serial number, revocation reason, validity dates and the issued date. When searching on dates the _from date does a >= search and the _to date does a <= search. When combined these are done as an AND. Dates are treated as GMT to match the dates in the certificates. The date format is YYYY-mm-dd. EXAMPLES: Request a new certificate and add the principal: ipa cert-request --add --principal=HTTP/lion.example.com example.csr Retrieve an existing certificate: ipa cert-show 1032 Revoke a certificate (see RFC 5280 for reason details): ipa cert-revoke --revocation-reason=6 1032 Remove a certificate from revocation hold status: ipa cert-remove-hold 1032 Check the status of a signing request: ipa cert-status 10 Search for certificates by hostname: ipa cert-find --subject=ipaserver.example.com Search for revoked certificates by reason: ipa cert-find --revocation-reason=5 Search for certificates based on issuance date ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07 IPA currently immediately issues (or declines) all certificate requests so the status of a request is not normally useful. This is for future use or the case where a CA does not immediately issue a certificate. The following revocation reasons are supported: * 0 - unspecified * 1 - keyCompromise * 2 - cACompromise * 3 - affiliationChanged * 4 - superseded * 5 - cessationOfOperation * 6 - certificateHold * 8 - removeFromCRL * 9 - privilegeWithdrawn * 10 - aACompromise Note that reason code 7 is not used. See RFC 5280 for more details: http://www.ietf.org/rfc/rfc5280.txt cCs7ytj|dƒ}Wntk r2}t|ƒSXdS(s* A date in the format of %Y-%m-%d s%Y-%m-%dN(ttimetstrptimet ValueErrortstrtNone(tugettexttvaluettste((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytvalidate_pkidate}s  cCs_y)tj|ƒ}tj|ƒ}|jSWn/tk rZ}tjdtdƒ|ƒ‚nXdS(sF Return the value of CN in the subject of the request or None terrors0Failure decoding Certificate Signing Request: %sN(R tload_certificate_requestt get_subjectt common_nameRR tCertificateOperationErrorR(tcsrtrequesttsubjecttnsprerr((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytget_csr_hostnameˆs  cCs‡yQtj|ƒ}x7|jD],}|jtjkrtj|jƒdSqWdSWn/t k r‚}t j dt dƒ|ƒ‚nXdS(s@ Return the first value of the subject alt name, if any iRs0Failure decoding Certificate Signing Request: %sN( R R t extensionstoid_tagtnsstSEC_OID_X509_SUBJECT_ALT_NAMEt x509_alt_nameRRRR R#R(R$R%t extensionR'((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytget_subjectaltname”s cCs¤tjjdkr1|r1tjj|ƒr1dSnytj|ƒ}WnYtk rq}t j dt |ƒƒ‚n/t k rŸ}t j dtdƒ|ƒ‚nXdS(sX Ensure the CSR is base64-encoded and can be decoded by our PKCS#10 parser. tcliNRRs0Failure decoding Certificate Signing Request: %s(RtenvRtostpathtexistsR R t TypeErrorR tBase64DecodeErrorRt ExceptionR#R(RR$R%R((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyt validate_csr¢scCs¥d}|jdƒ}|dkr3|jdƒ}n|jdƒ}|dkru|jdƒ}|dkrud}qun|dkr¡|dkr¡||||!}n|S(sI Strip any leading and trailing cruft around the BEGIN/END block i%s'-----BEGIN NEW CERTIFICATE REQUEST-----iÿÿÿÿs#-----BEGIN CERTIFICATE REQUEST-----s%-----END NEW CERTIFICATE REQUEST-----s!-----END CERTIFICATE REQUEST-----i!(tfind(R$tend_lentsR((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyt normalize_csr³s    cCsXyt|dƒ}Wn>tk rSyt|dƒ}WqTtk rOd}qTXnX|S(sk Convert a SN given in decimal or hexadecimal. Returns the number or None if conversion fails. iiN(tintRR(tnum((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyt_convert_serial_numberÇs  cCst|ƒdkrdSdS(Nu;Decimal or hexadecimal number is required for serial number(R?R(RR>((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytvalidate_serial_numberØscCstt|ƒƒS(N(tunicodeR?(R>((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytnormalize_serial_numberÝscCs[td|ƒ|jdƒ}|jdƒ}|dkrFt|ƒ}n||d|!}|S(sP Given a principal with or without a realm return the host portion. t@t/iÿÿÿÿiN(RRR9tlen(t principaltrealmtslashthostname((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pytget_host_from_principalás  t cert_requestc Bs‘eZedƒZedededƒdddeƒfZdZe dded ƒd ed ƒƒe d d dde ƒe dd edƒd e de ƒfZ e ddedƒƒe ddedƒƒe ddedƒƒe ddedƒƒe ddedƒƒe ddedƒƒe ddedƒƒe d ded!ƒƒe d"ded#ƒƒf Zejd$d%ed ed&ƒƒfZd'„ZRS((s%Submit a certificate signing request.R$tlabeltCSRtcli_nametcsr_filet normalizersrequest certificateRFt PrincipaltdocsCService principal for this certificate (e.g. HTTP/test.example.com)t request_typetdefaultupkcs10tautofilltadds3automatically add the principal if it doesn't existt certificatet CertificateR&tSubjecttissuertIssuertvalid_not_befores Not Beforetvalid_not_afters Not Aftertmd5_fingerprintsFingerprint (MD5)tsha1_fingerprintsFingerprint (SHA1)t serial_numbers Serial numbertserial_number_hexsSerial number (hex)tresultttypes)Dictionary mapping variable name to valuecKs“|jjj}|jdƒ}|jdƒ}|jdƒ}d}ttdƒ}|jdƒsm|jƒnt |ƒ} | s t j dddt dƒƒ‚nt |ƒ\} } } | jƒ| jƒkrût jd t d ƒtd | d | ƒƒ‚nd} d}yp|jdƒsCtjd |dtƒd}|d} n3t|ƒ} tjd| dtƒd}|d} Wn•t jk r}|s­t jdt dƒƒ‚ny/tjd|itd6d}|d} Wqt jk r t jd t dƒƒ‚qXnX|j| dƒs@t jd t dƒ| ƒ‚ntj|ƒ}tj|ƒ}|dk r@xÓ|D]È}t|ƒ}y+tjd|dtƒd}|d}Wn0t jk ràt jdt dƒ|ƒ‚nXttdƒ}|jdƒrq||jdgƒkr9t jd t dƒ|ƒ‚q9qqqqWnd|kr:tj|dddtjƒ}yhtjdt|ƒƒd}d|krÓy!tjd t|ƒdd!ƒWqÓt jk rÏqÓXnWnt jk rênX|jdƒstjd"|ddƒq:t|ƒ} tjd#| ddƒn|jjj|d|ƒ}tj |d$ƒ}t|j!ƒ|d%Serial number in decimal or if prefixed with 0x in hexadecimalRPRpc Bs"eZedƒZeZeddedƒƒeddedƒƒeddedƒƒedded ƒƒed ded ƒƒed ded ƒƒeddedƒƒeddedƒƒeddedƒƒf ZeddedƒdedƒddƒfZdZ d„Z d„Z RS(s!Retrieve an existing certificate.RWRLRXR&RYRZR[R\s Not BeforeR]s Not AfterR^sFingerprint (MD5)R_sFingerprint (SHA1)RqsRevocation reasonRasSerial number (hex)sout?sOutput filenameRRs!File to store the certificate in.texcludetwebuisretrieve certificatecKsjd}y|jƒWnVtjk rl}|jdƒttdƒ}|jdƒs]|‚nt|ƒ}nX|j j j |ƒ}t j |dƒ}t|jƒ|dNot granted by ACI to revoke certificate, looking at principalRpRbRqiRs"7 is not a valid revocation reason(RRzR R}R°RRRAR„R#RR~RuR…trevoke_certificate(RŽR`RRIR³RbRq((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyR›Js !   ( RœRRRžR¼RŸRR£R RRR¢R›(((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyRr2s      tcert_remove_holdcBsYeZedƒZeZeddedƒƒeddedƒƒfZdZ d„Z RS(s$Take a revoked certificate off hold.t unrevokedRLt Unrevokedt error_stringtErrorscertificate remove holdcKs&|jƒtd|jjj|ƒƒS(NRb(RzR~RuR…ttake_certificate_off_hold(RŽR`R((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyR›ps ( RœRRRžR¼RŸRRR£R R›(((s1/home/mkosek/freeipa-clean/ipalib/plugins/cert.pyRÃas    t cert_findcBs`eZedƒZeddedƒdedƒdeƒeddedƒdedƒd d d d deƒed dedƒded d ƒeddedƒded dƒeddedƒdeƒedededƒdeƒedededƒdeƒedededƒdeƒedededƒdeƒedededƒdeƒedededƒdeƒed eded!ƒdeƒed"eded#ƒdeƒed$ded%ƒded&ƒd'd(gd d d)d*ƒfZ e j Z ed+ded,ƒƒed-ded.ƒƒed/ded0ƒƒfZ ed1d2d ƒZd3„ZRS(4s!Search for existing certificates.ssubject?RLRYRRRUsrevocation_reason?R¿s*Reason for revoking the certificate (0-10)RÀiRÁi smin_serial_number?sminimum serial numbersmax_serial_number?smaximum serial numberiÿÿÿsexactly?smatch the common name exactlysvalidnotafter_from?s+Valid not after from this date (YYYY-mm-dd)svalidnotafter_to?s)Valid not after to this date (YYYY-mm-dd)svalidnotbefore_from?s,Valid not before from this date (YYYY-mm-dd)svalidnotbefore_to?s*Valid not before to this date (YYYY-mm-dd)sissuedon_from?s%Issued on from this date (YYYY-mm-dd)s issuedon_to?s#Issued on to this date (YYYY-mm-dd)srevokedon_from?s&Revoked on from this date (YYYY-mm-dd)s revokedon_to?s$Revoked on to this date (YYYY-mm-dd)s sizelimit?s Size Limits Maximum number of certs returnedR¨t no_displayRTidRasSerial number (hex)R`s Serial numbertstatustStatuss%(count)d certificate matcheds%(count)d certificates matchedcKs@td|jjj|ƒƒ}t|dƒ|ds`  .   N        Ç     U ,  `freeipa-3.3.4/ipalib/plugins/misc.pyc0000664000175000017500000000744212271707517017113 0ustar mkosekmkosekó ­8 Rc@sªddlZddlmZmZmZmZddlmZmZddlm Z edƒZ defd„ƒYZ ej e ƒdefd „ƒYZ ej e ƒdS( iÿÿÿÿN(tapit LocalOrRemotet_tngettext(tOutputtsummary(tFlags Misc plug-ins tenvc BsáeZedƒZedƒZdZejeddddedƒddd d gd e ƒfZe d d e dedƒƒe dd e dedƒd dgƒe dd e dedƒd dgƒe fZd„Zd„ZRS(sShow environment variables.s%(count)d variabless variables*talltcli_nametdocsJretrieve and print all attributes from the server. Affects command output.texcludetwebuitflagst no_outputtdefaulttresultttypes)Dictionary mapping variable name to valuettotals(Total number of variables env (>= count)t no_displaytcounts'Number of variables returned (<= total)cCsžtƒ}xŽ|D]†}d|krwtj|jddƒdƒ}xR|jD]%}|j|ƒrK|j|ƒqKqKWq||jkr|j|ƒqqW|S(Nt*s.*t$(tsettretcompiletreplaceRtmatchtadd(tselft variablestkeystquerytpattkey((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyt __find_keysHs   c s›|dkrˆj}nˆj|ƒ}tdt‡fd†|Dƒƒdt|ƒdtˆjƒƒ}t|ƒdkrˆj||d[sRRiR(tNoneRt_env__find_keystdicttlent msg_summary(RRtoptionsRtret((Rs1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pytexecuteTs    (s variables*(t__name__t __module__Rt__doc__R)t takes_argsRt takes_optionsRtTrueRR'tintRt has_outputR&R,(((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyR#s0                tpluginsc BsŸeZedƒZedddƒZejeddddedƒdd d d gd e ƒfZe d e dƒe dde dedƒƒe fZd„ZRS(sShow all loaded plugins.s%(count)d plugin loadeds%(count)d plugins loadediRR R sJretrieve and print all attributes from the server. Affects command output.R R R RRRs(Dictionary mapping plugin names to basesRRsNumber of plugins loadedcKsDt|jjdd„ƒ}tdtd„|Dƒƒdt|ƒƒS(NR"cSs|jS(N(tplugin(to((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyt„sRcss!|]}|j|jfVqdS(N(R6tbases(R$tp((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pys ‡sR(tsortedRR5R'R((RR*R5((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyR,ƒs (R-R.RR/RR)RR1RR2RR'R3RR4R,(((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyR5is         (RtipalibRRRRt ipalib.outputRRRR/RtregisterR5(((s1/home/mkosek/freeipa-clean/ipalib/plugins/misc.pyts " C #freeipa-3.3.4/ipalib/plugins/permission.pyc0000664000175000017500000004053612271707517020351 0ustar mkosekmkosekó †fçRc@sddlTddlmZmZmZddlmZmZmZddlm Z ddlm Z ddl m Z m Z edƒZdZed d ed ƒƒed d ed ƒƒfZd„Zdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒde fd„ƒYZ!eje!ƒde"fd „ƒYZ#eje#ƒd!S("iÿÿÿÿ(t*(tapit_tngettext(tFlagtStrtStrEnum(tcontext(terrors(tDNt EditableDNs˜ Permissions A permission enables fine-grained delegation of rights. A permission is a human-readable form of a 389-ds Access Control Rule, or instruction (ACI). A permission grants the right to perform a specific task such as adding a user, modifying a group, etc. A permission may not contain other permissions. * A permission grants access to read, write, add or delete. * A privilege combines similar permissions (for example all the permissions needed to add a user). * A role grants a set of privileges to users, groups, hosts or hostgroups. A permission is made up of a number of different parts: 1. The name of the permission. 2. The target of the permission. 3. The rights granted by the permission. Rights define what operations are allowed, and may be one or more of the following: 1. write - write one or more attributes 2. read - read one or more attributes 3. add - add a new entry to the tree 4. delete - delete an existing entry 5. all - all permissions are granted Read permission is granted for most attributes by default so the read permission is not expected to be used very often. Note the distinction between attributes and entries. The permissions are independent, so being able to add a user does not mean that the user will be editable. There are a number of allowed targets: 1. type: a type of object (user, group, etc). 2. memberof: a member of a group or hostgroup 3. filter: an LDAP filter 4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a super-set of the "type" target. 5. targetgroup: grant access to modify a specific group (such as granting the rights to manage group membership) EXAMPLES: Add a permission that grants the creation of users: ipa permission-add --type=user --permissions=add "Add Users" Add a permission that grants the ability to manage group membership: ipa permission-add --attrs=member --permissions=write --type=group "Manage Group Members" u permissiontipapermissiontypetlabelsPermission TypetacitACIcst‡fd†|DƒƒS(sÎReturn a dict that includes entries from `options` that are in `keys` example: >>> filtered = filter_options({'a': 1, 'b': 2, 'c': 3}, ['a', 'c']) >>> filtered == {'a': 1, 'c': 3} True c3s+|]!}|ˆkr|ˆ|fVqdS(N((t.0tk(toptions(s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pys ds(tdict(Rtkeys((Rs7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pytfilter_options\st permissioncBsAeZdZejjZedƒZedƒZ ddgZ ddddd gZ d d dd d ddddg Z idgd6dgd6Z eZedƒZedƒZeddddedƒdeddddƒeddddedƒded ƒd!eƒed"dd ded#ƒded$ƒd!ed%d&„d'd(ƒed)dd ded*ƒded+ƒd,dBd'd(ƒed4ddded5ƒded6ƒd'd(ƒed7ddded8ƒded9ƒd'd(ƒed:ddded;ƒded<ƒd'd(ƒed=ddded>ƒded?ƒd'd(ƒfZd@„ZdA„ZRS(Cs Permission object. Rt permissionst groupofnamest ipapermissiontcntmembertmemberoftmemberindirectR R tgrouptattrsttypetfiltertsubtreet targetgroupt privilegetrolet Permissionst Permissiontcli_nametnameR sPermission namet primary_keytpatterns^[-_ a-zA-Z0-9]+$tpattern_errmsgs2May only contain letters, numbers, -, _, and spaces permissions+tdocs4Permissions to grant (read, write, add, delete, all)tcsvsattrs*t Attributess*Attributes to which the permission appliest normalizercCs |jƒS(N(tlower(tvalue((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyt‘stflagst ask_createstype?tTypesIType of IPA object (user, group, host, hostgroup, service, netgroup, dns)tvaluesuuserugroupuhostuserviceu hostgroupunetgroupu dnsrecords memberof?sMember of groupsTarget members of a groupsfilter?tFilters'Legal LDAP filter (e.g. ou=Engineering)ssubtree?tSubtreesSubtree to apply permissions tos targetgroup?s Target groups"User group to apply permissions tocGsjy|j|dgƒ\}}Wn!tjk rB|j|ŒnXd|krfd|dkrftSntS(NR tSYSTEM(t get_entryRtNotFoundthandle_not_foundtFalsetTrue(tselftldaptdnRt entry_attrs((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyt check_system¶s cs t‡fd†|jƒDƒƒS(s:Return option dictionary that only includes ACI attributesc3s0|]&\}}|ˆjkr||fVqdS(N(taci_attributes(RRtv(R?(s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pys Âs (Rtitems(R?R((R?s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pytfilter_aci_attributesÀs(uuserugroupuhostuserviceu hostgroupunetgroupu dnsrecord(t__name__t __module__t__doc__Rtenvtcontainer_permissiont container_dnRt object_nametobject_name_pluralt object_classtdefault_attributesRDtattribute_membersR>trdn_is_primary_keyR tlabel_singularRRt takes_paramsRCRG(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRfsz                                    tpermission_addcBs?eZedƒZedƒZejeZd„Zd„Z RS(sAdd a new permission.sAdded permission "%(value)s"c Osœt|tƒst‚|jj|ƒ}t|d<|d|dt ACI_PREFIXRtCommandtaci_add( R?R@RARBt attrs_listRRtoptsto((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyt pre_callbackÎs    c Os[t|tƒst‚|jj|ƒ}t|d<|d|dt|tƒst‚|jdƒ}|r:|g|dtNO_CLIRt takes_optionsRtRvRc(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRqs        Rfc BsceZedƒZedƒZejeddedƒdddgded ƒƒfZd „ZRS( sDelete a permission.sDeleted permission "%(value)s"tforceR tForceR3t no_optiont no_outputR,s"force delete of SYSTEM permissionscOs•t|tƒst‚|jdƒ rY|jj|||Œ rYtjdtdƒƒ‚ny!|j j j |ddt ƒWntj k rnX|S(NR}tinfos&A SYSTEM permission may not be removediÿÿÿÿRX(RZR R[RyR\RCRtACIErrorRRR^RhR]R;(R?R@RARR((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRc0s) !( RHRIRRJRmt LDAPDeleteR|RRc(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRf#s     tpermission_modcBsHeZedƒZedƒZejeZd„Zd„Z d„Z RS(sModify a permission.sModified permission "%(value)s"c Ost|tƒst‚|jj|||ŒsHtjdtdƒƒ‚ny|j||ƒ\}}Wn$tj k rŠ|jj |ŒnXd|kr]|dr<yyt |ƒ}|ddWn)t t fk rë} td|ƒ‚nX|d|d_|j||ƒ\}}tjƒ‚WqZtj k r8qZXq]tjdddtd ƒƒ‚n|jj|ƒ} ttd tƒt| ƒdkrÖ|d | d RD( R?R@RARBR`RRRtnew_dnRjRaRb((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRcEsH       cOsJ|jdkr@t|tjƒr@ttdƒ}|r=dSq@n|‚dS(Nt update_entryR‡(t func_nameRZRt EmptyModlisttgetattrR(R?RRtexct call_funct call_argst call_kwargsR‡((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyt exc_callbackws  c Osçt|tƒst‚|d}d|kr~|jjj|dtd|dƒ|jjj|dtd|dƒ|d}nt|dddgƒ}|jjj ||d }x.|D]&} | j d ƒs¹|| || R R)R(t make_entryRŽtappend(R?R@tentriesRªtargsRR©R¦tentryRARR¢R Rit max_entriestconfigRat aciresultstresultstfoundRtpkt new_entry((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRl¡sf   $             ( RHRIRRJRRmt LDAPSearchRoRpRl(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyR¥™s   R cBs*eZedƒZejeZd„ZRS(s'Display information about a permission.c Ost|tƒst‚yst|ddgƒ}|jjj|ddt|d}x1|jj D]#}||kr`||||R{(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyR¿stpermission_remove_membercBseZdZeZRS(s+ Remove members from a permission. (RHRIRJR>R{(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyRÀ sN($tipalib.plugins.baseldaptipalibRRRRRRtipalib.requestRRt ipapython.dnR R RJR]RpRt LDAPObjectRtregisterRnRVRqRƒRfR¤R„R¼R¥R¾R t LDAPAddMemberR¿tLDAPRemoveMemberRÀ(((s7/home/mkosek/freeipa-clean/ipalib/plugins/permission.pyts> 4     _ 6   W O   freeipa-3.3.4/ipalib/plugins/batch.py0000664000175000017500000001100212271663206017055 0ustar mkosekmkosek# Authors: # Adam Young # Rob Crittenden # # Copyright (c) 2010 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 . """ Plugin to make multiple ipa calls via one remote procedure call To run this code in the lite-server curl -H "Content-Type:application/json" -H "Accept:application/json" -H "Accept-Language:en" --negotiate -u : --cacert /etc/ipa/ca.crt -d @batch_request.json -X POST http://localhost:8888/ipa/json where the contents of the file batch_request.json follow the below example {"method":"batch","params":[[ {"method":"group_find","params":[[],{}]}, {"method":"user_find","params":[[],{"whoami":"true","all":"true"}]}, {"method":"user_show","params":[["admin"],{"all":true}]} ],{}],"id":1} The format of the response is nested the same way. At the top you will see "error": null, "id": 1, "result": { "count": 3, "results": [ And then a nested response for each IPA command method sent in the request """ from ipalib import api, errors from ipalib import Command from ipalib.parameters import Str, Any from ipalib.output import Output from ipalib import output from ipalib.text import _ from ipalib.request import context from ipapython.version import API_VERSION class batch(Command): NO_CLI = True takes_args = ( Any('methods*', doc=_('Nested Methods to execute'), ), ) take_options = ( Str('version', cli_name='version', doc=_('Client version. Used to determine if server will accept request.'), exclude='webui', flags=['no_option', 'no_output'], default=API_VERSION, autofill=True, ), ) has_output = ( Output('count', int, doc=''), Output('results', (list, tuple), doc='') ) def execute(self, *args, **options): results = [] for arg in args[0]: params = dict() name = None try: if 'method' not in arg: raise errors.RequirementError(name='method') if 'params' not in arg: raise errors.RequirementError(name='params') name = arg['method'] if name not in self.Command: raise errors.CommandError(name=name) a, kw = arg['params'] newkw = dict((str(k), v) for k, v in kw.iteritems()) params = api.Command[name].args_options_2_params(*a, **newkw) newkw.setdefault('version', options['version']) result = api.Command[name](*a, **newkw) self.info( '%s: batch: %s(%s): SUCCESS', context.principal, name, ', '.join(api.Command[name]._repr_iter(**params)) ) result['error']=None except Exception, e: if isinstance(e, errors.RequirementError) or \ isinstance(e, errors.CommandError): self.info( '%s: batch: %s', context.principal, e.__class__.__name__ ) else: 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) api.register(batch) freeipa-3.3.4/ipalib/plugins/virtual.py0000664000175000017500000000447212202434255017471 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2009 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 . """ Base classes for non-LDAP backend plugins. """ from ipalib import api from ipalib import Command from ipalib import errors from ipapython.dn import DN from ipalib.text import _ class VirtualCommand(Command): """ A command that doesn't use the LDAP backend but wants to use the LDAP access control system to make authorization decisions. The class variable operation is the commonName attribute of the entry to be tested against. In advance, you need to create an entry of the form: cn=, api.env.container_virtual, api.env.basedn Ex. cn=request certificate, cn=virtual operations,cn=etc, dc=example, dc=com """ operation = None def check_access(self, operation=None): """ Perform an LDAP query to determine authorization. This should be executed before any actual work is done. """ if self.operation is None and operation is None: raise errors.ACIError(info=_('operation not defined')) if operation is None: operation = self.operation ldap = self.api.Backend.ldap2 self.log.debug("IPA: virtual verify %s" % operation) operationdn = DN(('cn', operation), self.api.env.container_virtual, self.api.env.basedn) try: if not ldap.can_write(operationdn, "objectclass"): raise errors.ACIError( info=_('not allowed to perform this command')) except errors.NotFound: raise errors.ACIError(info=_('No such virtual command')) return True freeipa-3.3.4/ipalib/plugins/misc.py0000664000175000017500000000767412202434255016745 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . import re from ipalib import api, LocalOrRemote, _, ngettext from ipalib.output import Output, summary from ipalib import Flag __doc__ = _(""" Misc plug-ins """) # FIXME: We should not let env return anything in_server # when mode == 'production'. This would allow an attacker to see the # configuration of the server, potentially revealing compromising # information. However, it's damn handy for testing/debugging. class env(LocalOrRemote): __doc__ = _('Show environment variables.') msg_summary = _('%(count)d variables') takes_args = ( 'variables*', ) takes_options = LocalOrRemote.takes_options + ( Flag('all', cli_name='all', doc=_('retrieve and print all attributes from the server. Affects command output.'), exclude='webui', flags=['no_output'], default=True, ), ) has_output = ( Output('result', type=dict, doc=_('Dictionary mapping variable name to value'), ), Output('total', type=int, doc=_('Total number of variables env (>= count)'), flags=['no_display'], ), Output('count', type=int, doc=_('Number of variables returned (<= total)'), flags=['no_display'], ), summary, ) def __find_keys(self, variables): keys = set() for query in variables: if '*' in query: pat = re.compile(query.replace('*', '.*') + '$') for key in self.env: if pat.match(key): keys.add(key) elif query in self.env: keys.add(query) return keys def execute(self, variables, **options): if variables is None: keys = self.env else: keys = self.__find_keys(variables) ret = dict( result=dict( (key, self.env[key]) for key in keys ), count=len(keys), total=len(self.env), ) if len(keys) > 1: ret['summary'] = self.msg_summary % ret else: ret['summary'] = None return ret api.register(env) class plugins(LocalOrRemote): __doc__ = _('Show all loaded plugins.') msg_summary = ngettext( '%(count)d plugin loaded', '%(count)d plugins loaded', 0 ) takes_options = LocalOrRemote.takes_options + ( Flag('all', cli_name='all', doc=_('retrieve and print all attributes from the server. Affects command output.'), exclude='webui', flags=['no_output'], default=True, ), ) has_output = ( Output('result', dict, 'Dictionary mapping plugin names to bases'), Output('count', type=int, doc=_('Number of plugins loaded'), ), summary, ) def execute(self, **options): plugins = sorted(self.api.plugins, key=lambda o: o.plugin) return dict( result=dict( (p.plugin, p.bases) for p in plugins ), count=len(plugins), ) api.register(plugins) freeipa-3.3.4/ipalib/plugins/pwpolicy.py0000664000175000017500000004337412271663206017663 0ustar mkosekmkosek# Authors: # Pavel Zuna # Martin Kosek # # Copyright (C) 2010 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 . from ipalib import api from ipalib import Int, Str, DNParam from ipalib.plugins.baseldap import * from ipalib import _ from ipalib.request import context from ipapython.ipautil import run from ipapython.dn import DN from distutils import version __doc__ = _(""" Password policy A password policy sets limitations on IPA passwords, including maximum lifetime, minimum lifetime, the number of passwords to save in history, the number of character classes required (for stronger passwords) and the minimum password length. By default there is a single, global policy for all users. You can also create a password policy to apply to a group. Each user is only subject to one password policy, either the group policy or the global policy. A group policy stands alone; it is not a super-set of the global policy plus custom settings. Each group password policy requires a unique priority setting. If a user is in multiple groups that have password policies, this priority determines which password policy is applied. A lower value indicates a higher priority policy. Group password policies are automatically removed when the groups they are associated with are removed. EXAMPLES: Modify the global policy: ipa pwpolicy-mod --minlength=10 Add a new group password policy: ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --minlength=8 --priority=10 localadmins Display the global password policy: ipa pwpolicy-show Display a group password policy: ipa pwpolicy-show localadmins Display the policy that would be applied to a given user: ipa pwpolicy-show --user=tuser1 Modify a group password policy: ipa pwpolicy-mod --minclasses=2 localadmins """) class cosentry(LDAPObject): """ Class of Service object used for linking policies with groups """ NO_CLI = True container_dn = DN(('cn', 'costemplates'), api.env.container_accounts) object_class = ['top', 'costemplate', 'extensibleobject', 'krbcontainer'] default_attributes = ['cn', 'cospriority', 'krbpwdpolicyreference'] takes_params = ( Str('cn', primary_key=True), DNParam('krbpwdpolicyreference'), Int('cospriority', minvalue=0), ) priority_not_unique_msg = _( 'priority must be a unique value (%(prio)d already used by %(gname)s)' ) def get_dn(self, *keys, **options): group_dn = self.api.Object.group.get_dn(keys[-1]) return self.backend.make_dn_from_attr( 'cn', group_dn, DN(self.container_dn, api.env.basedn) ) def check_priority_uniqueness(self, *keys, **options): if options.get('cospriority') is not None: entries = self.methods.find( cospriority=options['cospriority'] )['result'] if len(entries) > 0: group_name = self.api.Object.group.get_primary_key_from_dn( DN(entries[0]['cn'][0])) raise errors.ValidationError( name='priority', error=self.priority_not_unique_msg % { 'prio': options['cospriority'], 'gname': group_name, } ) api.register(cosentry) class cosentry_add(LDAPCreate): NO_CLI = True def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # check for existence of the group group_dn = self.api.Object.group.get_dn(keys[-1]) result = ldap.get_entry(group_dn, ['objectclass']) oc = map(lambda x:x.lower(),result['objectclass']) if 'mepmanagedentry' in oc: raise errors.ManagedPolicyError() self.obj.check_priority_uniqueness(*keys, **options) del entry_attrs['cn'] return dn api.register(cosentry_add) class cosentry_del(LDAPDelete): NO_CLI = True api.register(cosentry_del) class cosentry_mod(LDAPUpdate): NO_CLI = True def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) new_cospriority = options.get('cospriority') if new_cospriority is not None: cos_entry = self.api.Command.cosentry_show(keys[-1])['result'] old_cospriority = int(cos_entry['cospriority'][0]) # check uniqueness only when the new priority differs if old_cospriority != new_cospriority: self.obj.check_priority_uniqueness(*keys, **options) return dn api.register(cosentry_mod) class cosentry_show(LDAPRetrieve): NO_CLI = True api.register(cosentry_show) class cosentry_find(LDAPSearch): NO_CLI = True api.register(cosentry_find) global_policy_name = 'global_policy' global_policy_dn = DN(('cn', global_policy_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn) class pwpolicy(LDAPObject): """ Password Policy object """ container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos')) object_name = _('password policy') object_name_plural = _('password policies') object_class = ['top', 'nscontainer', 'krbpwdpolicy'] default_attributes = [ 'cn', 'cospriority', 'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdhistorylength', 'krbpwdmindiffchars', 'krbpwdminlength', 'krbpwdmaxfailure', 'krbpwdfailurecountinterval', 'krbpwdlockoutduration', ] MIN_KRB5KDC_WITH_LOCKOUT = "1.8" has_lockout = False lockout_params = () (stdout, stderr, rc) = run(['klist', '-V'], raiseonerr=False) if rc == 0: verstr = stdout.split()[-1] ver = version.LooseVersion(verstr) min = version.LooseVersion(MIN_KRB5KDC_WITH_LOCKOUT) if ver >= min: has_lockout = True if has_lockout: lockout_params = ( Int('krbpwdmaxfailure?', cli_name='maxfail', label=_('Max failures'), doc=_('Consecutive failures before lockout'), minvalue=0, ), Int('krbpwdfailurecountinterval?', cli_name='failinterval', label=_('Failure reset interval'), doc=_('Period after which failure count will be reset (seconds)'), minvalue=0, ), Int('krbpwdlockoutduration?', cli_name='lockouttime', label=_('Lockout duration'), doc=_('Period for which lockout is enforced (seconds)'), minvalue=0, ), ) label = _('Password Policies') label_singular = _('Password Policy') takes_params = ( Str('cn?', cli_name='group', label=_('Group'), doc=_('Manage password policy for specific group'), primary_key=True, ), Int('krbmaxpwdlife?', cli_name='maxlife', label=_('Max lifetime (days)'), doc=_('Maximum password lifetime (in days)'), minvalue=0, maxvalue=20000, # a little over 54 years ), Int('krbminpwdlife?', cli_name='minlife', label=_('Min lifetime (hours)'), doc=_('Minimum password lifetime (in hours)'), minvalue=0, ), Int('krbpwdhistorylength?', cli_name='history', label=_('History size'), doc=_('Password history size'), minvalue=0, ), Int('krbpwdmindiffchars?', cli_name='minclasses', label=_('Character classes'), doc=_('Minimum number of character classes'), minvalue=0, maxvalue=5, ), Int('krbpwdminlength?', cli_name='minlength', label=_('Min length'), doc=_('Minimum length of password'), minvalue=0, ), Int('cospriority', cli_name='priority', label=_('Priority'), doc=_('Priority of the policy (higher number means lower priority'), minvalue=0, flags=('virtual_attribute',), ), ) + lockout_params def get_dn(self, *keys, **options): if keys[-1] is not None: return self.backend.make_dn_from_attr( self.primary_key.name, keys[-1], DN(self.container_dn, api.env.basedn) ) return global_policy_dn def convert_time_for_output(self, entry_attrs, **options): # Convert seconds to hours and days for displaying to user if not options.get('raw', False): if 'krbmaxpwdlife' in entry_attrs: entry_attrs['krbmaxpwdlife'][0] = unicode( int(entry_attrs['krbmaxpwdlife'][0]) / 86400 ) if 'krbminpwdlife' in entry_attrs: entry_attrs['krbminpwdlife'][0] = unicode( int(entry_attrs['krbminpwdlife'][0]) / 3600 ) def convert_time_on_input(self, entry_attrs): # Convert hours and days to seconds for writing to LDAP if 'krbmaxpwdlife' in entry_attrs and entry_attrs['krbmaxpwdlife']: entry_attrs['krbmaxpwdlife'] = entry_attrs['krbmaxpwdlife'] * 86400 if 'krbminpwdlife' in entry_attrs and entry_attrs['krbminpwdlife']: entry_attrs['krbminpwdlife'] = entry_attrs['krbminpwdlife'] * 3600 def validate_lifetime(self, entry_attrs, add=False, *keys): """ Ensure that the maximum lifetime is greater than the minimum. If there is no minimum lifetime set then don't return an error. """ maxlife=entry_attrs.get('krbmaxpwdlife', None) minlife=entry_attrs.get('krbminpwdlife', None) existing_entry = {} if not add: # then read existing entry existing_entry = self.api.Command.pwpolicy_show(keys[-1], all=True, )['result'] if minlife is None and 'krbminpwdlife' in existing_entry: minlife = int(existing_entry['krbminpwdlife'][0]) * 3600 if maxlife is None and 'krbmaxpwdlife' in existing_entry: maxlife = int(existing_entry['krbmaxpwdlife'][0]) * 86400 if maxlife is not None and minlife is not None: if minlife > maxlife: raise errors.ValidationError( name='maxlife', error=_('Maximum password life must be greater than minimum.'), ) def add_cospriority(self, entry, pwpolicy_name, rights=True): if pwpolicy_name and pwpolicy_name != global_policy_name: cos_entry = self.api.Command.cosentry_show( pwpolicy_name, rights=rights, all=rights )['result'] if cos_entry.get('cospriority') is not None: entry['cospriority'] = cos_entry['cospriority'] if rights: entry['attributelevelrights']['cospriority'] = \ cos_entry['attributelevelrights']['cospriority'] api.register(pwpolicy) class pwpolicy_add(LDAPCreate): __doc__ = _('Add a new group password policy.') def get_args(self): yield self.obj.primary_key.clone(attribute=True, required=True) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.convert_time_on_input(entry_attrs) self.obj.validate_lifetime(entry_attrs, True) self.api.Command.cosentry_add( keys[-1], krbpwdpolicyreference=dn, cospriority=options.get('cospriority') ) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.log.info('%r' % entry_attrs) # attribute rights are not allowed for pwpolicy_add self.obj.add_cospriority(entry_attrs, keys[-1], rights=False) self.obj.convert_time_for_output(entry_attrs, **options) return dn api.register(pwpolicy_add) class pwpolicy_del(LDAPDelete): __doc__ = _('Delete a group password policy.') def get_args(self): yield self.obj.primary_key.clone( attribute=True, required=True, multivalue=True ) def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) if dn == global_policy_dn: raise errors.ValidationError( name='group', error=_('cannot delete global password policy') ) return dn def post_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) try: self.api.Command.cosentry_del(keys[-1]) except errors.NotFound: pass return True api.register(pwpolicy_del) class pwpolicy_mod(LDAPUpdate): __doc__ = _('Modify a group password policy.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.convert_time_on_input(entry_attrs) self.obj.validate_lifetime(entry_attrs, False, *keys) setattr(context, 'cosupdate', False) if options.get('cospriority') is not None: if keys[-1] is None: raise errors.ValidationError( name='priority', error=_('priority cannot be set on global policy') ) try: self.api.Command.cosentry_mod( keys[-1], cospriority=options['cospriority'] ) except errors.EmptyModlist, e: if len(entry_attrs) == 1: # cospriority only was passed raise e else: setattr(context, 'cosupdate', True) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) rights = options.get('all', False) and options.get('rights', False) self.obj.add_cospriority(entry_attrs, keys[-1], rights) self.obj.convert_time_for_output(entry_attrs, **options) return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): if call_func.func_name == 'update_entry': if isinstance(exc, errors.EmptyModlist): entry_attrs = call_args[1] cosupdate = getattr(context, 'cosupdate') if not entry_attrs or cosupdate: return raise exc api.register(pwpolicy_mod) class pwpolicy_show(LDAPRetrieve): __doc__ = _('Display information about password policy.') takes_options = LDAPRetrieve.takes_options + ( Str('user?', label=_('User'), doc=_('Display effective policy for a specific user'), ), ) def pre_callback(self, ldap, dn, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('user') is not None: user_entry = self.api.Command.user_show( options['user'], all=True )['result'] if 'krbpwdpolicyreference' in user_entry: return user_entry.get('krbpwdpolicyreference', [dn])[0] return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) rights = options.get('all', False) and options.get('rights', False) self.obj.add_cospriority(entry_attrs, keys[-1], rights) self.obj.convert_time_for_output(entry_attrs, **options) return dn api.register(pwpolicy_show) class pwpolicy_find(LDAPSearch): __doc__ = _('Search for group password policies.') # this command does custom sorting in post_callback sort_result_entries = False def priority_sort_key(self, entry): """Key for sorting password policies returns a pair: (is_global, priority) """ # global policy will be always last in the output if entry[1]['cn'][0] == global_policy_name: return True, 0 else: # policies with higher priority (lower number) will be at the # beginning of the list try: cospriority = int(entry[1]['cospriority'][0]) except KeyError: # if cospriority is not present in the entry, rather return 0 # than crash cospriority = 0 return False, cospriority def post_callback(self, ldap, entries, truncated, *args, **options): for e in entries: # When pkey_only flag is on, entries should contain only a cn. # Add a cospriority attribute that will be used for sorting. # Attribute rights are not allowed for pwpolicy_find. self.obj.add_cospriority(e[1], e[1]['cn'][0], rights=False) self.obj.convert_time_for_output(e[1], **options) # do custom entry sorting by its cospriority entries.sort(key=self.priority_sort_key) if options.get('pkey_only', False): # remove cospriority that was used for sorting for e in entries: try: del e[1]['cospriority'] except KeyError: pass return truncated api.register(pwpolicy_find) freeipa-3.3.4/ipalib/plugins/xmlclient.py0000664000175000017500000000174712270466515020015 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # Rob Crittenden # # 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 . """ XML-RPC client plugin. """ from ipalib import api if 'in_server' in api.env and api.env.in_server is False: from ipalib.rpc import xmlclient api.register(xmlclient) freeipa-3.3.4/ipalib/plugins/automember.py0000664000175000017500000004675612271663206020164 0ustar mkosekmkosek# Authors: # Jr Aquino # # Copyright (C) 2011 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 . from ipalib import api, errors from ipalib import Str, StrEnum from ipalib.plugins.baseldap import * from ipalib import _, ngettext from ipalib.request import context import ldap as _ldap from ipapython.dn import DN __doc__ = _(""" Auto Membership Rule. Bring clarity to the membership of hosts and users by configuring inclusive or exclusive regex patterns, you can automatically assign a new entries into a group or hostgroup based upon attribute information. A rule is directly associated with a group by name, so you cannot create a rule without an accompanying group or hostgroup. A condition is a regular expression used by 389-ds to match a new incoming entry with an automember rule. If it matches an inclusive rule then the entry is added to the appropriate group or hostgroup. A default group or hostgroup could be specified for entries that do not match any rule. In case of user entries this group will be a fallback group because all users are by default members of group specified in IPA config. EXAMPLES: Add the initial group or hostgroup: ipa hostgroup-add --desc="Web Servers" webservers ipa group-add --desc="Developers" devel Add the initial rule: ipa automember-add --type=hostgroup webservers ipa automember-add --type=group devel Add a condition to the rule: ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers ipa automember-add-condition --key=manager --type=group --inclusive-regex=^uid=mscott devel Add an exclusive condition to the rule to prevent auto assignment: ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-regex=^web5\.example\.com webservers Add a host: ipa host-add web1.example.com Add a user: ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott Verify automembership: ipa hostgroup-show webservers Host-group: webservers Description: Web Servers Member hosts: web1.example.com ipa group-show devel Group name: devel Description: Developers GID: 1004200000 Member users: tuser Remove a condition from the rule: ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers Modify the automember rule: ipa automember-mod Set the default (fallback) target group: ipa automember-default-group-set --default-group=webservers --type=hostgroup ipa automember-default-group-set --default-group=ipausers --type=group Remove the default (fallback) target group: ipa automember-default-group-remove --type=hostgroup ipa automember-default-group-remove --type=group Show the default (fallback) target group: ipa automember-default-group-show --type=hostgroup ipa automember-default-group-show --type=group Find all of the automember rules: ipa automember-find Display a automember rule: ipa automember-show --type=hostgroup webservers ipa automember-show --type=group devel Delete an automember rule: ipa automember-del --type=hostgroup webservers ipa automember-del --type=group devel """) # Options used by Condition Add and Remove. INCLUDE_RE = 'automemberinclusiveregex' EXCLUDE_RE = 'automemberexclusiveregex' regex_attrs = ( Str('automemberinclusiveregex*', cli_name='inclusive_regex', label=_('Inclusive Regex'), doc=_('Inclusive Regex'), csv=True, alwaysask=True, ), Str('automemberexclusiveregex*', cli_name='exclusive_regex', label=_('Exclusive Regex'), doc=_('Exclusive Regex'), csv=True, alwaysask=True, ), Str('key', label=_('Attribute Key'), doc=_('Attribute to filter via regex. For example fqdn for a host, or manager for a user'), flags=['no_create', 'no_update', 'no_search'] ), ) group_type = ( StrEnum('type', label=_('Grouping Type'), doc=_('Grouping to which the rule applies'), values=(u'group', u'hostgroup', ), ), ) automember_rule = ( Str('cn', cli_name='automember_rule', label=_('Automember Rule'), doc=_('Automember Rule'), normalizer=lambda value: value.lower(), ), ) class automember(LDAPObject): """ Bring automember to a hostgroup with an Auto Membership Rule. """ container_dn = api.env.container_automember object_name = 'auto_member_rule' object_name_plural = 'auto_member_rules' object_class = ['top', 'automemberregexrule'] default_attributes = [ 'automemberinclusiveregex', 'automemberexclusiveregex', 'cn', 'automembertargetgroup', 'description', 'automemberdefaultgroup' ] label = _('Auto Membership Rule') takes_params = ( Str('description?', cli_name='desc', label=_('Description'), doc=_('A description of this auto member rule'), ), Str('automemberdefaultgroup?', cli_name='default_group', label=_('Default (fallback) Group'), doc=_('Default group for entries to land'), flags=['no_create', 'no_update', 'no_search'] ), ) def dn_exists(self, grouptype, groupname, *keys): ldap = self.api.Backend.ldap2 dn = self.api.Object[grouptype].get_dn(groupname) try: (gdn, entry_attrs) = ldap.get_entry(dn, []) except errors.NotFound: raise errors.NotFound(reason=_(u'Group: %s not found!') % groupname) return gdn def get_dn(self, *keys, **options): if self.parent_object: parent_dn = self.api.Object[self.parent_object].get_dn(*keys[:-1]) else: parent_dn = DN(self.container_dn, api.env.basedn) grouptype = options['type'] try: ndn = DN(('cn', keys[-1]), ('cn', grouptype), parent_dn) except IndexError: ndn = DN(('cn', grouptype), parent_dn) return ndn def check_attr(self, attr): """ Verify that the user supplied key is a valid attribute in the schema """ ldap = self.api.Backend.ldap2 obj = ldap.schema.get_obj(_ldap.schema.AttributeType, attr) if obj is not None: return obj else: raise errors.NotFound(reason=_('%s is not a valid attribute.') % attr) api.register(automember) def automember_container_exists(ldap): try: ldap.get_entry(DN(api.env.container_automember, api.env.basedn), []) except errors.NotFound: return False return True class automember_add(LDAPCreate): __doc__ = _(""" Add an automember rule. """) takes_options = LDAPCreate.takes_options + group_type takes_args = automember_rule msg_summary = _('Added automember rule "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) entry_attrs['cn'] = keys[-1] if not automember_container_exists(self.api.Backend.ldap2): raise errors.NotFound(reason=_('Auto Membership is not configured')) entry_attrs['automembertargetgroup'] = self.obj.dn_exists(options['type'], keys[-1]) return dn def execute(self, *keys, **options): result = super(automember_add, self).execute(*keys, **options) result['value'] = keys[-1] return result api.register(automember_add) class automember_add_condition(LDAPUpdate): __doc__ = _(""" Add conditions to an automember rule. """) has_output_params = ( Str('failed', label=_('Failed to add'), flags=['suppress_empty'], ), ) takes_options = regex_attrs + group_type takes_args = automember_rule msg_summary = _('Added condition(s) to "%(value)s"') # Prepare the output to expect failed results has_output = ( output.summary, output.Entry('result'), output.value, output.Output('failed', type=dict, doc=_('Conditions that could not be added'), ), output.Output('completed', type=int, doc=_('Number of conditions added'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Check to see if the automember rule exists try: (tdn, test_attrs) = ldap.get_entry(dn, []) except errors.NotFound: raise errors.NotFound(reason=_(u'Auto member rule: %s not found!') % keys[0]) # Define container key key = options['key'] # Check to see if the attribute is valid self.obj.check_attr(key) key = '%s=' % key completed = 0 failed = {'failed': {}} for attr in (INCLUDE_RE, EXCLUDE_RE): failed['failed'][attr] = [] if attr in options and options[attr]: entry_attrs[attr] = [key + condition for condition in options[attr]] completed += len(entry_attrs[attr]) try: (dn, old_entry) = ldap.get_entry(dn, [attr]) for regex in old_entry.keys(): if not isinstance(entry_attrs[regex], (list, tuple)): entry_attrs[regex] = [entry_attrs[regex]] duplicate = set(old_entry[regex]) & set(entry_attrs[regex]) if len(duplicate) > 0: completed -= 1 else: entry_attrs[regex] = list(entry_attrs[regex]) + old_entry[regex] except errors.NotFound: failed['failed'][attr].append(regex) entry_attrs = entry_to_dict(entry_attrs, **options) # Set failed and completed to they can be harvested in the execute super setattr(context, 'failed', failed) setattr(context, 'completed', completed) setattr(context, 'entry_attrs', entry_attrs) # Make sure to returned the failed results if there is nothing to remove if completed == 0: (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) raise errors.EmptyModlist return dn def execute(self, *keys, **options): __doc__ = _(""" Override this so we can add completed and failed to the return result. """) try: result = super(automember_add_condition, self).execute(*keys, **options) except errors.EmptyModlist: result = {'result': getattr(context, 'entry_attrs'), 'value': keys[-1]} result['failed'] = getattr(context, 'failed') result['completed'] = getattr(context, 'completed') result['value'] = keys[-1] return result api.register(automember_add_condition) class automember_remove_condition(LDAPUpdate): __doc__ = _(""" Remove conditions from an automember rule. """) takes_options = regex_attrs + group_type takes_args = automember_rule msg_summary = _('Removed condition(s) from "%(value)s"') # Prepare the output to expect failed results has_output = ( output.summary, output.Entry('result'), output.value, output.Output('failed', type=dict, doc=_('Conditions that could not be removed'), ), output.Output('completed', type=int, doc=_('Number of conditions removed'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Check to see if the automember rule exists try: (tdn, test_attrs) = ldap.get_entry(dn, []) except errors.NotFound: raise errors.NotFound(reason=_(u'Auto member rule: %s not found!') % keys[0]) # Define container key type_attr_default = {'group': 'manager', 'hostgroup': 'fqdn'} if 'key' in options: key = options['key'] else: key = type_attr_default[options['type']] key = '%s=' % key completed = 0 failed = {'failed': {}} # Check to see if there are existing exclusive conditions present. (dn, exclude_present) = ldap.get_entry(dn, [EXCLUDE_RE]) for attr in (INCLUDE_RE, EXCLUDE_RE): failed['failed'][attr] = [] if attr in options and options[attr]: entry_attrs[attr] = [key + condition for condition in options[attr]] (dn, entry_attrs_) = ldap.get_entry(dn, [attr]) old_entry = entry_attrs_.get(attr, []) for regex in entry_attrs[attr]: if regex in old_entry: old_entry.remove(regex) completed += 1 else: failed['failed'][attr].append(regex) entry_attrs[attr] = old_entry entry_attrs = entry_to_dict(entry_attrs, **options) # Set failed and completed to they can be harvested in the execute super setattr(context, 'failed', failed) setattr(context, 'completed', completed) setattr(context, 'entry_attrs', entry_attrs) # Make sure to returned the failed results if there is nothing to remove if completed == 0: (dn, entry_attrs) = ldap.get_entry(dn, attrs_list) raise errors.EmptyModlist return dn def execute(self, *keys, **options): __doc__ = _(""" Override this so we can set completed and failed. """) try: result = super(automember_remove_condition, self).execute(*keys, **options) except errors.EmptyModlist: result = {'result': getattr(context, 'entry_attrs'), 'value': keys[-1]} result['failed'] = getattr(context, 'failed') result['completed'] = getattr(context, 'completed') result['value'] = keys[-1] return result api.register(automember_remove_condition) class automember_mod(LDAPUpdate): __doc__ = _(""" Modify an automember rule. """) takes_args = automember_rule takes_options = LDAPUpdate.takes_options + group_type msg_summary = _('Modified automember rule "%(value)s"') def execute(self, *keys, **options): result = super(automember_mod, self).execute(*keys, **options) result['value'] = keys[-1] return result api.register(automember_mod) class automember_del(LDAPDelete): __doc__ = _(""" Delete an automember rule. """) takes_args = automember_rule takes_options = group_type msg_summary = _('Deleted automember rule "%(value)s"') def execute(self, *keys, **options): result = super(automember_del, self).execute(*keys, **options) result['value'] = keys[-1] return result api.register(automember_del) class automember_find(LDAPSearch): __doc__ = _(""" Search for automember rules. """) takes_options = group_type has_output_params = LDAPSearch.has_output_params + automember_rule + regex_attrs msg_summary = ngettext( '%(count)d rules matched', '%(count)d rules matched', 0 ) def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) scope = ldap.SCOPE_SUBTREE ndn = DN(('cn', options['type']), base_dn) return (filters, ndn, scope) api.register(automember_find) class automember_show(LDAPRetrieve): __doc__ = _(""" Display information about an automember rule. """) takes_args = automember_rule takes_options = group_type has_output_params = LDAPRetrieve.has_output_params + regex_attrs def execute(self, *keys, **options): result = super(automember_show, self).execute(*keys, **options) result['value'] = keys[-1] return result api.register(automember_show) class automember_default_group_set(LDAPUpdate): __doc__ = _(""" Set default (fallback) group for all unmatched entries. """) takes_options = ( Str('automemberdefaultgroup', cli_name='default_group', label=_('Default (fallback) Group'), doc=_('Default (fallback) group for entries to land'), flags=['no_create', 'no_update'] ), ) + group_type msg_summary = _('Set default (fallback) group for automember "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): dn = DN(('cn', options['type']), api.env.container_automember, api.env.basedn) entry_attrs['automemberdefaultgroup'] = self.obj.dn_exists(options['type'], options['automemberdefaultgroup']) return dn def execute(self, *keys, **options): result = super(automember_default_group_set, self).execute(*keys, **options) result['value'] = options['type'] return result api.register(automember_default_group_set) class automember_default_group_remove(LDAPUpdate): __doc__ = _(""" Remove default (fallback) group for all unmatched entries. """) takes_options = group_type msg_summary = _('Removed default (fallback) group for automember "%(value)s"') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): dn = DN(('cn', options['type']), api.env.container_automember, api.env.basedn) attr = 'automemberdefaultgroup' (dn, entry_attrs_) = ldap.get_entry(dn, [attr]) if attr not in entry_attrs_: raise errors.NotFound(reason=_(u'No default (fallback) group set')) else: entry_attrs[attr] = [] return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if 'automemberdefaultgroup' not in entry_attrs: entry_attrs['automemberdefaultgroup'] = unicode(_('No default (fallback) group set')) return dn def execute(self, *keys, **options): result = super(automember_default_group_remove, self).execute(*keys, **options) result['value'] = options['type'] return result api.register(automember_default_group_remove) class automember_default_group_show(LDAPRetrieve): __doc__ = _(""" Display information about the default (fallback) automember groups. """) takes_options = group_type def pre_callback(self, ldap, dn, attrs_list, *keys, **options): dn = DN(('cn', options['type']), api.env.container_automember, api.env.basedn) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if 'automemberdefaultgroup' not in entry_attrs: entry_attrs['automemberdefaultgroup'] = unicode(_('No default (fallback) group set')) return dn def execute(self, *keys, **options): result = super(automember_default_group_show, self).execute(*keys, **options) result['value'] = options['type'] return result api.register(automember_default_group_show) freeipa-3.3.4/ipalib/plugins/batch.pyc0000664000175000017500000000751012271707517017235 0ustar mkosekmkosekó †fçRc@s¹dZddlmZmZddlmZddlmZmZddlm Z ddlm Z ddl m Z ddl mZdd lmZd efd „ƒYZejeƒd S( s Plugin to make multiple ipa calls via one remote procedure call To run this code in the lite-server curl -H "Content-Type:application/json" -H "Accept:application/json" -H "Accept-Language:en" --negotiate -u : --cacert /etc/ipa/ca.crt -d @batch_request.json -X POST http://localhost:8888/ipa/json where the contents of the file batch_request.json follow the below example {"method":"batch","params":[[ {"method":"group_find","params":[[],{}]}, {"method":"user_find","params":[[],{"whoami":"true","all":"true"}]}, {"method":"user_show","params":[["admin"],{"all":true}]} ],{}],"id":1} The format of the response is nested the same way. At the top you will see "error": null, "id": 1, "result": { "count": 3, "results": [ And then a nested response for each IPA command method sent in the request iÿÿÿÿ(tapiterrors(tCommand(tStrtAny(tOutput(toutput(t_(tcontext(t API_VERSIONtbatchcBs¡eZeZeddedƒƒfZeddddedƒdddd d gd ed eƒfZ e d e ddƒe de e fddƒfZd„ZRS(smethods*tdocsNested Methods to executetversiontcli_names@Client version. Used to determine if server will accept request.texcludetwebuitflagst no_optiont no_outputtdefaulttautofilltcountttresultsc OsZg}x8|dD],}tƒ}d}yd|krJtjddƒ‚nd|krktjddƒ‚n|d}||jkr™tjd|ƒ‚n|d\}}td„|jƒDƒƒ} tj|j|| Ž}| j d|dƒtj||| Ž} |j dt j |dj tj|j|ƒƒd| d `sR s%s: batch: %s(%s): SUCCESSs, terrors %s: batch: %ss%s: batch: %s(%s): %st error_codet error_nameRR(tdicttNoneRtRequirementErrorRt CommandErrort iteritemsRtargs_options_2_paramst setdefaulttinfoRt principaltjoint _repr_itert Exceptiont isinstancet __class__t__name__t PublicErrort InternalErrortstrerrorterrnotunicodettypetappendtlen( tselftargstoptionsRtargRRtatkwtnewkwtresulttetreported_error((s2/home/mkosek/freeipa-clean/ipalib/plugins/batch.pytexecuteRsH    ,5    (R0t __module__tTruetNO_CLIRRt takes_argsRR t take_optionsRtinttlistttuplet has_outputRC(((s2/home/mkosek/freeipa-clean/ipalib/plugins/batch.pyR 9s     N(t__doc__tipalibRRRtipalib.parametersRRt ipalib.outputRRt ipalib.textRtipalib.requestRtipapython.versionR R tregister(((s2/home/mkosek/freeipa-clean/ipalib/plugins/batch.pyt.sFfreeipa-3.3.4/ipalib/plugins/user.py0000664000175000017500000010072312271663206016763 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # Pavel Zuna # # 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 . from time import gmtime, strftime import string import posixpath import os from ipalib import api, errors from ipalib import Flag, Int, Password, Str, Bool from ipalib.plugins.baseldap import * from ipalib.plugins import baseldap from ipalib.request import context from ipalib import _, ngettext from ipalib import output from ipapython.ipautil import ipa_generate_password from ipapython.ipavalidate import Email from ipalib.capabilities import client_has_capability from ipalib.util import (normalize_sshpubkey, validate_sshpubkey, convert_sshpubkey_post) if api.env.in_server and api.env.context in ['lite', 'server']: from ipaserver.plugins.ldap2 import ldap2 __doc__ = _(""" Users Manage user entries. All users are POSIX users. IPA supports a wide range of username formats, but you need to be aware of any restrictions that may apply to your particular environment. For example, usernames that start with a digit or usernames that exceed a certain length may cause problems for some UNIX systems. Use 'ipa config-mod' to change the username format allowed by IPA tools. Disabling a user account prevents that user from obtaining new Kerberos credentials. It does not invalidate any credentials that have already been issued. Password management is not a part of this module. For more information about this topic please see: ipa help passwd Account lockout on password failure happens per IPA master. The user-status command can be used to identify which master the user is locked out on. It is on that master the administrator must unlock the user. EXAMPLES: Add a new user: ipa user-add --first=Tim --last=User --password tuser1 Find all users whose entries include the string "Tim": ipa user-find Tim Find all users with "Tim" as the first name: ipa user-find --first=Tim Disable a user account: ipa user-disable tuser1 Enable a user account: ipa user-enable tuser1 Delete a user: ipa user-del tuser1 """) NO_UPG_MAGIC = '__no_upg__' user_output_params = ( Flag('has_keytab', label=_('Kerberos keys available'), ), Str('sshpubkeyfp*', label=_('SSH public key fingerprint'), ), ) status_output_params = ( Str('server', label=_('Server'), ), Str('krbloginfailedcount', label=_('Failed logins'), ), Str('krblastsuccessfulauth', label=_('Last successful authentication'), ), Str('krblastfailedauth', label=_('Last failed authentication'), ), Str('now', label=_('Time now'), ), ) # characters to be used for generating random user passwords user_pwdchars = string.digits + string.ascii_letters + '_,.@+-=' def validate_nsaccountlock(entry_attrs): if 'nsaccountlock' in entry_attrs: nsaccountlock = entry_attrs['nsaccountlock'] if not isinstance(nsaccountlock, (bool, Bool)): if not isinstance(nsaccountlock, basestring): raise errors.OnlyOneValueAllowed(attr='nsaccountlock') if nsaccountlock.lower() not in ('true', 'false'): raise errors.ValidationError(name='nsaccountlock', error=_('must be TRUE or FALSE')) def convert_nsaccountlock(entry_attrs): if not 'nsaccountlock' in entry_attrs: entry_attrs['nsaccountlock'] = False else: nsaccountlock = Bool('temp') entry_attrs['nsaccountlock'] = nsaccountlock.convert(entry_attrs['nsaccountlock'][0]) def split_principal(principal): """ Split the principal into its components and do some basic validation. Automatically append our realm if it wasn't provided. """ realm = None parts = principal.split('@') user = parts[0].lower() if len(parts) > 2: raise errors.MalformedUserPrincipal(principal=principal) if len(parts) == 2: realm = parts[1].upper() # At some point we'll support multiple realms if realm != api.env.realm: raise errors.RealmMismatch() else: realm = api.env.realm return (user, realm) def validate_principal(ugettext, principal): """ All the real work is done in split_principal. """ (user, realm) = split_principal(principal) return None def normalize_principal(principal): """ Ensure that the name in the principal is lower-case. The realm is upper-case by convention but it isn't required. The principal is validated at this point. """ (user, realm) = split_principal(principal) return unicode('%s@%s' % (user, realm)) def check_protected_member(user, protected_group_name=u'admins'): ''' Ensure the last enabled member of a protected group cannot be deleted or disabled by raising LastMemberError. ''' # Get all users in the protected group result = api.Command.user_find(in_group=protected_group_name) # Build list of users in the protected group who are enabled result = result['result'] enabled_users = [entry['uid'][0] for entry in result if not entry['nsaccountlock']] # If the user is the last enabled user raise LastMemberError exception if enabled_users == [user]: raise errors.LastMemberError(key=user, label=_(u'group'), container=protected_group_name) class user(LDAPObject): """ User object. """ container_dn = api.env.container_user object_name = _('user') object_name_plural = _('users') object_class = ['posixaccount'] object_class_config = 'ipauserobjectclasses' possible_objectclasses = ['meporiginentry'] disallow_object_classes = ['krbticketpolicyaux'] search_attributes_config = 'ipausersearchfields' default_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', 'uidnumber', 'gidnumber', 'mail', 'ou', 'telephonenumber', 'title', 'memberof', 'nsaccountlock', 'memberofindirect', ] search_display_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', 'mail', 'telephonenumber', 'title', 'nsaccountlock', 'uidnumber', 'gidnumber', 'sshpubkeyfp', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], } rdn_is_primary_key = True bindable = True password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] label = _('Users') label_singular = _('User') takes_params = ( Str('uid', pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', maxlength=255, cli_name='login', label=_('User login'), primary_key=True, default_from=lambda givenname, sn: givenname[0] + sn, normalizer=lambda value: value.lower(), ), Str('givenname', cli_name='first', label=_('First name'), ), Str('sn', cli_name='last', label=_('Last name'), ), Str('cn', label=_('Full name'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('displayname?', label=_('Display name'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('initials?', label=_('Initials'), default_from=lambda givenname, sn: '%c%c' % (givenname[0], sn[0]), autofill=True, ), Str('homedirectory?', cli_name='homedir', label=_('Home directory'), ), Str('gecos?', label=_('GECOS'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('loginshell?', cli_name='shell', label=_('Login shell'), ), Str('krbprincipalname?', validate_principal, cli_name='principal', label=_('Kerberos principal'), default_from=lambda uid: '%s@%s' % (uid.lower(), api.env.realm), autofill=True, flags=['no_update'], normalizer=lambda value: normalize_principal(value), ), Str('mail*', cli_name='email', label=_('Email address'), ), Password('userpassword?', cli_name='password', label=_('Password'), doc=_('Prompt to set the user password'), # FIXME: This is temporary till bug is fixed causing updates to # bomb out via the webUI. exclude='webui', ), Flag('random?', doc=_('Generate a random user password'), flags=('no_search', 'virtual_attribute'), default=False, ), Str('randompassword?', label=_('Random password'), flags=('no_create', 'no_update', 'no_search', 'virtual_attribute'), ), Int('uidnumber?', cli_name='uid', label=_('UID'), doc=_('User ID Number (system will assign one if not provided)'), minvalue=1, ), Int('gidnumber?', label=_('GID'), doc=_('Group ID Number'), minvalue=1, ), Str('street?', cli_name='street', label=_('Street address'), ), Str('l?', cli_name='city', label=_('City'), ), Str('st?', cli_name='state', label=_('State/Province'), ), Str('postalcode?', label=_('ZIP'), ), Str('telephonenumber*', cli_name='phone', label=_('Telephone Number') ), Str('mobile*', label=_('Mobile Telephone Number') ), Str('pager*', label=_('Pager Number') ), Str('facsimiletelephonenumber*', cli_name='fax', label=_('Fax Number'), ), Str('ou?', cli_name='orgunit', label=_('Org. Unit'), ), Str('title?', label=_('Job Title'), ), Str('manager?', label=_('Manager'), ), Str('carlicense?', label=_('Car License'), ), Bool('nsaccountlock?', label=_('Account disabled'), flags=['no_option'], ), Str('ipasshpubkey*', validate_sshpubkey, cli_name='sshpubkey', label=_('SSH public key'), normalizer=normalize_sshpubkey, csv=True, flags=['no_search'], ), ) def _normalize_and_validate_email(self, email, config=None): if not config: config = self.backend.get_ipa_config()[1] # check if default email domain should be added defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if email: norm_email = [] if not isinstance(email, (list, tuple)): email = [email] for m in email: if isinstance(m, basestring): if '@' not in m and defaultdomain: m = m + u'@' + defaultdomain if not Email(m): raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m)) norm_email.append(m) else: if not Email(m): raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m)) norm_email.append(m) return norm_email return email def _normalize_manager(self, manager): """ Given a userid verify the user's existence and return the dn. """ if not manager: return None if not isinstance(manager, list): manager = [manager] try: container_dn = DN(self.container_dn, api.env.basedn) for m in xrange(len(manager)): if isinstance(manager[m], DN) and manager[m].endswith(container_dn): continue (dn, entry_attrs) = self.backend.find_entry_by_attr( self.primary_key.name, manager[m], self.object_class, [''], container_dn ) manager[m] = dn except errors.NotFound: raise errors.NotFound(reason=_('manager %(manager)s not found') % dict(manager=manager[m])) return manager def _convert_manager(self, entry_attrs, **options): """ Convert a manager dn into a userid """ if options.get('raw', False): return if 'manager' in entry_attrs: for m in xrange(len(entry_attrs['manager'])): entry_attrs['manager'][m] = self.get_primary_key_from_dn(entry_attrs['manager'][m]) api.register(user) class user_add(LDAPCreate): __doc__ = _('Add a new user.') msg_summary = _('Added user "%(value)s"') has_output_params = LDAPCreate.has_output_params + user_output_params takes_options = LDAPCreate.takes_options + ( Flag('noprivate', cli_name='noprivate', doc=_('Don\'t create user private group'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if not options.get('noprivate', False): try: # The Managed Entries plugin will allow a user to be created # even if a group has a duplicate name. This would leave a user # without a private group. Check for both the group and the user. self.api.Object['group'].get_dn_if_exists(keys[-1]) try: self.api.Command['user_show'](keys[-1]) self.obj.handle_duplicate_entry(*keys) except errors.NotFound: raise errors.ManagedGroupExistsError(group=keys[-1]) except errors.NotFound: pass else: # we don't want an user private group to be created for this user # add NO_UPG_MAGIC description attribute to let the DS plugin know entry_attrs.setdefault('description', []) entry_attrs['description'].append(NO_UPG_MAGIC) entry_attrs.setdefault('uidnumber', baseldap.DNA_MAGIC) if not client_has_capability( options['version'], 'optional_uid_params'): # https://fedorahosted.org/freeipa/ticket/2886 # Old clients say 999 (OLD_DNA_MAGIC) when they really mean # "assign a value dynamically". OLD_DNA_MAGIC = 999 if entry_attrs.get('uidnumber') == OLD_DNA_MAGIC: entry_attrs['uidnumber'] = baseldap.DNA_MAGIC if entry_attrs.get('gidnumber') == OLD_DNA_MAGIC: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC validate_nsaccountlock(entry_attrs) config = ldap.get_ipa_config()[1] if 'ipamaxusernamelength' in config: if len(keys[-1]) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) default_shell = config.get('ipadefaultloginshell', ['/bin/sh'])[0] entry_attrs.setdefault('loginshell', default_shell) # hack so we can request separate first and last name in CLI full_name = '%s %s' % (entry_attrs['givenname'], entry_attrs['sn']) entry_attrs.setdefault('cn', full_name) if 'homedirectory' not in entry_attrs: # get home's root directory from config homes_root = config.get('ipahomesrootdir', ['/home'])[0] # build user's home directory based on his uid entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1]) entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm)) if entry_attrs.get('gidnumber') is None: # gidNumber wasn't specified explicity, find out what it should be if not options.get('noprivate', False) and ldap.has_upg(): # User Private Groups - uidNumber == gidNumber entry_attrs['gidnumber'] = entry_attrs['uidnumber'] else: # we're adding new users to a default group, get its gidNumber # get default group name from config def_primary_group = config.get('ipadefaultprimarygroup') group_dn = self.api.Object['group'].get_dn(def_primary_group) try: (group_dn, group_attrs) = ldap.get_entry(group_dn, ['gidnumber']) except errors.NotFound: error_msg = _('Default group for new users not found') raise errors.NotFound(reason=error_msg) if 'gidnumber' not in group_attrs: error_msg = _('Default group for new users is not POSIX') raise errors.NotFound(reason=error_msg) entry_attrs['gidnumber'] = group_attrs['gidnumber'] if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj._normalize_and_validate_email(entry_attrs['mail'], config) else: # No e-mail passed in. If we have a default e-mail domain set # then we'll add it automatically. defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if defaultdomain: entry_attrs['mail'] = self.obj._normalize_and_validate_email(keys[-1], config) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager']) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) config = ldap.get_ipa_config()[1] # add the user we just created into the default primary group def_primary_group = config.get('ipadefaultprimarygroup') group_dn = self.api.Object['group'].get_dn(def_primary_group) # if the user is already a member of default primary group, # do not raise error # this can happen if automember rule or default group is set try: ldap.add_entry_to_group(dn, group_dn) except errors.AlreadyGroupMember: pass self.obj._convert_manager(entry_attrs, **options) # delete description attribute NO_UPG_MAGIC if present if options.get('noprivate', False): if not options.get('all', False): (dn, desc_attr) = ldap.get_entry(dn, ['description']) entry_attrs.update(desc_attr) if 'description' in entry_attrs and NO_UPG_MAGIC in entry_attrs['description']: entry_attrs['description'].remove(NO_UPG_MAGIC) kw = {'setattr': unicode('description=%s' % ','.join(entry_attrs['description']))} try: self.api.Command['user_mod'](keys[-1], **kw) except (errors.EmptyModlist, errors.NotFound): pass # Fetch the entry again to update memberof, mep data, etc updated # at the end of the transaction. (newdn, newentry) = ldap.get_entry(dn, ['*']) entry_attrs.update(newentry) if options.get('random', False): try: entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) except AttributeError: # if both randompassword and userpassword options were used pass self.obj.get_password_attributes(ldap, dn, entry_attrs) convert_sshpubkey_post(ldap, dn, entry_attrs) return dn api.register(user_add) class user_del(LDAPDelete): __doc__ = _('Delete a user.') msg_summary = _('Deleted user "%(value)s"') def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) check_protected_member(keys[-1]) return dn api.register(user_del) class user_mod(LDAPUpdate): __doc__ = _('Modify a user.') msg_summary = _('Modified user "%(value)s"') has_output_params = LDAPUpdate.has_output_params + user_output_params def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('rename') is not None: config = ldap.get_ipa_config()[1] if 'ipamaxusernamelength' in config: if len(options['rename']) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict( len = int(config.get('ipamaxusernamelength')[0]) ) ) if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj._normalize_and_validate_email(entry_attrs['mail']) if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj._normalize_manager(entry_attrs['manager']) validate_nsaccountlock(entry_attrs) if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(user_pwdchars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) if 'ipasshpubkey' in entry_attrs: if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: (_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass']) obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass'] if 'ipasshuser' not in obj_classes: obj_classes.append('ipasshuser') return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if options.get('random', False): try: entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) except AttributeError: # if both randompassword and userpassword options were used pass convert_nsaccountlock(entry_attrs) self.obj._convert_manager(entry_attrs, **options) self.obj.get_password_attributes(ldap, dn, entry_attrs) convert_sshpubkey_post(ldap, dn, entry_attrs) return dn api.register(user_mod) class user_find(LDAPSearch): __doc__ = _('Search for users.') member_attributes = ['memberof'] has_output_params = LDAPSearch.has_output_params + user_output_params takes_options = LDAPSearch.takes_options + ( Flag('whoami', label=_('Self'), doc=_('Display user record for current Kerberos principal'), ), ) def execute(self, *args, **options): # assure the manager attr is a dn, not just a bare uid manager = options.get('manager') if manager is not None: options['manager'] = self.obj._normalize_manager(manager) return super(user_find, self).execute(self, *args, **options) def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options): assert isinstance(base_dn, DN) if options.get('whoami'): return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\ getattr(context, 'principal'), base_dn, scope) return (filter, base_dn, scope) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, attrs) = entry self.obj._convert_manager(attrs, **options) self.obj.get_password_attributes(ldap, dn, attrs) convert_nsaccountlock(attrs) convert_sshpubkey_post(ldap, dn, attrs) return truncated msg_summary = ngettext( '%(count)d user matched', '%(count)d users matched', 0 ) api.register(user_find) class user_show(LDAPRetrieve): __doc__ = _('Display information about a user.') has_output_params = LDAPRetrieve.has_output_params + user_output_params def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) convert_nsaccountlock(entry_attrs) self.obj._convert_manager(entry_attrs, **options) self.obj.get_password_attributes(ldap, dn, entry_attrs) convert_sshpubkey_post(ldap, dn, entry_attrs) return dn api.register(user_show) class user_disable(LDAPQuery): __doc__ = _('Disable a user account.') has_output = output.standard_value msg_summary = _('Disabled user account "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend check_protected_member(keys[-1]) dn = self.obj.get_dn(*keys, **options) ldap.deactivate_entry(dn) return dict( result=True, value=keys[0], ) api.register(user_disable) class user_enable(LDAPQuery): __doc__ = _('Enable a user account.') has_output = output.standard_value has_output_params = LDAPQuery.has_output_params + user_output_params msg_summary = _('Enabled user account "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) ldap.activate_entry(dn) return dict( result=True, value=keys[0], ) api.register(user_enable) class user_unlock(LDAPQuery): __doc__ = _(""" Unlock a user account An account may become locked if the password is entered incorrectly too many times within a specific time period as controlled by password policy. A locked account is a temporary condition and may be unlocked by an administrator.""") has_output = output.standard_value msg_summary = _('Unlocked account "%(value)s"') def execute(self, *keys, **options): dn = self.obj.get_dn(*keys, **options) entry_attrs = {'krbLastAdminUnlock': strftime("%Y%m%d%H%M%SZ",gmtime()), 'krbLoginFailedCount': '0'} self.obj.backend.update_entry(dn, entry_attrs) return dict( result=True, value=keys[0], ) api.register(user_unlock) class user_status(LDAPQuery): __doc__ = _(""" Lockout status of a user account An account may become locked if the password is entered incorrectly too many times within a specific time period as controlled by password policy. A locked account is a temporary condition and may be unlocked by an administrator. This connects to each IPA master and displays the lockout status on each one. To determine whether an account is locked on a given server you need to compare the number of failed logins and the time of the last failure. For an account to be locked it must exceed the maxfail failures within the failinterval duration as specified in the password policy associated with the user. The failed login counter is modified only when a user attempts a log in so it is possible that an account may appear locked but the last failed login attempt is older than the lockouttime of the password policy. This means that the user may attempt a login again. """) has_output = output.standard_list_of_entries has_output_params = LDAPSearch.has_output_params + status_output_params def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) attr_list = ['krbloginfailedcount', 'krblastsuccessfulauth', 'krblastfailedauth', 'nsaccountlock'] disabled = False masters = [] # Get list of masters try: (masters, truncated) = ldap.find_entries( None, ['*'], DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn), ldap.SCOPE_ONELEVEL ) except errors.NotFound: # If this happens we have some pretty serious problems self.error('No IPA masters found!') pass entries = [] count = 0 for master in masters: host = master[1]['cn'][0] if host == api.env.host: other_ldap = self.obj.backend else: other_ldap = ldap2(shared_instance=False, ldap_uri='ldap://%s' % host, base_dn=self.api.env.basedn) try: other_ldap.connect(ccache=os.environ['KRB5CCNAME']) except Exception, e: self.error("user_status: Connecting to %s failed with %s" % (host, str(e))) newresult = ldap.make_entry(dn) newresult['server'] = _("%(host)s failed: %(error)s") % dict(host=host, error=str(e)) entries.append(newresult) count += 1 continue try: entry = other_ldap.get_entry(dn, attr_list) newresult = ldap.make_entry(dn) for attr in ['krblastsuccessfulauth', 'krblastfailedauth']: newresult[attr] = entry[1].get(attr, [u'N/A']) newresult['krbloginfailedcount'] = entry[1].get('krbloginfailedcount', u'0') if not options.get('raw', False): for attr in ['krblastsuccessfulauth', 'krblastfailedauth']: try: if newresult[attr][0] == u'N/A': continue newtime = time.strptime(newresult[attr][0], '%Y%m%d%H%M%SZ') newresult[attr][0] = unicode(time.strftime('%Y-%m-%dT%H:%M:%SZ', newtime)) except Exception, e: self.debug("time conversion failed with %s" % str(e)) pass newresult['server'] = host if options.get('raw', False): time_format = '%Y%m%d%H%M%SZ' else: time_format = '%Y-%m-%dT%H:%M:%SZ' newresult['now'] = unicode(strftime(time_format, gmtime())) convert_nsaccountlock(entry[1]) if 'nsaccountlock' in entry[1].keys(): disabled = entry[1]['nsaccountlock'] entries.append(newresult) count += 1 except errors.NotFound: self.obj.handle_not_found(*keys) except Exception, e: self.error("user_status: Retrieving status for %s failed with %s" % (dn, str(e))) newresult = ldap.make_entry(dn) newresult['server'] = _("%(host)s failed") % dict(host=host) entries.append(newresult) count += 1 if host != api.env.host: other_ldap.destroy_connection() return dict(result=entries, count=count, truncated=False, summary=unicode(_('Account disabled: %(disabled)s' % dict(disabled=disabled))), ) api.register(user_status) freeipa-3.3.4/ipalib/plugins/dns.py0000664000175000017500000031435312271663206016577 0ustar mkosekmkosek# Authors: # Martin Kosek # Pavel Zuna # # Copyright (C) 2010 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 . from __future__ import absolute_import import netaddr import time import re import dns.name from ipalib.request import context from ipalib import api, errors, output from ipalib import Command from ipalib.parameters import (Flag, Bool, Int, Decimal, Str, StrEnum, Any, DeprecatedParam) from ipalib.plugins.baseldap import * from ipalib import _, ngettext from ipalib.util import (validate_zonemgr, normalize_zonemgr, normalize_zone, validate_hostname, validate_dns_label, validate_domain_name, get_dns_forward_zone_update_policy, get_dns_reverse_zone_update_policy, get_reverse_zone_default, zone_is_reverse, REVERSE_DNS_ZONES) from ipapython.ipautil import valid_ip, CheckedIPAddress, is_host_resolvable __doc__ = _(""" Domain Name System (DNS) Manage DNS zone and resource records. USING STRUCTURED PER-TYPE OPTIONS There are many structured DNS RR types where DNS data stored in LDAP server is not just a scalar value, for example an IP address or a domain name, but a data structure which may be often complex. A good example is a LOC record [RFC1876] which consists of many mandatory and optional parts (degrees, minutes, seconds of latitude and longitude, altitude or precision). It may be difficult to manipulate such DNS records without making a mistake and entering an invalid value. DNS module provides an abstraction over these raw records and allows to manipulate each RR type with specific options. For each supported RR type, DNS module provides a standard option to manipulate a raw records with format ---rec, e.g. --mx-rec, and special options for every part of the RR structure with format ---, e.g. --mx-preference and --mx-exchanger. When adding a record, either RR specific options or standard option for a raw value can be used, they just should not be combined in one add operation. When modifying an existing entry, new RR specific options can be used to change one part of a DNS record, where the standard option for raw value is used to specify the modified value. The following example demonstrates a modification of MX record preference from 0 to 1 in a record without modifying the exchanger: ipa dnsrecord-mod --mx-rec="0 mx.example.com." --mx-preference=1 EXAMPLES: Add new zone: ipa dnszone-add example.com --name-server=ns \\ --admin-email=admin@example.com \\ --ip-address=10.0.0.1 Add system permission that can be used for per-zone privilege delegation: ipa dnszone-add-permission example.com Modify the zone to allow dynamic updates for hosts own records in realm EXAMPLE.COM: ipa dnszone-mod example.com --dynamic-update=TRUE This is the equivalent of: ipa dnszone-mod example.com --dynamic-update=TRUE \\ --update-policy="grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;" Modify the zone to allow zone transfers for local network only: ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8 Add new reverse zone specified by network IP address: ipa dnszone-add --name-from-ip=80.142.15.0/24 \\ --name-server=ns.example.com. Add second nameserver for example.com: ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com Add a mail server for example.com: ipa dnsrecord-add example.com @ --mx-rec="10 mail1" Add another record using MX record specific options: ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2 Add another record using interactive mode (started when dnsrecord-add, dnsrecord-mod, or dnsrecord-del are executed with no options): ipa dnsrecord-add example.com @ Please choose a type of DNS resource record to be added The most common types for this type of zone are: NS, MX, LOC DNS resource record type: MX MX Preference: 30 MX Exchanger: mail3 Record name: example.com MX record: 10 mail1, 20 mail2, 30 mail3 NS record: nameserver.example.com., nameserver2.example.com. Delete previously added nameserver from example.com: ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com. Add LOC record for example.com: ipa dnsrecord-add example.com @ --loc-rec="49 11 42.4 N 16 36 29.6 E 227.64m" Add new A record for www.example.com. Create a reverse record in appropriate reverse zone as well. In this case a PTR record "2" pointing to www.example.com will be created in zone 15.142.80.in-addr.arpa. ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse Add new PTR record for www.example.com ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com. Add new SRV records for LDAP servers. Three quarters of the requests should go to fast.example.com, one quarter to slow.example.com. If neither is available, switch to backup.example.com. ipa dnsrecord-add example.com _ldap._tcp --srv-rec="0 3 389 fast.example.com" ipa dnsrecord-add example.com _ldap._tcp --srv-rec="0 1 389 slow.example.com" ipa dnsrecord-add example.com _ldap._tcp --srv-rec="1 1 389 backup.example.com" The interactive mode can be used for easy modification: ipa dnsrecord-mod example.com _ldap._tcp No option to modify specific record provided. Current DNS record contents: SRV record: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 backup.example.com Modify SRV record '0 3 389 fast.example.com'? Yes/No (default No): Modify SRV record '0 1 389 slow.example.com'? Yes/No (default No): y SRV Priority [0]: (keep the default value) SRV Weight [1]: 2 (modified value) SRV Port [389]: (keep the default value) SRV Target [slow.example.com]: (keep the default value) 1 SRV record skipped. Only one value per DNS record type can be modified at one time. Record name: _ldap._tcp SRV record: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 389 slow.example.com After this modification, three fifths of the requests should go to fast.example.com and two fifths to slow.example.com. An example of the interactive mode for dnsrecord-del command: ipa dnsrecord-del example.com www No option to delete specific record provided. Delete all? Yes/No (default No): (do not delete all records) Current DNS record contents: A record: 1.2.3.4, 11.22.33.44 Delete A record '1.2.3.4'? Yes/No (default No): Delete A record '11.22.33.44'? Yes/No (default No): y Record name: www A record: 1.2.3.4 (A record 11.22.33.44 has been deleted) Show zone example.com: ipa dnszone-show example.com Find zone with "example" in its domain name: ipa dnszone-find example Find records for resources with "www" in their name in zone example.com: ipa dnsrecord-find example.com www Find A records with value 10.10.0.1 in zone example.com ipa dnsrecord-find example.com --a-rec=10.10.0.1 Show records for resource www in zone example.com ipa dnsrecord-show example.com www Delegate zone sub.example to another nameserver: ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5 ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com. If global forwarder is configured, all requests to sub.example.com will be routed through the global forwarder. To change the behavior for example.com zone only and forward the request directly to ns.sub.example.com., global forwarding may be disabled per-zone: ipa dnszone-mod example.com --forward-policy=none Forward all requests for the zone external.com to another nameserver using a "first" policy (it will send the queries to the selected forwarder and if not answered it will use global resolvers): ipa dnszone-add external.com ipa dnszone-mod external.com --forwarder=10.20.0.1 \\ --forward-policy=first Delete zone example.com with all resource records: ipa dnszone-del example.com Resolve a host name to see if it exists (will add default IPA domain if one is not included): ipa dns-resolve www.example.com ipa dns-resolve www GLOBAL DNS CONFIGURATION DNS configuration passed to command line install script is stored in a local configuration file on each IPA server where DNS service is configured. These local settings can be overridden with a common configuration stored in LDAP server: Show global DNS configuration: ipa dnsconfig-show Modify global DNS configuration and set a list of global forwarders: ipa dnsconfig-mod --forwarder=10.0.0.1 """) # supported resource record types _record_types = ( u'A', u'AAAA', u'A6', u'AFSDB', u'APL', u'CERT', u'CNAME', u'DHCID', u'DLV', u'DNAME', u'DNSKEY', u'DS', u'HIP', u'IPSECKEY', u'KEY', u'KX', u'LOC', u'MX', u'NAPTR', u'NS', u'NSEC', u'NSEC3', u'NSEC3PARAM', u'PTR', u'RRSIG', u'RP', u'SIG', u'SPF', u'SRV', u'SSHFP', u'TA', u'TKEY', u'TSIG', u'TXT', ) # DNS zone record identificator _dns_zone_record = u'@' # most used record types, always ask for those in interactive prompt _top_record_types = ('A', 'AAAA', ) _rev_top_record_types = ('PTR', ) _zone_top_record_types = ('NS', 'MX', 'LOC', ) # attributes derived from record types _record_attributes = [str('%srecord' % t.lower()) for t in _record_types] # supported DNS classes, IN = internet, rest is almost never used _record_classes = (u'IN', u'CS', u'CH', u'HS') def _rname_validator(ugettext, zonemgr): try: validate_zonemgr(zonemgr) except ValueError, e: return unicode(e) return None def _create_zone_serial(): """ 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): try: netaddr.IPAddress(str(netstr)) except (netaddr.AddrFormatError, ValueError): pass else: # use more sensible default prefix than netaddr default return unicode(get_reverse_zone_default(netstr)) net = netaddr.IPNetwork(netstr) items = net.ip.reverse_dns.split('.') if net.version == 4: return u'.'.join(items[4 - net.prefixlen / 8:]) elif net.version == 6: return u'.'.join(items[32 - net.prefixlen / 4:]) else: return None def _validate_ipaddr(ugettext, ipaddr, ip_version=None): try: ip = netaddr.IPAddress(str(ipaddr), flags=netaddr.INET_PTON) if ip_version is not None: if ip.version != ip_version: return _('invalid IP address version (is %(value)d, must be %(required_value)d)!') \ % dict(value=ip.version, required_value=ip_version) except (netaddr.AddrFormatError, ValueError): return _('invalid IP address format') return None def _validate_ip4addr(ugettext, ipaddr): return _validate_ipaddr(ugettext, ipaddr, 4) def _validate_ip6addr(ugettext, ipaddr): return _validate_ipaddr(ugettext, ipaddr, 6) def _validate_ipnet(ugettext, ipnet): try: net = netaddr.IPNetwork(ipnet) except (netaddr.AddrFormatError, ValueError, UnboundLocalError): return _('invalid IP network format') return None def _validate_bind_aci(ugettext, bind_acis): if not bind_acis: return bind_acis = bind_acis.split(';') if bind_acis[-1]: return _('each ACL element must be terminated with a semicolon') else: bind_acis.pop(-1) for bind_aci in bind_acis: if bind_aci in ("any", "none", "localhost", "localnets"): continue if bind_aci.startswith('!'): bind_aci = bind_aci[1:] try: ip = CheckedIPAddress(bind_aci, parse_netmask=True, allow_network=True, allow_loopback=True) except (netaddr.AddrFormatError, ValueError), e: return unicode(e) except UnboundLocalError: return _(u"invalid address format") def _normalize_bind_aci(bind_acis): if not bind_acis: return bind_acis = bind_acis.split(';') normalized = [] for bind_aci in bind_acis: if not bind_aci: continue if bind_aci in ("any", "none", "localhost", "localnets"): normalized.append(bind_aci) continue prefix = "" if bind_aci.startswith('!'): bind_aci = bind_aci[1:] prefix = "!" try: ip = CheckedIPAddress(bind_aci, parse_netmask=True, allow_network=True, allow_loopback=True) if '/' in bind_aci: # addr with netmask netmask = "/%s" % ip.prefixlen else: netmask = "" normalized.append(u"%s%s%s" % (prefix, str(ip), netmask)) continue except: normalized.append(bind_aci) continue acis = u';'.join(normalized) acis += u';' return acis def _bind_hostname_validator(ugettext, value): if value == _dns_zone_record: return try: # Allow domain name which is not fully qualified. These are supported # in bind and then translated as .. validate_hostname(value, check_fqdn=False, allow_underscore=True) except ValueError, e: return _('invalid domain-name: %s') \ % unicode(e) return None def _dns_record_name_validator(ugettext, value): if value == _dns_zone_record: return try: map(lambda label:validate_dns_label(label, allow_underscore=True), \ value.split(u'.')) except ValueError, e: return unicode(e) def _validate_bind_forwarder(ugettext, forwarder): ip_address, sep, port = forwarder.partition(u' port ') ip_address_validation = _validate_ipaddr(ugettext, ip_address) if ip_address_validation is not None: return ip_address_validation if sep: try: port = int(port) if port < 0 or port > 65535: raise ValueError() except ValueError: return _('%(port)s is not a valid port' % dict(port=port)) return None def _domain_name_validator(ugettext, value): try: validate_domain_name(value) except ValueError, e: return unicode(e) def _hostname_validator(ugettext, value): try: validate_hostname(value) except ValueError, e: return _('invalid domain-name: %s') \ % unicode(e) return None def _normalize_hostname(domain_name): """Make it fully-qualified""" if domain_name[-1] != '.': return domain_name + '.' else: return domain_name def is_forward_record(zone, str_address): addr = netaddr.IPAddress(str_address) if addr.version == 4: result = api.Command['dnsrecord_find'](zone, arecord=str_address) elif addr.version == 6: result = api.Command['dnsrecord_find'](zone, aaaarecord=str_address) else: raise ValueError('Invalid address family') return result['count'] > 0 def add_forward_record(zone, name, str_address): addr = netaddr.IPAddress(str_address) try: if addr.version == 4: api.Command['dnsrecord_add'](zone, name, arecord=str_address) elif addr.version == 6: api.Command['dnsrecord_add'](zone, name, aaaarecord=str_address) else: raise ValueError('Invalid address family') except errors.EmptyModlist: pass # the entry already exists and matches def get_reverse_zone(ipaddr, prefixlen=None): ip = netaddr.IPAddress(str(ipaddr)) revdns = unicode(ip.reverse_dns) if prefixlen is None: revzone = u'' result = api.Command['dnszone_find']()['result'] for zone in result: zonename = zone['idnsname'][0] if revdns.endswith(zonename) and len(zonename) > len(revzone): revzone = zonename else: if ip.version == 4: pos = 4 - prefixlen / 8 elif ip.version == 6: pos = 32 - prefixlen / 4 items = ip.reverse_dns.split('.') revzone = u'.'.join(items[pos:]) try: api.Command['dnszone_show'](revzone) except errors.NotFound: revzone = u'' if len(revzone) == 0: raise errors.NotFound( reason=_('DNS reverse zone for IP address %(addr)s not found') % dict(addr=ipaddr) ) revname = revdns[:-len(revzone)-1] return revzone, revname def add_records_for_host_validation(option_name, host, domain, ip_addresses, check_forward=True, check_reverse=True): try: api.Command['dnszone_show'](domain)['result'] except errors.NotFound: raise errors.NotFound( reason=_('DNS zone %(zone)s not found') % dict(zone=domain) ) if not isinstance(ip_addresses, (tuple, list)): ip_addresses = [ip_addresses] for ip_address in ip_addresses: try: ip = CheckedIPAddress(ip_address, match_local=False) except Exception, e: raise errors.ValidationError(name=option_name, error=unicode(e)) if check_forward: if is_forward_record(domain, unicode(ip)): raise errors.DuplicateEntry( message=_(u'IP address %(ip)s is already assigned in domain %(domain)s.')\ % dict(ip=str(ip), domain=domain)) if check_reverse: try: prefixlen = None if not ip.defaultnet: prefixlen = ip.prefixlen # we prefer lookup of the IP through the reverse zone revzone, revname = get_reverse_zone(ip, prefixlen) reverse = api.Command['dnsrecord_find'](revzone, idnsname=revname) if reverse['count'] > 0: raise errors.DuplicateEntry( message=_(u'Reverse record for IP address %(ip)s already exists in reverse zone %(zone)s.')\ % dict(ip=str(ip), zone=revzone)) except errors.NotFound: pass def add_records_for_host(host, domain, ip_addresses, add_forward=True, add_reverse=True): if not isinstance(ip_addresses, (tuple, list)): ip_addresses = [ip_addresses] for ip_address in ip_addresses: ip = CheckedIPAddress(ip_address, match_local=False) if add_forward: add_forward_record(domain, host, unicode(ip)) if add_reverse: try: prefixlen = None if not ip.defaultnet: prefixlen = ip.prefixlen revzone, revname = get_reverse_zone(ip, prefixlen) addkw = { 'ptrrecord' : host + "." + domain } api.Command['dnsrecord_add'](revzone, revname, **addkw) except errors.EmptyModlist: # the entry already exists and matches pass class DNSRecord(Str): # a list of parts that create the actual raw DNS record parts = None # an optional list of parameters used in record-specific operations extra = None supported = True # supported RR types: https://fedorahosted.org/bind-dyndb-ldap/browser/doc/schema label_format = _("%s record") part_label_format = "%s %s" doc_format = _('Raw %s records') option_group_format = _('%s Record') see_rfc_msg = _("(see RFC %s for details)") part_name_format = "%s_part_%s" extra_name_format = "%s_extra_%s" cli_name_format = "%s_%s" format_error_msg = None kwargs = Str.kwargs + ( ('validatedns', bool, True), ('normalizedns', bool, True), ) # should be replaced in subclasses rrtype = None rfc = None def __init__(self, name=None, *rules, **kw): if self.rrtype not in _record_types: raise ValueError("Unknown RR type: %s. Must be one of %s" % \ (str(self.rrtype), ", ".join(_record_types))) if not name: name = "%srecord*" % self.rrtype.lower() kw.setdefault('cli_name', '%s_rec' % self.rrtype.lower()) kw.setdefault('label', self.label_format % self.rrtype) kw.setdefault('doc', self.doc_format % self.rrtype) kw.setdefault('option_group', self.option_group_format % self.rrtype) kw['csv'] = True if not self.supported: kw['flags'] = ('no_option',) super(DNSRecord, self).__init__(name, *rules, **kw) def _get_part_values(self, value): values = value.split() if len(values) != len(self.parts): return None return tuple(values) def _part_values_to_string(self, values, index): self._validate_parts(values) return u" ".join(super(DNSRecord, self)._convert_scalar(v, index) \ for v in values if v is not None) def get_parts_from_kw(self, kw, raise_on_none=True): part_names = tuple(self.part_name_format % (self.rrtype.lower(), part.name) \ for part in self.parts) vals = tuple(kw.get(part_name) for part_name in part_names) if all(val is None for val in vals): return if raise_on_none: for val_id,val in enumerate(vals): if val is None and self.parts[val_id].required: cli_name = self.cli_name_format % (self.rrtype.lower(), self.parts[val_id].name) raise errors.ConversionError(name=self.name, error=_("'%s' is a required part of DNS record") % cli_name) return vals def _validate_parts(self, parts): if len(parts) != len(self.parts): raise errors.ValidationError(name=self.name, error=_("Invalid number of parts!")) def _convert_scalar(self, value, index=None): if isinstance(value, (tuple, list)): return self._part_values_to_string(value, index) return super(DNSRecord, self)._convert_scalar(value, index) def normalize(self, value): if self.normalizedns: if isinstance(value, (tuple, list)): value = tuple( self._normalize_parts(v) for v in value \ if v is not None ) elif value is not None: value = (self._normalize_parts(value),) return super(DNSRecord, self).normalize(value) def _normalize_parts(self, value): """ Normalize a DNS record value using normalizers for its parts. """ if self.parts is None: return value try: values = self._get_part_values(value) if not values: return value converted_values = [ part._convert_scalar(values[part_id]) \ if values[part_id] is not None else None for part_id, part in enumerate(self.parts) ] new_values = [ part.normalize(converted_values[part_id]) \ for part_id, part in enumerate(self.parts) ] value = self._convert_scalar(new_values) except Exception: # cannot normalize, rather return original value than fail pass return value def _rule_validatedns(self, _, value): if not self.validatedns: return if value is None: return if value is None: return if not self.supported: return _('DNS RR type "%s" is not supported by bind-dyndb-ldap plugin') \ % self.rrtype if self.parts is None: return # validate record format values = self._get_part_values(value) if not values: if not self.format_error_msg: part_names = [part.name.upper() for part in self.parts] if self.rfc: see_rfc_msg = " " + self.see_rfc_msg % self.rfc else: see_rfc_msg = "" return _('format must be specified as "%(format)s" %(rfcs)s') \ % dict(format=" ".join(part_names), rfcs=see_rfc_msg) else: return self.format_error_msg # validate every part for part_id, part in enumerate(self.parts): val = part.normalize(values[part_id]) val = part.convert(val) part.validate(val) return None def _convert_dnsrecord_part(self, part): """ All parts of DNSRecord need to be processed and modified before they can be added to global DNS API. For example a prefix need to be added before part name so that the name is unique in the global namespace. """ name = self.part_name_format % (self.rrtype.lower(), part.name) cli_name = self.cli_name_format % (self.rrtype.lower(), part.name) label = self.part_label_format % (self.rrtype, unicode(part.label)) option_group = self.option_group_format % self.rrtype flags = list(part.flags) + ['dnsrecord_part', 'virtual_attribute',] if not part.required: flags.append('dnsrecord_optional') return part.clone_rename(name, cli_name=cli_name, label=label, required=False, option_group=option_group, flags=flags, hint=self.name,) # name of parent RR param def _convert_dnsrecord_extra(self, extra): """ Parameters for special per-type behavior need to be processed in the same way as record parts in _convert_dnsrecord_part(). """ name = self.extra_name_format % (self.rrtype.lower(), extra.name) cli_name = self.cli_name_format % (self.rrtype.lower(), extra.name) label = self.part_label_format % (self.rrtype, unicode(extra.label)) option_group = self.option_group_format % self.rrtype flags = list(extra.flags) + ['dnsrecord_extra', 'virtual_attribute',] return extra.clone_rename(name, cli_name=cli_name, label=label, required=False, option_group=option_group, flags=flags, hint=self.name,) # name of parent RR param def get_parts(self): if self.parts is None: return tuple() return tuple(self._convert_dnsrecord_part(part) for part in self.parts) def get_extra(self): if self.extra is None: return tuple() return tuple(self._convert_dnsrecord_extra(extra) for extra in self.extra) def __get_part_param(self, cmd, part, output_kw, default=None): name = self.part_name_format % (self.rrtype.lower(), part.name) label = self.part_label_format % (self.rrtype, unicode(part.label)) optional = not part.required output_kw[name] = cmd.prompt_param(part, optional=optional, label=label) def prompt_parts(self, cmd, mod_dnsvalue=None): mod_parts = None if mod_dnsvalue is not None: mod_parts = self._get_part_values(mod_dnsvalue) user_options = {} if self.parts is None: return user_options for part_id, part in enumerate(self.parts): if mod_parts: default = mod_parts[part_id] else: default = None self.__get_part_param(cmd, part, user_options, default) return user_options def prompt_missing_parts(self, cmd, kw, prompt_optional=False): user_options = {} if self.parts is None: return user_options for part in self.parts: name = self.part_name_format % (self.rrtype.lower(), part.name) if name in kw: continue optional = not part.required if optional and not prompt_optional: continue default = part.get_default(**kw) self.__get_part_param(cmd, part, user_options, default) return user_options # callbacks for per-type special record behavior def dnsrecord_add_pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) def dnsrecord_add_post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) class ForwardRecord(DNSRecord): extra = ( Flag('create_reverse?', label=_('Create reverse'), doc=_('Create reverse record for this IP Address'), flags=['no_update'] ), ) def dnsrecord_add_pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) reverse_option = self._convert_dnsrecord_extra(self.extra[0]) if options.get(reverse_option.name): records = entry_attrs.get(self.name, []) if not records: # ---create-reverse is set, but there are not records raise errors.RequirementError(name=self.name) for record in records: add_records_for_host_validation(self.name, keys[-1], keys[-2], record, check_forward=False, check_reverse=True) setattr(context, '%s_reverse' % self.name, entry_attrs.get(self.name)) def dnsrecord_add_post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) rev_records = getattr(context, '%s_reverse' % self.name, []) if rev_records: # make sure we don't run this post callback action again in nested # commands, line adding PTR record in add_records_for_host delattr(context, '%s_reverse' % self.name) for record in rev_records: try: add_records_for_host(keys[-1], keys[-2], record, add_forward=False, add_reverse=True) except Exception, e: raise errors.NonFatalError( reason=_('Cannot create reverse record for "%(value)s": %(exc)s') \ % dict(value=record, exc=unicode(e))) class ARecord(ForwardRecord): rrtype = 'A' rfc = 1035 parts = ( Str('ip_address', _validate_ip4addr, label=_('IP Address'), ), ) class A6Record(DNSRecord): rrtype = 'A6' rfc = 3226 parts = ( Str('data', label=_('Record data'), ), ) def _get_part_values(self, value): # A6 RR type is obsolete and only a raw interface is provided return (value,) class AAAARecord(ForwardRecord): rrtype = 'AAAA' rfc = 3596 parts = ( Str('ip_address', _validate_ip6addr, label=_('IP Address'), ), ) class AFSDBRecord(DNSRecord): rrtype = 'AFSDB' rfc = 1183 parts = ( Int('subtype?', label=_('Subtype'), minvalue=0, maxvalue=65535, ), Str('hostname', _bind_hostname_validator, label=_('Hostname'), ), ) class APLRecord(DNSRecord): rrtype = 'APL' rfc = 3123 supported = False class CERTRecord(DNSRecord): rrtype = 'CERT' rfc = 4398 parts = ( Int('type', label=_('Certificate Type'), minvalue=0, maxvalue=65535, ), Int('key_tag', label=_('Key Tag'), minvalue=0, maxvalue=65535, ), Int('algorithm', label=_('Algorithm'), minvalue=0, maxvalue=255, ), Str('certificate_or_crl', label=_('Certificate/CRL'), ), ) class CNAMERecord(DNSRecord): rrtype = 'CNAME' rfc = 1035 parts = ( Str('hostname', _bind_hostname_validator, label=_('Hostname'), doc=_('A hostname which this alias hostname points to'), ), ) class DHCIDRecord(DNSRecord): rrtype = 'DHCID' rfc = 4701 supported = False class DLVRecord(DNSRecord): rrtype = 'DLV' rfc = 4431 supported = False class DNAMERecord(DNSRecord): rrtype = 'DNAME' rfc = 2672 parts = ( Str('target', _bind_hostname_validator, label=_('Target'), ), ) class DNSKEYRecord(DNSRecord): rrtype = 'DNSKEY' rfc = 4034 supported = False class DSRecord(DNSRecord): rrtype = 'DS' rfc = 4034 parts = ( Int('key_tag', label=_('Key Tag'), minvalue=0, maxvalue=65535, ), Int('algorithm', label=_('Algorithm'), minvalue=0, maxvalue=255, ), Int('digest_type', label=_('Digest Type'), minvalue=0, maxvalue=255, ), Str('digest', label=_('Digest'), ), ) class HIPRecord(DNSRecord): rrtype = 'HIP' rfc = 5205 supported = False class KEYRecord(DNSRecord): rrtype = 'KEY' rfc = 2535 parts = ( Int('flags', label=_('Flags'), minvalue=0, maxvalue=65535, ), Int('protocol', label=_('Protocol'), minvalue=0, maxvalue=255, ), Int('algorithm', label=_('Algorithm'), minvalue=0, maxvalue=255, ), Str('public_key', label=_('Public Key'), ), ) class IPSECKEYRecord(DNSRecord): rrtype = 'IPSECKEY' rfc = 4025 supported = False class KXRecord(DNSRecord): rrtype = 'KX' rfc = 2230 parts = ( Int('preference', label=_('Preference'), doc=_('Preference given to this exchanger. Lower values are more preferred'), minvalue=0, maxvalue=65535, ), Str('exchanger', _bind_hostname_validator, label=_('Exchanger'), doc=_('A host willing to act as a key exchanger'), ), ) class LOCRecord(DNSRecord): rrtype = 'LOC' rfc = 1876 parts = ( Int('lat_deg', label=_('Degrees Latitude'), minvalue=0, maxvalue=90, ), Int('lat_min?', label=_('Minutes Latitude'), minvalue=0, maxvalue=59, ), Decimal('lat_sec?', label=_('Seconds Latitude'), minvalue='0.0', maxvalue='59.999', precision=3, ), StrEnum('lat_dir', label=_('Direction Latitude'), values=(u'N', u'S',), ), Int('lon_deg', label=_('Degrees Longitude'), minvalue=0, maxvalue=180, ), Int('lon_min?', label=_('Minutes Longitude'), minvalue=0, maxvalue=59, ), Decimal('lon_sec?', label=_('Seconds Longitude'), minvalue='0.0', maxvalue='59.999', precision=3, ), StrEnum('lon_dir', label=_('Direction Longitude'), values=(u'E', u'W',), ), Decimal('altitude', label=_('Altitude'), minvalue='-100000.00', maxvalue='42849672.95', precision=2, ), Decimal('size?', label=_('Size'), minvalue='0.0', maxvalue='90000000.00', precision=2, ), Decimal('h_precision?', label=_('Horizontal Precision'), minvalue='0.0', maxvalue='90000000.00', precision=2, ), Decimal('v_precision?', label=_('Vertical Precision'), minvalue='0.0', maxvalue='90000000.00', precision=2, ), ) format_error_msg = _("""format must be specified as "d1 [m1 [s1]] {"N"|"S"} d2 [m2 [s2]] {"E"|"W"} alt["m"] [siz["m"] [hp["m"] [vp["m"]]]]" where: d1: [0 .. 90] (degrees latitude) d2: [0 .. 180] (degrees longitude) m1, m2: [0 .. 59] (minutes latitude/longitude) s1, s2: [0 .. 59.999] (seconds latitude/longitude) alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters) siz, hp, vp: [0 .. 90000000.00] (size/precision in meters) See RFC 1876 for details""") def _get_part_values(self, value): regex = re.compile(\ r'(?P\d{1,2}\s+)(?P\d{1,2}\s+)?(?P\d{1,2}\.?\d{1,3}?\s+)?'\ r'(?P[N|S])\s+'\ r'(?P\d{1,3}\s+)(?P\d{1,2}\s+)?(?P\d{1,2}\.?\d{1,3}?\s+)?'\ r'(?P[W|E])\s+'\ r'(?P-?\d{1,8}\.?\d{1,2}?)m?\s*'\ r'(?P\d{1,8}\.?\d{1,2}?)?m?\s*'\ r'(?P\d{1,8}\.?\d{1,2}?)?m?\s*(?P\d{1,8}\.?\d{1,2}?)?m?\s*$') m = regex.match(value) if m is None: return None return tuple(x.strip() if x is not None else x for x in m.groups()) def _validate_parts(self, parts): super(LOCRecord, self)._validate_parts(parts) # create part_name -> part_id map first part_name_map = dict((part.name, part_id) \ for part_id,part in enumerate(self.parts)) requirements = ( ('lat_sec', 'lat_min'), ('lon_sec', 'lon_min'), ('h_precision', 'size'), ('v_precision', 'h_precision', 'size') ) for req in requirements: target_part = req[0] if parts[part_name_map[target_part]] is not None: required_parts = req[1:] if any(parts[part_name_map[part]] is None for part in required_parts): target_cli_name = self.cli_name_format % (self.rrtype.lower(), req[0]) required_cli_names = [ self.cli_name_format % (self.rrtype.lower(), part) for part in req[1:] ] error = _("'%(required)s' must not be empty when '%(name)s' is set") % \ dict(required=', '.join(required_cli_names), name=target_cli_name) raise errors.ValidationError(name=self.name, error=error) class MXRecord(DNSRecord): rrtype = 'MX' rfc = 1035 parts = ( Int('preference', label=_('Preference'), doc=_('Preference given to this exchanger. Lower values are more preferred'), minvalue=0, maxvalue=65535, ), Str('exchanger', _bind_hostname_validator, label=_('Exchanger'), doc=_('A host willing to act as a mail exchanger'), ), ) class NSRecord(DNSRecord): rrtype = 'NS' rfc = 1035 parts = ( Str('hostname', _bind_hostname_validator, label=_('Hostname'), ), ) class NSECRecord(DNSRecord): rrtype = 'NSEC' rfc = 4034 format_error_msg = _('format must be specified as "NEXT TYPE1 '\ '[TYPE2 [TYPE3 [...]]]" (see RFC 4034 for details)') _allowed_types = (u'SOA',) + _record_types parts = ( Str('next', _bind_hostname_validator, label=_('Next Domain Name'), ), StrEnum('types+', label=_('Type Map'), values=_allowed_types, csv=True, ), ) def _get_part_values(self, value): values = value.split() if len(values) < 2: return None return (values[0], tuple(values[1:])) def _part_values_to_string(self, values, index): self._validate_parts(values) values_flat = [values[0],] # add "next" part types = values[1] if not isinstance(types, (list, tuple)): types = [types,] values_flat.extend(types) return u" ".join(Str._convert_scalar(self, v, index) \ for v in values_flat if v is not None) class NSEC3Record(DNSRecord): rrtype = 'NSEC3' rfc = 5155 supported = False class NSEC3PARAMRecord(DNSRecord): rrtype = 'NSEC3PARAM' rfc = 5155 supported = False def _validate_naptr_flags(ugettext, flags): allowed_flags = u'SAUP' flags = flags.replace('"','').replace('\'','') for flag in flags: if flag not in allowed_flags: return _('flags must be one of "S", "A", "U", or "P"') class NAPTRRecord(DNSRecord): rrtype = 'NAPTR' rfc = 2915 parts = ( Int('order', label=_('Order'), minvalue=0, maxvalue=65535, ), Int('preference', label=_('Preference'), minvalue=0, maxvalue=65535, ), Str('flags', _validate_naptr_flags, label=_('Flags'), normalizer=lambda x:x.upper() ), Str('service', label=_('Service'), ), Str('regexp', label=_('Regular Expression'), ), Str('replacement', label=_('Replacement'), ), ) class PTRRecord(DNSRecord): rrtype = 'PTR' rfc = 1035 parts = ( Str('hostname', _hostname_validator, normalizer=_normalize_hostname, label=_('Hostname'), doc=_('The hostname this reverse record points to'), ), ) class RPRecord(DNSRecord): rrtype = 'RP' rfc = 1183 supported = False def _srv_target_validator(ugettext, value): if value == u'.': # service not available return return _bind_hostname_validator(ugettext, value) class SRVRecord(DNSRecord): rrtype = 'SRV' rfc = 2782 parts = ( Int('priority', label=_('Priority'), minvalue=0, maxvalue=65535, ), Int('weight', label=_('Weight'), minvalue=0, maxvalue=65535, ), Int('port', label=_('Port'), minvalue=0, maxvalue=65535, ), Str('target', _srv_target_validator, label=_('Target'), doc=_('The domain name of the target host or \'.\' if the service is decidedly not available at this domain'), ), ) def _sig_time_validator(ugettext, value): time_format = "%Y%m%d%H%M%S" try: time.strptime(value, time_format) except ValueError: return _('the value does not follow "YYYYMMDDHHMMSS" time format') class SIGRecord(DNSRecord): rrtype = 'SIG' rfc = 2535 _allowed_types = tuple([u'SOA'] + [x for x in _record_types if x != u'SIG']) parts = ( StrEnum('type_covered', label=_('Type Covered'), values=_allowed_types, ), Int('algorithm', label=_('Algorithm'), minvalue=0, maxvalue=255, ), Int('labels', label=_('Labels'), minvalue=0, maxvalue=255, ), Int('original_ttl', label=_('Original TTL'), minvalue=0, ), Str('signature_expiration', _sig_time_validator, label=_('Signature Expiration'), ), Str('signature_inception', _sig_time_validator, label=_('Signature Inception'), ), Int('key_tag', label=_('Key Tag'), minvalue=0, maxvalue=65535, ), Str('signers_name', label=_('Signer\'s Name'), ), Str('signature', label=_('Signature'), ), ) class SPFRecord(DNSRecord): rrtype = 'SPF' rfc = 4408 supported = False class RRSIGRecord(SIGRecord): rrtype = 'RRSIG' rfc = 4034 class SSHFPRecord(DNSRecord): rrtype = 'SSHFP' rfc = 4255 parts = ( Int('algorithm', label=_('Algorithm'), minvalue=0, maxvalue=255, ), Int('fp_type', label=_('Fingerprint Type'), minvalue=0, maxvalue=255, ), Str('fingerprint', label=_('Fingerprint'), ), ) class TARecord(DNSRecord): rrtype = 'TA' supported = False class TKEYRecord(DNSRecord): rrtype = 'TKEY' supported = False class TSIGRecord(DNSRecord): rrtype = 'TSIG' supported = False class TXTRecord(DNSRecord): rrtype = 'TXT' rfc = 1035 parts = ( Str('data', label=_('Text Data'), ), ) def _get_part_values(self, value): # ignore any space in TXT record return (value,) _dns_records = ( ARecord(), AAAARecord(), A6Record(), AFSDBRecord(), APLRecord(), CERTRecord(), CNAMERecord(), DHCIDRecord(), DLVRecord(), DNAMERecord(), DNSKEYRecord(), DSRecord(), HIPRecord(), IPSECKEYRecord(), KEYRecord(), KXRecord(), LOCRecord(), MXRecord(), NAPTRRecord(), NSRecord(), NSECRecord(), NSEC3Record(), NSEC3PARAMRecord(), PTRRecord(), RRSIGRecord(), RPRecord(), SIGRecord(), SPFRecord(), SRVRecord(), SSHFPRecord(), TARecord(), TKEYRecord(), TSIGRecord(), TXTRecord(), ) def __dns_record_options_iter(): for opt in (Any('dnsrecords?', label=_('Records'), flags=['no_create', 'no_search', 'no_update'],), Str('dnstype?', label=_('Record type'), flags=['no_create', 'no_search', 'no_update'],), Str('dnsdata?', label=_('Record data'), flags=['no_create', 'no_search', 'no_update'],)): # These 3 options are used in --structured format. They are defined # rather in takes_params than has_output_params because of their # order - they should be printed to CLI before any DNS part param yield opt for option in _dns_records: yield option for part in option.get_parts(): yield part for extra in option.get_extra(): yield extra _dns_record_options = tuple(__dns_record_options_iter()) _dns_supported_record_types = tuple(record.rrtype for record in _dns_records \ if record.supported) def check_ns_rec_resolvable(zone, name): if name == _dns_zone_record: name = normalize_zone(zone) elif not name.endswith('.'): # this is a DNS name relative to the zone zone = dns.name.from_text(zone) name = unicode(dns.name.from_text(name, origin=zone)) try: return api.Command['dns_resolve'](name) except errors.NotFound: raise errors.NotFound( reason=_('Nameserver \'%(host)s\' does not have a corresponding A/AAAA record') % {'host': name} ) def dns_container_exists(ldap): try: ldap.get_entry(DN(api.env.container_dns, api.env.basedn), []) except errors.NotFound: return False return True def default_zone_update_policy(zone): if zone_is_reverse(zone): return get_dns_reverse_zone_update_policy(api.env.realm, zone) else: return get_dns_forward_zone_update_policy(api.env.realm) dnszone_output_params = ( Str('managedby', label=_('Managedby permission'), ), ) class dnszone(LDAPObject): """ DNS Zone, container for resource records. """ container_dn = api.env.container_dns object_name = _('DNS zone') object_name_plural = _('DNS zones') object_class = ['top', 'idnsrecord', 'idnszone'] possible_objectclasses = ['ipadnszone'] default_attributes = [ 'idnsname', 'idnszoneactive', 'idnssoamname', 'idnssoarname', 'idnssoaserial', 'idnssoarefresh', 'idnssoaretry', 'idnssoaexpire', 'idnssoaminimum', 'idnsallowquery', 'idnsallowtransfer', 'idnsforwarders', 'idnsforwardpolicy' ] + _record_attributes label = _('DNS Zones') label_singular = _('DNS Zone') takes_params = ( Str('idnsname', _domain_name_validator, cli_name='name', label=_('Zone name'), doc=_('Zone name (FQDN)'), default_from=lambda name_from_ip: _reverse_zone_name(name_from_ip), normalizer=lambda value: value.lower(), primary_key=True, ), Str('name_from_ip?', _validate_ipnet, label=_('Reverse zone IP network'), doc=_('IP network to create reverse zone name from'), flags=('virtual_attribute',), ), Str('idnssoamname', cli_name='name_server', label=_('Authoritative nameserver'), doc=_('Authoritative nameserver domain name'), normalizer=lambda value: value.lower(), ), Str('idnssoarname', _rname_validator, cli_name='admin_email', label=_('Administrator e-mail address'), doc=_('Administrator e-mail address'), default_from=lambda idnsname: 'hostmaster.%s' % idnsname, normalizer=normalize_zonemgr, ), Int('idnssoaserial', cli_name='serial', label=_('SOA serial'), doc=_('SOA record serial number'), minvalue=1, maxvalue=4294967295L, default_from=_create_zone_serial, autofill=True, ), Int('idnssoarefresh', cli_name='refresh', label=_('SOA refresh'), doc=_('SOA record refresh time'), minvalue=0, maxvalue=2147483647, default=3600, autofill=True, ), Int('idnssoaretry', cli_name='retry', label=_('SOA retry'), doc=_('SOA record retry time'), minvalue=0, maxvalue=2147483647, default=900, autofill=True, ), Int('idnssoaexpire', cli_name='expire', label=_('SOA expire'), doc=_('SOA record expire time'), default=1209600, minvalue=0, maxvalue=2147483647, autofill=True, ), Int('idnssoaminimum', cli_name='minimum', label=_('SOA minimum'), doc=_('How long should negative responses be cached'), default=3600, minvalue=0, maxvalue=2147483647, autofill=True, ), Int('dnsttl?', cli_name='ttl', label=_('SOA time to live'), doc=_('SOA record time to live'), minvalue=0, maxvalue=2147483647, # see RFC 2181 ), StrEnum('dnsclass?', cli_name='class', label=_('SOA class'), doc=_('SOA record class'), values=_record_classes, ), Str('idnsupdatepolicy?', cli_name='update_policy', label=_('BIND update policy'), doc=_('BIND update policy'), default_from=lambda idnsname: default_zone_update_policy(idnsname), autofill=True ), Bool('idnszoneactive?', cli_name='zone_active', label=_('Active zone'), doc=_('Is zone active?'), flags=['no_create', 'no_update'], attribute=True, ), Bool('idnsallowdynupdate?', cli_name='dynamic_update', label=_('Dynamic update'), doc=_('Allow dynamic updates.'), attribute=True, default=False, autofill=True ), Str('idnsallowquery?', _validate_bind_aci, normalizer=_normalize_bind_aci, cli_name='allow_query', label=_('Allow query'), doc=_('Semicolon separated list of IP addresses or networks which are allowed to issue queries'), default=u'any;', # anyone can issue queries by default autofill=True, ), Str('idnsallowtransfer?', _validate_bind_aci, normalizer=_normalize_bind_aci, cli_name='allow_transfer', label=_('Allow transfer'), doc=_('Semicolon separated list of IP addresses or networks which are allowed to transfer the zone'), default=u'none;', # no one can issue queries by default autofill=True, ), Str('idnsforwarders*', _validate_bind_forwarder, cli_name='forwarder', label=_('Zone forwarders'), doc=_('Per-zone forwarders. A custom port can be specified ' 'for each forwarder using a standard format "IP_ADDRESS port PORT"'), csv=True, ), StrEnum('idnsforwardpolicy?', cli_name='forward_policy', label=_('Forward policy'), doc=_('Per-zone conditional forwarding policy. Set to "none" to ' 'disable forwarding to global forwarder for this zone. In ' 'that case, conditional zone forwarders are disregarded.'), values=(u'only', u'first', u'none'), ), Bool('idnsallowsyncptr?', cli_name='allow_sync_ptr', label=_('Allow PTR sync'), doc=_('Allow synchronization of forward (A, AAAA) and reverse (PTR) records in the zone'), ), ) def get_dn(self, *keys, **options): zone = keys[-1] dn = super(dnszone, self).get_dn(zone, **options) try: self.backend.get_entry(dn, ['']) except errors.NotFound: if zone.endswith(u'.'): zone = zone[:-1] else: zone = zone + u'.' test_dn = super(dnszone, self).get_dn(zone, **options) try: (dn, entry_attrs) = self.backend.get_entry(test_dn, ['']) except errors.NotFound: pass return dn def permission_name(self, zone): return u"Manage DNS zone %s" % zone def get_name_in_zone(self, zone, hostname): """ Get name of a record that is to be added to a new zone. I.e. when we want to add record "ipa.lab.example.com" in a zone "example.com", this function should return "ipa.lab". Returns None when record cannot be added to a zone """ if hostname == _dns_zone_record: # special case: @ --> zone name return hostname if hostname.endswith(u'.'): hostname = hostname[:-1] if zone.endswith(u'.'): zone = zone[:-1] hostname_parts = hostname.split(u'.') zone_parts = zone.split(u'.') dns_name = list(hostname_parts) for host_part, zone_part in zip(reversed(hostname_parts), reversed(zone_parts)): if host_part != zone_part: return None dns_name.pop() if not dns_name: # hostname is directly in zone itself return _dns_zone_record return u'.'.join(dns_name) api.register(dnszone) class dnszone_add(LDAPCreate): __doc__ = _('Create new DNS zone (SOA record).') has_output_params = LDAPCreate.has_output_params + dnszone_output_params takes_options = LDAPCreate.takes_options + ( Flag('force', label=_('Force'), doc=_('Force DNS zone creation even if nameserver is not resolvable.'), ), Str('ip_address?', _validate_ipaddr, doc=_('Add forward record for nameserver located in the created zone'), label=_('Nameserver IP address'), ), ) def interactive_prompt_callback(self, kw): """ Interactive mode should prompt for nameserver IP address only if all of the following conditions are true: * New zone is a forward zone * NS is defined inside the new zone (NS can be given either in the form of absolute or relative name) """ if kw.get('ip_address', None): return zone = normalize_zone(kw['idnsname']) ns = kw['idnssoamname'] relative_ns = not ns.endswith('.') ns_in_zone = self.obj.get_name_in_zone(zone, ns) if not zone_is_reverse(zone) and (relative_ns or ns_in_zone): ip_address = self.Backend.textui.prompt(_(u'Nameserver IP address')) kw['ip_address'] = ip_address def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if not dns_container_exists(self.api.Backend.ldap2): raise errors.NotFound(reason=_('DNS is not configured')) entry_attrs['idnszoneactive'] = 'TRUE' # Check nameserver has a forward record nameserver = entry_attrs['idnssoamname'] # NS record must contain domain name if valid_ip(nameserver): raise errors.ValidationError(name='name-server', error=_("Nameserver address is not a domain name")) nameserver_ip_address = options.get('ip_address') normalized_zone = normalize_zone(keys[-1]) if nameserver.endswith('.'): record_in_zone = self.obj.get_name_in_zone(keys[-1], nameserver) else: record_in_zone = nameserver if zone_is_reverse(normalized_zone): if not nameserver.endswith('.'): raise errors.ValidationError(name='name-server', error=_("Nameserver for reverse zone cannot be " "a relative DNS name")) elif nameserver_ip_address: raise errors.ValidationError(name='ip_address', error=_("Nameserver DNS record is created for " "for forward zones only")) elif nameserver_ip_address and nameserver.endswith('.') and not record_in_zone: raise errors.ValidationError(name='ip_address', error=_("Nameserver DNS record is created only for " "nameservers in current zone")) if not nameserver_ip_address and not options['force']: check_ns_rec_resolvable(keys[0], nameserver) entry_attrs['nsrecord'] = nameserver entry_attrs['idnssoamname'] = nameserver return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) nameserver_ip_address = options.get('ip_address') if nameserver_ip_address: nameserver = entry_attrs['idnssoamname'][0] if nameserver.endswith('.'): dns_record = self.obj.get_name_in_zone(keys[-1], nameserver) else: dns_record = nameserver add_forward_record(keys[-1], dns_record, nameserver_ip_address) # Add entry to realmdomains # except for our own domain, forwarded zones and reverse zones zone = keys[0] if (zone != api.env.domain and not options.get('idnsforwarders') and not zone_is_reverse(zone)): try: api.Command['realmdomains_mod'](add_domain=zone, force=True) except errors.EmptyModlist: pass return dn api.register(dnszone_add) class dnszone_del(LDAPDelete): __doc__ = _('Delete DNS zone (SOA record).') msg_summary = _('Deleted DNS zone "%(value)s"') def post_callback(self, ldap, dn, *keys, **options): try: api.Command['permission_del'](self.obj.permission_name(keys[-1]), force=True) except errors.NotFound: pass # Delete entry from realmdomains # except for our own domain zone = keys[0] if zone != api.env.domain: try: api.Command['realmdomains_mod'](del_domain=zone, force=True) except errors.AttrValueNotFound: pass return True api.register(dnszone_del) class dnszone_mod(LDAPUpdate): __doc__ = _('Modify DNS zone (SOA record).') takes_options = LDAPUpdate.takes_options + ( Flag('force', label=_('Force'), doc=_('Force nameserver change even if nameserver not in DNS'), ), ) has_output_params = LDAPUpdate.has_output_params + dnszone_output_params def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): nameserver = entry_attrs.get('idnssoamname') if nameserver and nameserver != _dns_zone_record and not options['force']: check_ns_rec_resolvable(keys[0], nameserver) return dn api.register(dnszone_mod) class dnszone_find(LDAPSearch): __doc__ = _('Search for DNS zones (SOA records).') has_output_params = LDAPSearch.has_output_params + dnszone_output_params def args_options_2_params(self, *args, **options): # FIXME: Check that name_from_ip is valid. This is necessary because # custom validation rules, including _validate_ipnet, are not # used when doing a search. Once we have a parameter type for # IP network objects, this will no longer be necessary, as the # parameter type will handle the validation itself (see # ). if 'name_from_ip' in options: self.obj.params['name_from_ip'](unicode(options['name_from_ip'])) return super(dnszone_find, self).args_options_2_params(*args, **options) def args_options_2_entry(self, *args, **options): if 'name_from_ip' in options: if 'idnsname' not in options: options['idnsname'] = self.obj.params['idnsname'].get_default(**options) del options['name_from_ip'] return super(dnszone_find, self).args_options_2_entry(*args, **options) takes_options = LDAPSearch.takes_options + ( Flag('forward_only', label=_('Forward zones only'), cli_name='forward_only', doc=_('Search for forward zones only'), ), ) def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) if options.get('forward_only', False): search_kw = {} search_kw['idnsname'] = REVERSE_DNS_ZONES.keys() rev_zone_filter = ldap.make_filter(search_kw, rules=ldap.MATCH_NONE, exact=False, trailing_wildcard=False) filter = ldap.combine_filters((rev_zone_filter, filter), rules=ldap.MATCH_ALL) return (filter, base_dn, scope) api.register(dnszone_find) class dnszone_show(LDAPRetrieve): __doc__ = _('Display information about a DNS zone (SOA record).') has_output_params = LDAPRetrieve.has_output_params + dnszone_output_params api.register(dnszone_show) class dnszone_disable(LDAPQuery): __doc__ = _('Disable DNS Zone.') has_output = output.standard_value msg_summary = _('Disabled DNS zone "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) try: ldap.update_entry(dn, {'idnszoneactive': 'FALSE'}) except errors.EmptyModlist: pass return dict(result=True, value=keys[-1]) api.register(dnszone_disable) class dnszone_enable(LDAPQuery): __doc__ = _('Enable DNS Zone.') has_output = output.standard_value msg_summary = _('Enabled DNS zone "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) try: ldap.update_entry(dn, {'idnszoneactive': 'TRUE'}) except errors.EmptyModlist: pass return dict(result=True, value=keys[-1]) api.register(dnszone_enable) class dnszone_add_permission(LDAPQuery): __doc__ = _('Add a permission for per-zone access delegation.') has_output = output.standard_value msg_summary = _('Added system permission "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) try: (dn_, entry_attrs) = ldap.get_entry(dn, ['objectclass']) except errors.NotFound: self.obj.handle_not_found(*keys) permission_name = self.obj.permission_name(keys[-1]) permission = api.Command['permission_add_noaci'](permission_name, permissiontype=u'SYSTEM' )['result'] update = {} dnszone_ocs = entry_attrs.get('objectclass') if dnszone_ocs: dnszone_ocs.append('ipadnszone') update['objectclass'] = list(set(dnszone_ocs)) update['managedby'] = [permission['dn']] ldap.update_entry(dn, update) return dict( result=True, value=permission_name, ) api.register(dnszone_add_permission) class dnszone_remove_permission(LDAPQuery): __doc__ = _('Remove a permission for per-zone access delegation.') has_output = output.standard_value msg_summary = _('Removed system permission "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) try: ldap.update_entry(dn, {'managedby': None}) except errors.NotFound: self.obj.handle_not_found(*keys) except errors.EmptyModlist: # managedBy attribute is clean, lets make sure there is also no # dangling DNS zone permission pass permission_name = self.obj.permission_name(keys[-1]) api.Command['permission_del'](permission_name, force=True) return dict( result=True, value=permission_name, ) api.register(dnszone_remove_permission) class dnsrecord(LDAPObject): """ DNS record. """ parent_object = 'dnszone' container_dn = api.env.container_dns object_name = _('DNS resource record') object_name_plural = _('DNS resource records') object_class = ['top', 'idnsrecord'] default_attributes = ['idnsname'] + _record_attributes rdn_is_primary_key = True label = _('DNS Resource Records') label_singular = _('DNS Resource Record') takes_params = ( Str('idnsname', _dns_record_name_validator, cli_name='name', label=_('Record name'), doc=_('Record name'), primary_key=True, ), Int('dnsttl?', cli_name='ttl', label=_('Time to live'), doc=_('Time to live'), ), StrEnum('dnsclass?', cli_name='class', label=_('Class'), doc=_('DNS class'), values=_record_classes, ), ) + _dns_record_options structured_flag = Flag('structured', label=_('Structured'), doc=_('Parse all raw DNS records and return them in a structured way'), ) def _nsrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) nsrecords = entry_attrs.get('nsrecord') if options.get('force', False) or nsrecords is None: return for nsrecord in nsrecords: check_ns_rec_resolvable(keys[0], nsrecord) def _ptrrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) ptrrecords = entry_attrs.get('ptrrecord') if ptrrecords is None: return zone = keys[-2] if self.is_pkey_zone_record(*keys): addr = u'' else: addr = keys[-1] zone_len = 0 for valid_zone in REVERSE_DNS_ZONES: if zone.endswith(valid_zone): zone = zone.replace(valid_zone,'') zone_name = valid_zone zone_len = REVERSE_DNS_ZONES[valid_zone] if not zone_len: allowed_zones = ', '.join(REVERSE_DNS_ZONES) raise errors.ValidationError(name='ptrrecord', error=unicode(_('Reverse zone for PTR record should be a sub-zone of one the following fully qualified domains: %s') % allowed_zones)) addr_len = len(addr.split('.')) if addr else 0 ip_addr_comp_count = addr_len + len(zone.split('.')) if ip_addr_comp_count != zone_len: raise errors.ValidationError(name='ptrrecord', error=unicode(_('Reverse zone %(name)s requires exactly %(count)d IP address components, %(user_count)d given') % dict(name=zone_name, count=zone_len, user_count=ip_addr_comp_count))) def run_precallback_validators(self, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) ldap = self.api.Backend.ldap2 for rtype in entry_attrs.keys(): rtype_cb = getattr(self, '_%s_pre_callback' % rtype, None) if rtype_cb: rtype_cb(ldap, dn, entry_attrs, *keys, **options) def is_pkey_zone_record(self, *keys): idnsname = keys[-1] if idnsname == str(_dns_zone_record) or idnsname == ('%s.' % keys[-2]): return True return False def get_dn(self, *keys, **options): if self.is_pkey_zone_record(*keys): dn = self.api.Object[self.parent_object].get_dn(*keys[:-1], **options) # zone must exist ldap = self.api.Backend.ldap2 try: (dn_, zone) = ldap.get_entry(dn, []) except errors.NotFound: self.api.Object['dnszone'].handle_not_found(keys[-2]) return self.api.Object[self.parent_object].get_dn(*keys[:-1], **options) return super(dnsrecord, self).get_dn(*keys, **options) def attr_to_cli(self, attr): try: cliname = attr[:-len('record')].upper() except IndexError: cliname = attr return cliname def get_dns_masters(self): ldap = self.api.Backend.ldap2 base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn) ldap_filter = '(&(objectClass=ipaConfigObject)(cn=DNS))' dns_masters = [] try: entries = ldap.find_entries(filter=ldap_filter, base_dn=base_dn)[0] for entry in entries: master_dn = entry[0] assert isinstance(master_dn, DN) try: master = master_dn[1]['cn'] dns_masters.append(master) except (IndexError, KeyError): pass except errors.NotFound: return [] return dns_masters def has_cli_options(self, options, no_option_msg, allow_empty_attrs=False): if any(k in options for k in ('setattr', 'addattr', 'delattr', 'rename')): return has_options = False for attr in options.keys(): if attr in self.params and not self.params[attr].primary_key: if options[attr] or allow_empty_attrs: has_options = True break if not has_options: raise errors.OptionError(no_option_msg) def get_record_entry_attrs(self, entry_attrs): return dict((attr, val) for attr,val in entry_attrs.iteritems() \ if attr in self.params and not self.params[attr].primary_key) def postprocess_record(self, record, **options): if options.get('structured', False): for attr in record.keys(): # attributes in LDAPEntry may not be normalized attr = attr.lower() try: param = self.params[attr] except KeyError: continue if not isinstance(param, DNSRecord): continue parts_params = param.get_parts() for dnsvalue in record[attr]: dnsentry = { u'dnstype' : unicode(param.rrtype), u'dnsdata' : dnsvalue } values = param._get_part_values(dnsvalue) if values is None: continue for val_id, val in enumerate(values): if val is not None: dnsentry[parts_params[val_id].name] = val record.setdefault('dnsrecords', []).append(dnsentry) del record[attr] def get_rrparam_from_part(self, part_name): """ Get an instance of DNSRecord parameter that has part_name as its part. If such parameter is not found, None is returned :param part_name Part parameter name """ try: param = self.params[part_name] if not any(flag in param.flags for flag in \ ('dnsrecord_part', 'dnsrecord_extra')): return None # All DNS record part or extra parameters contain a name of its # parent RR parameter in its hint attribute rrparam = self.params[param.hint] except (KeyError, AttributeError): return None return rrparam def iterate_rrparams_by_parts(self, kw, skip_extra=False): """ Iterates through all DNSRecord instances that has at least one of its parts or extra options in given dictionary. It returns the DNSRecord instance only for the first occurence of part/extra option. :param kw Dictionary with DNS record parts or extra options :param skip_extra Skip DNS record extra options, yield only DNS records with a real record part """ processed = [] for opt in kw: rrparam = self.get_rrparam_from_part(opt) if rrparam is None: continue if skip_extra and 'dnsrecord_extra' in self.params[opt].flags: continue if rrparam.name not in processed: processed.append(rrparam.name) yield rrparam def check_record_type_collisions(self, keys, old_entry, entry_attrs): # Test that only allowed combination of record types was created rrattrs = {} if old_entry is not None: old_rrattrs = dict((key, value) for key, value in old_entry.iteritems() if key in self.params and isinstance(self.params[key], DNSRecord)) rrattrs.update(old_rrattrs) new_rrattrs = dict((key, value) for key, value in entry_attrs.iteritems() if key in self.params and isinstance(self.params[key], DNSRecord)) rrattrs.update(new_rrattrs) # CNAME record validation try: cnames = rrattrs['cnamerecord'] except KeyError: pass else: if cnames is not None: if len(cnames) > 1: raise errors.ValidationError(name='cnamerecord', error=_('only one CNAME record is allowed per name ' '(RFC 2136, section 1.1.5)')) if any(rrvalue is not None and rrattr != 'cnamerecord' for rrattr, rrvalue in rrattrs.iteritems()): raise errors.ValidationError(name='cnamerecord', error=_('CNAME record is not allowed to coexist ' 'with any other record (RFC 1034, section 3.6.2)')) # DNAME record validation try: dnames = rrattrs['dnamerecord'] except KeyError: pass else: if dnames is not None: if len(dnames) > 1: raise errors.ValidationError(name='dnamerecord', error=_('only one DNAME record is allowed per name ' '(RFC 6672, section 2.4)')) # DNAME must not coexist with CNAME, but this is already checked earlier if rrattrs.get('nsrecord') and keys[1] != _dns_zone_record: raise errors.ValidationError(name='dnamerecord', error=_('DNAME record is not allowed to coexist with an ' 'NS record except when located in a zone root ' 'record (RFC 6672, section 2.3)')) api.register(dnsrecord) class dnsrecord_add(LDAPCreate): __doc__ = _('Add new DNS resource record.') no_option_msg = 'No options to add a specific record provided.\n' \ "Command help may be consulted for all supported record types." takes_options = LDAPCreate.takes_options + ( Flag('force', label=_('Force'), flags=['no_option', 'no_output'], doc=_('force NS record creation even if its hostname is not in DNS'), ), dnsrecord.structured_flag, ) def args_options_2_entry(self, *keys, **options): self.obj.has_cli_options(options, self.no_option_msg) return super(dnsrecord_add, self).args_options_2_entry(*keys, **options) def interactive_prompt_callback(self, kw): try: self.obj.has_cli_options(kw, self.no_option_msg) # Some DNS records were entered, do not use full interactive help # We should still ask user for required parts of DNS parts he is # trying to add in the same way we do for standard LDAP parameters # # Do not ask for required parts when any "extra" option is used, # it can be used to fill all required params by itself new_kw = {} for rrparam in self.obj.iterate_rrparams_by_parts(kw, skip_extra=True): user_options = rrparam.prompt_missing_parts(self, kw, prompt_optional=False) new_kw.update(user_options) kw.update(new_kw) return except errors.OptionError: pass # check zone type if kw['idnsname'] == _dns_zone_record: common_types = u', '.join(_zone_top_record_types) elif zone_is_reverse(kw['dnszoneidnsname']): common_types = u', '.join(_rev_top_record_types) else: common_types = u', '.join(_top_record_types) self.Backend.textui.print_plain(_(u'Please choose a type of DNS resource record to be added')) self.Backend.textui.print_plain(_(u'The most common types for this type of zone are: %s\n') %\ common_types) ok = False while not ok: rrtype = self.Backend.textui.prompt(_(u'DNS resource record type')) if rrtype is None: return try: name = '%srecord' % rrtype.lower() param = self.params[name] if not isinstance(param, DNSRecord): raise ValueError() if not param.supported: raise ValueError() except (KeyError, ValueError): all_types = u', '.join(_dns_supported_record_types) self.Backend.textui.print_plain(_(u'Invalid or unsupported type. Allowed values are: %s') % all_types) continue ok = True user_options = param.prompt_parts(self) kw.update(user_options) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) precallback_attrs = [] processed_attrs = [] for option in options: try: param = self.params[option] except KeyError: continue rrparam = self.obj.get_rrparam_from_part(option) if rrparam is None: continue if 'dnsrecord_part' in param.flags: if rrparam.name in processed_attrs: # this record was already entered continue if rrparam.name in entry_attrs: # this record is entered both via parts and raw records raise errors.ValidationError(name=param.cli_name or param.name, error=_('Raw value of a DNS record was already set by "%(name)s" option') \ % dict(name=rrparam.cli_name or rrparam.name)) parts = rrparam.get_parts_from_kw(options) dnsvalue = [rrparam._convert_scalar(parts)] entry_attrs[rrparam.name] = dnsvalue processed_attrs.append(rrparam.name) continue if 'dnsrecord_extra' in param.flags: # do not run precallback for unset flags if isinstance(param, Flag) and not options[option]: continue # extra option is passed, run per-type pre_callback for given RR type precallback_attrs.append(rrparam.name) # Run pre_callback validators self.obj.run_precallback_validators(dn, entry_attrs, *keys, **options) # run precallback also for all new RR type attributes in entry_attrs for attr in entry_attrs.keys(): try: param = self.params[attr] except KeyError: continue if not isinstance(param, DNSRecord): continue precallback_attrs.append(attr) precallback_attrs = list(set(precallback_attrs)) for attr in precallback_attrs: # run per-type try: param = self.params[attr] except KeyError: continue param.dnsrecord_add_pre_callback(ldap, dn, entry_attrs, attrs_list, *keys, **options) # Store all new attrs so that DNSRecord post callback is called for # 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, _record_attributes) except errors.NotFound: old_entry = None else: for attr in entry_attrs.keys(): if attr not in _record_attributes: continue if entry_attrs[attr] is None: entry_attrs[attr] = [] if not isinstance(entry_attrs[attr], (tuple, list)): vals = [entry_attrs[attr]] else: vals = list(entry_attrs[attr]) entry_attrs[attr] = list(set(old_entry.get(attr, []) + vals)) self.obj.check_record_type_collisions(keys, old_entry, entry_attrs) return dn def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs): if call_func.func_name == 'add_entry': if isinstance(exc, errors.DuplicateEntry): # A new record is being added to existing LDAP DNS object # Update can be safely run as old record values has been # already merged in pre_callback ldap = self.obj.backend dn = call_args[0] entry_attrs = self.obj.get_record_entry_attrs(call_args[1]) ldap.update_entry(dn, entry_attrs, **call_kwargs) return raise exc def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) for attr in getattr(context, 'dnsrecord_precallback_attrs', []): param = self.params[attr] param.dnsrecord_add_post_callback(ldap, dn, entry_attrs, *keys, **options) if self.obj.is_pkey_zone_record(*keys): entry_attrs[self.obj.primary_key.name] = [_dns_zone_record] self.obj.postprocess_record(entry_attrs, **options) return dn api.register(dnsrecord_add) class dnsrecord_mod(LDAPUpdate): __doc__ = _('Modify a DNS resource record.') no_option_msg = 'No options to modify a specific record provided.' takes_options = LDAPUpdate.takes_options + ( dnsrecord.structured_flag, ) def args_options_2_entry(self, *keys, **options): self.obj.has_cli_options(options, self.no_option_msg, True) return super(dnsrecord_mod, self).args_options_2_entry(*keys, **options) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('rename') and self.obj.is_pkey_zone_record(*keys): # zone rename is not allowed raise errors.ValidationError(name='rename', error=_('DNS zone root record cannot be renamed')) # check if any attr should be updated using structured instead of replaced # format is recordname : (old_value, new_parts) updated_attrs = {} for param in self.obj.iterate_rrparams_by_parts(options, skip_extra=True): parts = param.get_parts_from_kw(options, raise_on_none=False) if parts is None: # old-style modification continue old_value = entry_attrs.get(param.name) if not old_value: raise errors.RequirementError(name=param.name) if isinstance(old_value, (tuple, list)): if len(old_value) > 1: raise errors.ValidationError(name=param.name, error=_('DNS records can be only updated one at a time')) old_value = old_value[0] updated_attrs[param.name] = (old_value, parts) # Run pre_callback validators self.obj.run_precallback_validators(dn, entry_attrs, *keys, **options) # 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) except errors.NotFound: 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] if old_dnsvalue not in old_entry.get(attr, []): attr_name = unicode(param.label or param.name) raise errors.AttrValueNotFound(attr=attr_name, value=old_dnsvalue) old_entry[attr].remove(old_dnsvalue) old_parts = param._get_part_values(old_dnsvalue) modified_parts = tuple(part if part is not None else old_parts[part_id] \ for part_id,part in enumerate(new_parts)) new_dnsvalue = [param._convert_scalar(modified_parts)] entry_attrs[attr] = list(set(old_entry[attr] + new_dnsvalue)) self.obj.check_record_type_collisions(keys, old_entry, entry_attrs) return dn def execute(self, *keys, **options): result = super(dnsrecord_mod, self).execute(*keys, **options) # remove if empty if not self.obj.is_pkey_zone_record(*keys): rename = options.get('rename') if rename is not None: keys = keys[:-1] + (rename,) dn = self.obj.get_dn(*keys, **options) ldap = self.obj.backend (dn_, old_entry) = ldap.get_entry(dn, _record_attributes) del_all = True for attr in old_entry.keys(): if old_entry[attr]: del_all = False break if del_all: return self.obj.methods.delentry(*keys, version=options['version']) return result def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if self.obj.is_pkey_zone_record(*keys): entry_attrs[self.obj.primary_key.name] = [_dns_zone_record] self.obj.postprocess_record(entry_attrs, **options) return dn def interactive_prompt_callback(self, kw): try: self.obj.has_cli_options(kw, self.no_option_msg, True) except errors.OptionError: pass else: # some record type entered, skip this helper return # get DNS record first so that the NotFound exception is raised # before the helper would start dns_record = api.Command['dnsrecord_show'](kw['dnszoneidnsname'], kw['idnsname'])['result'] rec_types = [rec_type for rec_type in dns_record if rec_type in _record_attributes] self.Backend.textui.print_plain(_("No option to modify specific record provided.")) # ask user for records to be removed self.Backend.textui.print_plain(_(u'Current DNS record contents:\n')) record_params = [] for attr in dns_record: try: param = self.params[attr] except KeyError: continue if not isinstance(param, DNSRecord): continue record_params.append(param) rec_type_content = u', '.join(dns_record[param.name]) self.Backend.textui.print_plain(u'%s: %s' % (param.label, rec_type_content)) self.Backend.textui.print_plain(u'') # ask what records to remove for param in record_params: rec_values = list(dns_record[param.name]) for rec_value in dns_record[param.name]: rec_values.remove(rec_value) mod_value = self.Backend.textui.prompt_yesno( _("Modify %(name)s '%(value)s'?") % dict(name=param.label, value=rec_value), default=False) if mod_value is True: user_options = param.prompt_parts(self, mod_dnsvalue=rec_value) kw[param.name] = [rec_value] kw.update(user_options) if rec_values: self.Backend.textui.print_plain(ngettext( u'%(count)d %(type)s record skipped. Only one value per DNS record type can be modified at one time.', u'%(count)d %(type)s records skipped. Only one value per DNS record type can be modified at one time.', 0) % dict(count=len(rec_values), type=param.rrtype)) break api.register(dnsrecord_mod) class dnsrecord_delentry(LDAPDelete): """ Delete DNS record entry. """ msg_summary = _('Deleted record "%(value)s"') NO_CLI = True api.register(dnsrecord_delentry) class dnsrecord_del(LDAPUpdate): __doc__ = _('Delete DNS resource record.') has_output = output.standard_delete no_option_msg = _('Neither --del-all nor options to delete a specific record provided.\n'\ "Command help may be consulted for all supported record types.") takes_options = ( Flag('del_all', default=False, label=_('Delete all associated records'), ), dnsrecord.structured_flag, ) def get_options(self): for option in super(dnsrecord_del, self).get_options(): if any(flag in option.flags for flag in \ ('dnsrecord_part', 'dnsrecord_extra',)): continue elif option.name in ('rename', ): # options only valid for dnsrecord-mod continue elif isinstance(option, DNSRecord): yield option.clone(option_group=None) continue yield option def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) try: (dn_, old_entry) = ldap.get_entry(dn, _record_attributes) except errors.NotFound: self.obj.handle_not_found(*keys) for attr in entry_attrs.keys(): if attr not in _record_attributes: continue if not isinstance(entry_attrs[attr], (tuple, list)): vals = [entry_attrs[attr]] else: vals = entry_attrs[attr] for val in vals: try: old_entry[attr].remove(val) except (KeyError, ValueError): try: param = self.params[attr] attr_name = unicode(param.label or param.name) except: attr_name = attr raise errors.AttrValueNotFound(attr=attr_name, value=val) entry_attrs[attr] = list(set(old_entry[attr])) del_all = False if not self.obj.is_pkey_zone_record(*keys): record_found = False for attr in old_entry.keys(): if old_entry[attr]: record_found = True break del_all = not record_found # set del_all flag in context # when the flag is enabled, the entire DNS record object is deleted # in a post callback setattr(context, 'del_all', del_all) return dn def execute(self, *keys, **options): if options.get('del_all', False): if self.obj.is_pkey_zone_record(*keys): raise errors.ValidationError( name='del_all', error=_('Zone record \'%s\' cannot be deleted') \ % _dns_zone_record ) return self.obj.methods.delentry(*keys, version=options['version']) result = super(dnsrecord_del, self).execute(*keys, **options) if getattr(context, 'del_all', False) and not \ self.obj.is_pkey_zone_record(*keys): return self.obj.methods.delentry(*keys, version=options['version']) return result def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if self.obj.is_pkey_zone_record(*keys): entry_attrs[self.obj.primary_key.name] = [_dns_zone_record] self.obj.postprocess_record(entry_attrs, **options) return dn def args_options_2_entry(self, *keys, **options): self.obj.has_cli_options(options, self.no_option_msg) return super(dnsrecord_del, self).args_options_2_entry(*keys, **options) def interactive_prompt_callback(self, kw): if kw.get('del_all', False): return try: self.obj.has_cli_options(kw, self.no_option_msg) except errors.OptionError: pass else: # some record type entered, skip this helper return # get DNS record first so that the NotFound exception is raised # before the helper would start dns_record = api.Command['dnsrecord_show'](kw['dnszoneidnsname'], kw['idnsname'])['result'] rec_types = [rec_type for rec_type in dns_record if rec_type in _record_attributes] self.Backend.textui.print_plain(_("No option to delete specific record provided.")) user_del_all = self.Backend.textui.prompt_yesno(_("Delete all?"), default=False) if user_del_all is True: kw['del_all'] = True return # ask user for records to be removed self.Backend.textui.print_plain(_(u'Current DNS record contents:\n')) present_params = [] for attr in dns_record: try: param = self.params[attr] except KeyError: continue if not isinstance(param, DNSRecord): continue present_params.append(param) rec_type_content = u', '.join(dns_record[param.name]) self.Backend.textui.print_plain(u'%s: %s' % (param.label, rec_type_content)) self.Backend.textui.print_plain(u'') # ask what records to remove for param in present_params: deleted_values = [] for rec_value in dns_record[param.name]: user_del_value = self.Backend.textui.prompt_yesno( _("Delete %(name)s '%(value)s'?") \ % dict(name=param.label, value=rec_value), default=False) if user_del_value is True: deleted_values.append(rec_value) if deleted_values: kw[param.name] = tuple(deleted_values) api.register(dnsrecord_del) class dnsrecord_show(LDAPRetrieve): __doc__ = _('Display DNS resource.') takes_options = LDAPRetrieve.takes_options + ( dnsrecord.structured_flag, ) def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if self.obj.is_pkey_zone_record(*keys): entry_attrs[self.obj.primary_key.name] = [_dns_zone_record] self.obj.postprocess_record(entry_attrs, **options) return dn api.register(dnsrecord_show) class dnsrecord_find(LDAPSearch): __doc__ = _('Search for DNS resources.') takes_options = LDAPSearch.takes_options + ( dnsrecord.structured_flag, ) def get_options(self): for option in super(dnsrecord_find, self).get_options(): if any(flag in option.flags for flag in \ ('dnsrecord_part', 'dnsrecord_extra',)): continue elif isinstance(option, DNSRecord): yield option.clone(option_group=None) continue yield option def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) # include zone record (root entry) in the search return (filter, base_dn, ldap.SCOPE_SUBTREE) def post_callback(self, ldap, entries, truncated, *args, **options): if entries: zone_obj = self.api.Object[self.obj.parent_object] zone_dn = zone_obj.get_dn(args[0]) if entries[0][0] == zone_dn: entries[0][1][zone_obj.primary_key.name] = [_dns_zone_record] for entry in entries: self.obj.postprocess_record(entry[1], **options) return truncated api.register(dnsrecord_find) class dns_resolve(Command): __doc__ = _('Resolve a host name in DNS.') has_output = output.standard_value msg_summary = _('Found \'%(value)s\'') takes_args = ( Str('hostname', label=_('Hostname'), ), ) def execute(self, *args, **options): query=args[0] if query.find(api.env.domain) == -1 and query.find('.') == -1: query = '%s.%s.' % (query, api.env.domain) if query[-1] != '.': query = query + '.' if not is_host_resolvable(query): raise errors.NotFound( reason=_('Host \'%(host)s\' not found') % {'host': query} ) return dict(result=True, value=query) api.register(dns_resolve) class dns_is_enabled(Command): """ Checks if any of the servers has the DNS service enabled. """ NO_CLI = True has_output = output.standard_value base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) filter = '(&(objectClass=ipaConfigObject)(cn=DNS))' def execute(self, *args, **options): ldap = self.api.Backend.ldap2 dns_enabled = False try: ent = ldap.find_entries(filter=self.filter, base_dn=self.base_dn) if len(ent): dns_enabled = True except Exception, e: pass return dict(result=dns_enabled, value=u'') api.register(dns_is_enabled) class dnsconfig(LDAPObject): """ DNS global configuration object """ object_name = _('DNS configuration options') default_attributes = [ 'idnsforwardpolicy', 'idnsforwarders', 'idnsallowsyncptr' ] label = _('DNS Global Configuration') label_singular = _('DNS Global Configuration') takes_params = ( Str('idnsforwarders*', _validate_bind_forwarder, cli_name='forwarder', label=_('Global forwarders'), doc=_('Global forwarders. A custom port can be specified for each ' 'forwarder using a standard format "IP_ADDRESS port PORT"'), csv=True, ), StrEnum('idnsforwardpolicy?', cli_name='forward_policy', label=_('Forward policy'), doc=_('Global forwarding policy. Set to "none" to disable ' 'any configured global forwarders.'), values=(u'only', u'first', u'none'), ), Bool('idnsallowsyncptr?', cli_name='allow_sync_ptr', label=_('Allow PTR sync'), doc=_('Allow synchronization of forward (A, AAAA) and reverse (PTR) records'), ), DeprecatedParam('idnszonerefresh?', cli_name='zone_refresh', label=_('Zone refresh interval'), ), ) def get_dn(self, *keys, **kwargs): return DN(api.env.container_dns, api.env.basedn) def get_dnsconfig(self, ldap): (dn, entry) = ldap.get_entry(self.get_dn(), None) return entry def postprocess_result(self, result): if not any(param in result['result'] for param in self.params): result['summary'] = unicode(_('Global DNS configuration is empty')) api.register(dnsconfig) class dnsconfig_mod(LDAPUpdate): __doc__ = _('Modify global DNS configuration.') def execute(self, *keys, **options): result = super(dnsconfig_mod, self).execute(*keys, **options) self.obj.postprocess_result(result) return result api.register(dnsconfig_mod) class dnsconfig_show(LDAPRetrieve): __doc__ = _('Show the current global DNS configuration.') def execute(self, *keys, **options): result = super(dnsconfig_show, self).execute(*keys, **options) self.obj.postprocess_result(result) return result api.register(dnsconfig_show) freeipa-3.3.4/ipalib/plugins/automount.py0000664000175000017500000010346512271663206020046 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # 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 . import os from ipalib import api, errors from ipalib import Object, Command from ipalib import Flag, Str, IA5Str from ipalib.plugins.baseldap import * from ipalib import _, ngettext __doc__ = _(""" Automount Stores automount(8) configuration for autofs(8) in IPA. The base of an automount configuration is the configuration file auto.master. This is also the base location in IPA. Multiple auto.master configurations can be stored in separate locations. A location is implementation-specific with the default being a location named 'default'. For example, you can have locations by geographic region, by floor, by type, etc. Automount has three basic object types: locations, maps and keys. A location defines a set of maps anchored in auto.master. This allows you to store multiple automount configurations. A location in itself isn't very interesting, it is just a point to start a new automount map. A map is roughly equivalent to a discrete automount file and provides storage for keys. A key is a mount point associated with a map. When a new location is created, two maps are automatically created for it: auto.master and auto.direct. auto.master is the root map for all automount maps for the location. auto.direct is the default map for direct mounts and is mounted on /-. An automount map may contain a submount key. This key defines a mount location within the map that references another map. This can be done either using automountmap-add-indirect --parentmap or manually with automountkey-add and setting info to "-type=autofs :". EXAMPLES: Locations: Create a named location, "Baltimore": ipa automountlocation-add baltimore Display the new location: ipa automountlocation-show baltimore Find available locations: ipa automountlocation-find Remove a named automount location: ipa automountlocation-del baltimore Show what the automount maps would look like if they were in the filesystem: ipa automountlocation-tofiles baltimore Import an existing configuration into a location: ipa automountlocation-import baltimore /etc/auto.master The import will fail if any duplicate entries are found. For continuous operation where errors are ignored, use the --continue option. Maps: Create a new map, "auto.share": ipa automountmap-add baltimore auto.share Display the new map: ipa automountmap-show baltimore auto.share Find maps in the location baltimore: ipa automountmap-find baltimore Create an indirect map with auto.share as a submount: ipa automountmap-add-indirect baltimore --parentmap=auto.share --mount=sub auto.man This is equivalent to: ipa automountmap-add-indirect baltimore --mount=/man auto.man ipa automountkey-add baltimore auto.man --key=sub --info="-fstype=autofs ldap:auto.share" Remove the auto.share map: ipa automountmap-del baltimore auto.share Keys: Create a new key for the auto.share map in location baltimore. This ties the map we previously created to auto.master: ipa automountkey-add baltimore auto.master --key=/share --info=auto.share Create a new key for our auto.share map, an NFS mount for man pages: ipa automountkey-add baltimore auto.share --key=man --info="-ro,soft,rsize=8192,wsize=8192 ipa.example.com:/shared/man" Find all keys for the auto.share map: ipa automountkey-find baltimore auto.share Find all direct automount keys: ipa automountkey-find baltimore --key=/- Remove the man key from the auto.share map: ipa automountkey-del baltimore auto.share --key=man """) """ Developer notes: RFC 2707bis http://www.padl.com/~lukeh/rfc2307bis.txt A few notes on automount: - The default parent when adding an indirect map is auto.master - This uses the short format for automount maps instead of the URL format. Support for ldap as a map source in nsswitch.conf was added in autofs version 4.1.3-197. Any version prior to that is not expected to work. - An indirect key should not begin with / As an example, the following automount files: auto.master: /- auto.direct /mnt auto.mnt auto.mnt: stuff -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/archive/stuff are equivalent to the following LDAP entries: # auto.master, automount, example.com dn: automountmapname=auto.master,cn=automount,dc=example,dc=com objectClass: automountMap objectClass: top automountMapName: auto.master # auto.direct, automount, example.com dn: automountmapname=auto.direct,cn=automount,dc=example,dc=com objectClass: automountMap objectClass: top automountMapName: auto.direct # /-, auto.master, automount, example.com dn: automountkey=/-,automountmapname=auto.master,cn=automount,dc=example,dc=co m objectClass: automount objectClass: top automountKey: /- automountInformation: auto.direct # auto.mnt, automount, example.com dn: automountmapname=auto.mnt,cn=automount,dc=example,dc=com objectClass: automountMap objectClass: top automountMapName: auto.mnt # /mnt, auto.master, automount, example.com dn: automountkey=/mnt,automountmapname=auto.master,cn=automount,dc=example,dc= com objectClass: automount objectClass: top automountKey: /mnt automountInformation: auto.mnt # stuff, auto.mnt, automount, example.com dn: automountkey=stuff,automountmapname=auto.mnt,cn=automount,dc=example,dc=com objectClass: automount objectClass: top automountKey: stuff automountInformation: -ro,soft,rsize=8192,wsize=8192 nfs.example.com:/vol/arch ive/stuff """ DIRECT_MAP_KEY = u'/-' DEFAULT_MAPS = (u'auto.direct', ) DEFAULT_KEYS = (u'/-', ) class automountlocation(LDAPObject): """ Location container for automount maps. """ container_dn = api.env.container_automount object_name = _('automount location') object_name_plural = _('automount locations') object_class = ['nscontainer'] default_attributes = ['cn'] label = _('Automount Locations') label_singular = _('Automount Location') takes_params = ( Str('cn', cli_name='location', label=_('Location'), doc=_('Automount location name.'), primary_key=True, ), ) api.register(automountlocation) class automountlocation_add(LDAPCreate): __doc__ = _('Create a new automount location.') msg_summary = _('Added automount location "%(value)s"') def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # create auto.master for the new location self.api.Command['automountmap_add'](keys[-1], u'auto.master') # add additional pre-created maps and keys # IMPORTANT: add pre-created maps/keys to DEFAULT_MAPS/DEFAULT_KEYS # so that they do not cause conflicts during import operation self.api.Command['automountmap_add_indirect']( keys[-1], u'auto.direct', key=DIRECT_MAP_KEY ) return dn api.register(automountlocation_add) class automountlocation_del(LDAPDelete): __doc__ = _('Delete an automount location.') msg_summary = _('Deleted automount location "%(value)s"') api.register(automountlocation_del) class automountlocation_show(LDAPRetrieve): __doc__ = _('Display an automount location.') api.register(automountlocation_show) class automountlocation_find(LDAPSearch): __doc__ = _('Search for an automount location.') msg_summary = ngettext( '%(count)d automount location matched', '%(count)d automount locations matched', 0 ) api.register(automountlocation_find) class automountlocation_tofiles(LDAPQuery): __doc__ = _('Generate automount files for a specific location.') def execute(self, *args, **options): ldap = self.obj.backend location = self.api.Command['automountlocation_show'](args[0]) maps = [] result = self.api.Command['automountkey_find'](args[0], u'auto.master') truncated = result['truncated'] maps = result['result'] # maps, truncated # TODO: handle truncated results # ?use ldap.find_entries instead of automountkey_find? keys = {} mapnames = [u'auto.master'] for m in maps: info = m['automountinformation'][0] mapnames.append(info) key = info.split(None) result = self.api.Command['automountkey_find'](args[0], key[0]) truncated = result['truncated'] keys[info] = result['result'] # TODO: handle truncated results, same as above allmaps = self.api.Command['automountmap_find'](args[0])['result'] orphanmaps = [] for m in allmaps: if m['automountmapname'][0] not in mapnames: orphanmaps.append(m) orphankeys = [] # Collect all the keys for the orphaned maps for m in orphanmaps: key = m['automountmapname'] result = self.api.Command['automountkey_find'](args[0], key[0]) truncated = result['truncated'] orphankeys.append(result['result']) return dict(result=dict(maps=maps, keys=keys, orphanmaps=orphanmaps, orphankeys=orphankeys)) def output_for_cli(self, textui, result, *keys, **options): maps = result['result']['maps'] keys = result['result']['keys'] orphanmaps = result['result']['orphanmaps'] orphankeys = result['result']['orphankeys'] textui.print_plain('/etc/auto.master:') for m in maps: if m['automountinformation'][0].startswith('-'): textui.print_plain( '%s\t%s' % ( m['automountkey'][0], m['automountinformation'][0] ) ) else: textui.print_plain( '%s\t/etc/%s' % ( m['automountkey'][0], m['automountinformation'][0] ) ) for m in maps: if m['automountinformation'][0].startswith('-'): continue info = m['automountinformation'][0] textui.print_plain('---------------------------') textui.print_plain('/etc/%s:' % info) for k in keys[info]: textui.print_plain( '%s\t%s' % ( k['automountkey'][0], k['automountinformation'][0] ) ) textui.print_plain('') textui.print_plain(_('maps not connected to /etc/auto.master:')) for m in orphanmaps: textui.print_plain('---------------------------') textui.print_plain('/etc/%s:' % m['automountmapname']) for k in orphankeys: if len(k) == 0: continue dn = DN(k[0]['dn']) if dn['automountmapname'] == m['automountmapname'][0]: textui.print_plain( '%s\t%s' % ( k[0]['automountkey'][0], k[0]['automountinformation'][0] ) ) api.register(automountlocation_tofiles) class automountlocation_import(LDAPQuery): __doc__ = _('Import automount files for a specific location.') takes_args = ( Str('masterfile', label=_('Master file'), doc=_('Automount master file.'), ), ) takes_options = ( Flag('continue?', cli_name='continue', doc=_('Continuous operation mode. Errors are reported but the process continues.'), ), ) def __read_mapfile(self, filename): try: fp = open(filename, 'r') map = fp.readlines() fp.close() except IOError, e: if e.errno == 2: raise errors.NotFound( reason=_('File %(file)s not found') % {'file': filename} ) else: raise return map def forward(self, *args, **options): """ The basic idea is to read the master file and create all the maps we need, then read each map file and add all the keys for the map. """ location = self.api.Command['automountlocation_show'](args[0]) result = {'maps':[], 'keys':[], 'skipped':[], 'duplicatekeys':[], 'duplicatemaps':[]} maps = {} master = self.__read_mapfile(args[1]) for m in master: if m.startswith('#'): continue m = m.rstrip() if m.startswith('+'): result['skipped'].append([m,args[1]]) continue if len(m) == 0: continue am = m.split(None) if len(am) < 2: continue if am[1].startswith('/'): mapfile = am[1].replace('"','') am[1] = os.path.basename(am[1]) maps[am[1]] = mapfile info = ' '.join(am[1:]) # Add a new key to the auto.master map for the new map file try: api.Command['automountkey_add']( args[0], u'auto.master', automountkey=unicode(am[0]), automountinformation=unicode(' '.join(am[1:]))) result['keys'].append([am[0], u'auto.master']) except errors.DuplicateEntry, e: if unicode(am[0]) in DEFAULT_KEYS: # ignore conflict when the key was pre-created by the framework pass elif options.get('continue', False): result['duplicatekeys'].append(am[0]) pass else: raise errors.DuplicateEntry( message=_('key %(key)s already exists') % dict( key=am[0])) # Add the new map if not am[1].startswith('-'): try: api.Command['automountmap_add'](args[0], unicode(am[1])) result['maps'].append(am[1]) except errors.DuplicateEntry, e: if unicode(am[1]) in DEFAULT_MAPS: # ignore conflict when the map was pre-created by the framework pass elif options.get('continue', False): result['duplicatemaps'].append(am[0]) pass else: raise errors.DuplicateEntry( message=_('map %(map)s already exists') % dict( map=am[1])) except errors.DuplicateEntry: # This means the same map is used on several mount points. pass # Now iterate over the map files and add the keys. To handle # continuation lines I'll make a pass through it to skip comments # etc and also to combine lines. for m in maps: map = self.__read_mapfile(maps[m]) lines = [] cont = '' for x in map: if x.startswith('#'): continue x = x.rstrip() if x.startswith('+'): result['skipped'].append([m, maps[m]]) continue if len(x) == 0: continue if x.endswith("\\"): cont = cont + x[:-1] + ' ' else: lines.append(cont + x) cont='' for x in lines: am = x.split(None) key = unicode(am[0].replace('"','')) try: api.Command['automountkey_add']( args[0], unicode(m), automountkey=key, automountinformation=unicode(' '.join(am[1:]))) result['keys'].append([key,m]) except errors.DuplicateEntry, e: if options.get('continue', False): result['duplicatekeys'].append(am[0]) pass else: raise e return dict(result=result) def output_for_cli(self, textui, result, *keys, **options): maps = result['result']['maps'] keys = result['result']['keys'] duplicatemaps = result['result']['duplicatemaps'] duplicatekeys = result['result']['duplicatekeys'] skipped = result['result']['skipped'] textui.print_plain('Imported maps:') for m in maps: textui.print_plain( 'Added %s' % m ) textui.print_plain('') textui.print_plain('Imported keys:') for k in keys: textui.print_plain( 'Added %s to %s' % ( k[0], k[1] ) ) textui.print_plain('') if len(skipped) > 0: textui.print_plain('Ignored keys:') for k in skipped: textui.print_plain( 'Ignored %s to %s' % ( k[0], k[1] ) ) if options.get('continue', False) and len(duplicatemaps) > 0: textui.print_plain('') textui.print_plain('Duplicate maps skipped:') for m in duplicatemaps: textui.print_plain( 'Skipped %s' % m ) if options.get('continue', False) and len(duplicatekeys) > 0: textui.print_plain('') textui.print_plain('Duplicate keys skipped:') for k in duplicatekeys: textui.print_plain( 'Skipped %s' % k ) api.register(automountlocation_import) class automountmap(LDAPObject): """ Automount map object. """ parent_object = 'automountlocation' container_dn = api.env.container_automount object_name = _('automount map') object_name_plural = _('automount maps') object_class = ['automountmap'] default_attributes = ['automountmapname', 'description'] takes_params = ( IA5Str('automountmapname', cli_name='map', label=_('Map'), doc=_('Automount map name.'), primary_key=True, ), Str('description?', cli_name='desc', label=_('Description'), ), ) label = _('Automount Maps') label_singular = _('Automount Map') api.register(automountmap) class automountmap_add(LDAPCreate): __doc__ = _('Create a new automount map.') msg_summary = _('Added automount map "%(value)s"') api.register(automountmap_add) class automountmap_del(LDAPDelete): __doc__ = _('Delete an automount map.') msg_summary = _('Deleted automount map "%(value)s"') def post_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # delete optional parental connection (direct maps may not have this) try: (dn_, entry_attrs) = ldap.find_entry_by_attr( 'automountinformation', keys[0], 'automount', base_dn=DN(self.obj.container_dn, api.env.basedn) ) ldap.delete_entry(dn_) except errors.NotFound: pass return True api.register(automountmap_del) class automountmap_mod(LDAPUpdate): __doc__ = _('Modify an automount map.') msg_summary = _('Modified automount map "%(value)s"') api.register(automountmap_mod) class automountmap_find(LDAPSearch): __doc__ = _('Search for an automount map.') msg_summary = ngettext( '%(count)d automount map matched', '%(count)d automount maps matched', 0 ) api.register(automountmap_find) class automountmap_show(LDAPRetrieve): __doc__ = _('Display an automount map.') api.register(automountmap_show) class automountkey(LDAPObject): __doc__ = _('Automount key object.') parent_object = 'automountmap' container_dn = api.env.container_automount object_name = _('automount key') object_name_plural = _('automount keys') object_class = ['automount'] default_attributes = [ 'automountkey', 'automountinformation', 'description' ] rdn_is_primary_key = True rdn_separator = ' ' takes_params = ( IA5Str('automountkey', cli_name='key', label=_('Key'), doc=_('Automount key name.'), flags=('req_update',), ), IA5Str('automountinformation', cli_name='info', label=_('Mount information'), ), Str('description', label=_('description'), primary_key=True, required=False, flags=['no_create', 'no_update', 'no_search', 'no_output'], exclude='webui', ), ) num_parents = 2 label = _('Automount Keys') label_singular = _('Automount Key') already_exists_msg = _('The key,info pair must be unique. A key named %(key)s with info %(info)s already exists') key_already_exists_msg = _('key named %(key)s already exists') object_not_found_msg = _('The automount key %(key)s with info %(info)s does not exist') def get_dn(self, *keys, **kwargs): # all commands except for create send pk in keys, too # create cannot due to validation in frontend.py ldap = self.backend if len(keys) == self.num_parents: try: pkey = kwargs[self.primary_key.name] except KeyError: raise ValueError('Not enough keys and pkey not in kwargs') parent_keys = keys else: pkey = keys[-1] parent_keys = keys[:-1] parent_dn = self.api.Object[self.parent_object].get_dn(*parent_keys) dn = self.backend.make_dn_from_attr( self.primary_key.name, pkey, parent_dn ) # If we're doing an add then just return the dn we created, there # is no need to check for it. if kwargs.get('add_operation', False): return dn # We had an older mechanism where description consisted of # 'automountkey automountinformation' so we could support multiple # direct maps. This made showing keys nearly impossible since it # required automountinfo to show, which if you had you didn't need # to look at the key. We still support existing entries but now # only create this type of dn when the key is /- # # First we look with the information given, then try to search for # the right entry. try: (dn, entry_attrs) = ldap.get_entry(dn, ['*']) except errors.NotFound: if kwargs.get('automountinformation', False): sfilter = '(&(automountkey=%s)(automountinformation=%s))' % \ (kwargs['automountkey'], kwargs['automountinformation']) else: sfilter = '(automountkey=%s)' % kwargs['automountkey'] basedn = DN(('automountmapname', parent_keys[1]), ('cn', parent_keys[0]), self.container_dn, api.env.basedn) attrs_list = ['*'] entries, truncated = ldap.find_entries( sfilter, attrs_list, basedn, ldap.SCOPE_ONELEVEL) if len(entries) > 1: raise errors.NotFound(reason=_('More than one entry with key %(key)s found, use --info to select specific entry.') % dict(key=pkey)) if truncated: raise errors.LimitsExceeded() dn = entries[0][0] return dn def handle_not_found(self, *keys): pkey = keys[-1] key = pkey.split(self.rdn_separator)[0] info = self.rdn_separator.join(pkey.split(self.rdn_separator)[1:]) raise errors.NotFound( reason=self.object_not_found_msg % { 'key': key, 'info': info, } ) def handle_duplicate_entry(self, *keys): pkey = keys[-1] key = pkey.split(self.rdn_separator)[0] info = self.rdn_separator.join(pkey.split(self.rdn_separator)[1:]) if info: raise errors.DuplicateEntry( message=self.already_exists_msg % { 'key': key, 'info': info, } ) else: raise errors.DuplicateEntry( message=self.key_already_exists_msg % { 'key': key, } ) def get_pk(self, key, info=None): if key == DIRECT_MAP_KEY and info: return self.rdn_separator.join((key,info)) else: return key def check_key_uniqueness(self, location, map, **keykw): info = None key = keykw.get('automountkey') if key is None: return entries = self.methods.find(location, map, automountkey=key)['result'] if len(entries) > 0: if key == DIRECT_MAP_KEY: info = keykw.get('automountinformation') entries = self.methods.find(location, map, **keykw)['result'] if len(entries) > 0: self.handle_duplicate_entry(location, map, self.get_pk(key, info)) else: return self.handle_duplicate_entry(location, map, self.get_pk(key, info)) api.register(automountkey) class automountkey_add(LDAPCreate): __doc__ = _('Create a new automount key.') msg_summary = _('Added automount key "%(value)s"') internal_options = ['description', 'add_operation'] def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) options.pop('add_operation', None) options.pop('description', None) self.obj.check_key_uniqueness(keys[-2], keys[-1], **options) return dn def get_args(self): for key in self.obj.get_ancestor_primary_keys(): yield key def execute(self, *keys, **options): key = options['automountkey'] info = options.get('automountinformation', None) options[self.obj.primary_key.name] = self.obj.get_pk(key, info) options['add_operation'] = True result = super(automountkey_add, self).execute(*keys, **options) result['value'] = options['automountkey'] return result api.register(automountkey_add) class automountmap_add_indirect(LDAPCreate): __doc__ = _('Create a new indirect mount point.') msg_summary = _('Added automount indirect map "%(value)s"') takes_options = LDAPCreate.takes_options + ( Str('key', cli_name='mount', label=_('Mount point'), ), Str('parentmap?', cli_name='parentmap', label=_('Parent map'), doc=_('Name of parent automount map (default: auto.master).'), default=u'auto.master', autofill=True, ), ) def execute(self, *keys, **options): parentmap = options.pop('parentmap', None) key = options.pop('key') result = self.api.Command['automountmap_add'](*keys, **options) try: if parentmap != u'auto.master': if key.startswith('/'): raise errors.ValidationError(name='mount', error=_('mount point is relative to parent map, ' 'cannot begin with /')) location = keys[0] map = keys[1] options['automountinformation'] = map # Ensure the referenced map exists self.api.Command['automountmap_show'](location, parentmap) # Add a submount key self.api.Command['automountkey_add']( location, parentmap, automountkey=key, automountinformation='-fstype=autofs ldap:%s' % map) else: # adding to auto.master # Ensure auto.master exists self.api.Command['automountmap_show'](keys[0], parentmap) self.api.Command['automountkey_add']( keys[0], u'auto.master', automountkey=key, automountinformation=keys[1]) except Exception: # The key exists, drop the map self.api.Command['automountmap_del'](*keys) raise return result api.register(automountmap_add_indirect) class automountkey_del(LDAPDelete): __doc__ = _('Delete an automount key.') msg_summary = _('Deleted automount key "%(value)s"') takes_options = LDAPDelete.takes_options + ( IA5Str('automountkey', cli_name='key', label=_('Key'), doc=_('Automount key name.'), ), IA5Str('automountinformation?', cli_name='info', label=_('Mount information'), ), ) def get_options(self): for option in super(automountkey_del, self).get_options(): if option.name == 'continue': # TODO: hide for now - remove in future major release yield option.clone(exclude='webui', flags=['no_option', 'no_output']) else: yield option def get_args(self): for key in self.obj.get_ancestor_primary_keys(): yield key def execute(self, *keys, **options): keys += (self.obj.get_pk(options['automountkey'], options.get('automountinformation', None)),) options[self.obj.primary_key.name] = self.obj.get_pk( options['automountkey'], options.get('automountinformation', None)) result = super(automountkey_del, self).execute(*keys, **options) result['value'] = options['automountkey'] return result api.register(automountkey_del) class automountkey_mod(LDAPUpdate): __doc__ = _('Modify an automount key.') msg_summary = _('Modified automount key "%(value)s"') internal_options = ['newautomountkey'] takes_options = LDAPUpdate.takes_options + ( IA5Str('newautomountinformation?', cli_name='newinfo', label=_('New mount information'), ), ) def get_args(self): for key in self.obj.get_ancestor_primary_keys(): yield key def pre_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if 'newautomountkey' in options: entry_attrs['automountkey'] = options['newautomountkey'] if 'newautomountinformation' in options: entry_attrs['automountinformation'] = options['newautomountinformation'] return dn def execute(self, *keys, **options): ldap = self.api.Backend.ldap2 key = options['automountkey'] info = options.get('automountinformation', None) keys += (self.obj.get_pk(key, info), ) # handle RDN changes if 'rename' in options or 'newautomountinformation' in options: new_key = options.get('rename', key) new_info = options.get('newautomountinformation', info) if new_key == DIRECT_MAP_KEY and not new_info: # automountinformation attribute of existing LDAP object needs # to be retrieved so that RDN can be generated dn = self.obj.get_dn(*keys, **options) (dn_, entry_attrs_) = ldap.get_entry(dn, ['automountinformation']) new_info = entry_attrs_.get('automountinformation', [])[0] # automounkey attribute cannot be overwritten so that get_dn() # still works right options['newautomountkey'] = new_key new_rdn = self.obj.get_pk(new_key, new_info) if new_rdn != keys[-1]: options['rename'] = new_rdn result = super(automountkey_mod, self).execute(*keys, **options) result['value'] = options['automountkey'] return result api.register(automountkey_mod) class automountkey_find(LDAPSearch): __doc__ = _('Search for an automount key.') msg_summary = ngettext( '%(count)d automount key matched', '%(count)d automount keys matched', 0 ) api.register(automountkey_find) class automountkey_show(LDAPRetrieve): __doc__ = _('Display an automount key.') takes_options = LDAPRetrieve.takes_options + ( IA5Str('automountkey', cli_name='key', label=_('Key'), doc=_('Automount key name.'), ), IA5Str('automountinformation?', cli_name='info', label=_('Mount information'), ), ) def get_args(self): for key in self.obj.get_ancestor_primary_keys(): yield key def execute(self, *keys, **options): keys += (self.obj.get_pk(options['automountkey'], options.get('automountinformation', None)), ) options[self.obj.primary_key.name] = self.obj.get_pk( options['automountkey'], options.get('automountinformation', None)) result = super(automountkey_show, self).execute(*keys, **options) result['value'] = options['automountkey'] return result api.register(automountkey_show) freeipa-3.3.4/ipalib/plugins/sudocmd.pyc0000664000175000017500000001166612271707517017621 0ustar mkosekmkosekó †fçRc@sdddlZddlZddlZddlmZmZmZddlmZddlTddlm Z m Z e dƒZ de dƒfZ d e fd „ƒYZejeƒd efd „ƒYZejeƒd efd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdS(iÿÿÿÿN(tapiterrorstutil(tStr(t*(t_tngettextsÑ Sudo Commands Commands used as building blocks for sudo EXAMPLES: Create a new command ipa sudocmd-add --desc='For reading log files' /usr/bin/less Remove a command ipa sudocmd-del /usr/bin/less tsudos+commands for controlling sudo configurationtsudocmdc BsäeZdZejjZedƒZedƒZ ddgZ ddgZ dddgZ idgd6Z d Zd Zed ƒZed ƒZedd d ded ƒdeƒedd ddedƒdedƒƒfZd„ZRS(s Sudo Command object. s sudo commands sudo commandst ipaobjectt ipasudocmdRt descriptiontmemberoft sudocmdgroupt ipauniqueids Sudo Commandss Sudo Commandtcli_nametcommandtlabelt primary_keys description?tdesct DescriptiontdocsA description of this commandcOsÓ|djdƒr(|dd |d((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyt pre_callbackps*"  (  (R)R*RR+R8RT(((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyR9ks  t sudocmd_modcBs eZedƒZedƒZRS(sModify Sudo Command.s!Modified Sudo Command "%(value)s"(R)R*RR+R8(((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyRUŒs t sudocmd_findcBs&eZedƒZedddƒZRS(sSearch for Sudo Commands.s%(count)d Sudo Command matcheds%(count)d Sudo Commands matchedi(R)R*RR+RR8(((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyRV“s t sudocmd_showcBseZedƒZRS(sDisplay Sudo Command.(R)R*RR+(((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyRWœs(tplatformtostsystipalibRRRRtipalib.plugins.baseldapRRR+ttopict LDAPObjectRtregistert LDAPCreateR7t LDAPDeleteR9t LDAPUpdateRUt LDAPSearchRVt LDAPRetrieveRW(((s4/home/mkosek/freeipa-clean/ipalib/plugins/sudocmd.pyts*     4     freeipa-3.3.4/ipalib/plugins/cert.py0000664000175000017500000005704112271663206016746 0ustar mkosekmkosek# Authors: # Andrew Wnuk # Jason Gerard DeRose # John Dennis # # Copyright (C) 2009 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 . from ipalib import api, SkipPluginModule if api.env.enable_ra is not True: # In this case, abort loading this plugin module... raise SkipPluginModule(reason='env.enable_ra is not True') import os import time from ipalib import Command, Str, Int, Bytes, Flag, File from ipalib import errors from ipalib import pkcs10 from ipalib import x509 from ipalib import util from ipalib import ngettext from ipalib.plugins.virtual import * from ipalib.plugins.service import split_principal import base64 import traceback from ipalib.text import _ from ipalib.request import context from ipalib import output from ipalib.plugins.service import validate_principal import nss.nss as nss from nss.error import NSPRError __doc__ = _(""" IPA certificate operations Implements a set of commands for managing server SSL certificates. Certificate requests exist in the form of a Certificate Signing Request (CSR) in PEM format. The dogtag CA uses just the CN value of the CSR and forces the rest of the subject to values configured in the server. A certificate is stored with a service principal and a service principal needs a host. In order to request a certificate: * The host must exist * The service must exist (or you use the --add option to automatically add it) SEARCHING: Certificates may be searched on by certificate subject, serial number, revocation reason, validity dates and the issued date. When searching on dates the _from date does a >= search and the _to date does a <= search. When combined these are done as an AND. Dates are treated as GMT to match the dates in the certificates. The date format is YYYY-mm-dd. EXAMPLES: Request a new certificate and add the principal: ipa cert-request --add --principal=HTTP/lion.example.com example.csr Retrieve an existing certificate: ipa cert-show 1032 Revoke a certificate (see RFC 5280 for reason details): ipa cert-revoke --revocation-reason=6 1032 Remove a certificate from revocation hold status: ipa cert-remove-hold 1032 Check the status of a signing request: ipa cert-status 10 Search for certificates by hostname: ipa cert-find --subject=ipaserver.example.com Search for revoked certificates by reason: ipa cert-find --revocation-reason=5 Search for certificates based on issuance date ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07 IPA currently immediately issues (or declines) all certificate requests so the status of a request is not normally useful. This is for future use or the case where a CA does not immediately issue a certificate. The following revocation reasons are supported: * 0 - unspecified * 1 - keyCompromise * 2 - cACompromise * 3 - affiliationChanged * 4 - superseded * 5 - cessationOfOperation * 6 - certificateHold * 8 - removeFromCRL * 9 - privilegeWithdrawn * 10 - aACompromise Note that reason code 7 is not used. See RFC 5280 for more details: http://www.ietf.org/rfc/rfc5280.txt """) def validate_pkidate(ugettext, value): """ A date in the format of %Y-%m-%d """ try: ts = time.strptime(value, '%Y-%m-%d') except ValueError, e: return str(e) return None def get_csr_hostname(csr): """ Return the value of CN in the subject of the request or None """ try: request = pkcs10.load_certificate_request(csr) subject = pkcs10.get_subject(request) return subject.common_name except NSPRError, nsprerr: raise errors.CertificateOperationError( error=_('Failure decoding Certificate Signing Request: %s') % nsprerr) def get_subjectaltname(csr): """ Return the first value of the subject alt name, if any """ try: request = pkcs10.load_certificate_request(csr) for extension in request.extensions: if extension.oid_tag == nss.SEC_OID_X509_SUBJECT_ALT_NAME: return nss.x509_alt_name(extension.value)[0] return None except NSPRError, nsprerr: raise errors.CertificateOperationError( error=_('Failure decoding Certificate Signing Request: %s') % nsprerr) def validate_csr(ugettext, csr): """ Ensure the CSR is base64-encoded and can be decoded by our PKCS#10 parser. """ if api.env.context == 'cli': # If we are passed in a pointer to a valid file on the client side # escape and let the load_files() handle things if csr and os.path.exists(csr): return try: request = pkcs10.load_certificate_request(csr) except TypeError, e: raise errors.Base64DecodeError(reason=str(e)) except Exception, e: raise errors.CertificateOperationError(error=_('Failure decoding Certificate Signing Request: %s') % e) def normalize_csr(csr): """ Strip any leading and trailing cruft around the BEGIN/END block """ end_len = 37 s = csr.find('-----BEGIN NEW CERTIFICATE REQUEST-----') if s == -1: s = csr.find('-----BEGIN CERTIFICATE REQUEST-----') e = csr.find('-----END NEW CERTIFICATE REQUEST-----') if e == -1: e = csr.find('-----END CERTIFICATE REQUEST-----') if e != -1: end_len = 33 if s > -1 and e > -1: # We're normalizing here, not validating csr = csr[s:e+end_len] return csr def _convert_serial_number(num): """ Convert a SN given in decimal or hexadecimal. Returns the number or None if conversion fails. """ # plain decimal or hexa with radix prefix try: num = int(num, 0) except ValueError: try: # hexa without prefix num = int(num, 16) except ValueError: num = None return num def validate_serial_number(ugettext, num): if _convert_serial_number(num) == None: return u"Decimal or hexadecimal number is required for serial number" return None def normalize_serial_number(num): # It's been already validated return unicode(_convert_serial_number(num)) def get_host_from_principal(principal): """ Given a principal with or without a realm return the host portion. """ validate_principal(None, principal) realm = principal.find('@') slash = principal.find('/') if realm == -1: realm = len(principal) hostname = principal[slash+1:realm] return hostname class cert_request(VirtualCommand): __doc__ = _('Submit a certificate signing request.') takes_args = ( File('csr', validate_csr, label=_('CSR'), cli_name='csr_file', normalizer=normalize_csr, ), ) operation="request certificate" takes_options = ( Str('principal', label=_('Principal'), doc=_('Service principal for this certificate (e.g. HTTP/test.example.com)'), ), Str('request_type', default=u'pkcs10', autofill=True, ), Flag('add', doc=_("automatically add the principal if it doesn't exist"), default=False, autofill=True ), ) has_output_params = ( Str('certificate', label=_('Certificate'), ), Str('subject', label=_('Subject'), ), Str('issuer', label=_('Issuer'), ), Str('valid_not_before', label=_('Not Before'), ), Str('valid_not_after', label=_('Not After'), ), Str('md5_fingerprint', label=_('Fingerprint (MD5)'), ), Str('sha1_fingerprint', label=_('Fingerprint (SHA1)'), ), Str('serial_number', label=_('Serial number'), ), Str('serial_number_hex', label=_('Serial number (hex)'), ), ) has_output = ( output.Output('result', type=dict, doc=_('Dictionary mapping variable name to value'), ), ) def execute(self, csr, **kw): ldap = self.api.Backend.ldap2 principal = kw.get('principal') add = kw.get('add') request_type = kw.get('request_type') service = None """ Access control is partially handled by the ACI titled 'Hosts can modify service userCertificate'. This is for the case where a machine binds using a host/ prinicpal. It can only do the request if the target hostname is in the managedBy attribute which is managed using the add/del member commands. Binding with a user principal one needs to be in the request_certs taskgroup (directly or indirectly via role membership). """ bind_principal = getattr(context, 'principal') # Can this user request certs? if not bind_principal.startswith('host/'): self.check_access() # FIXME: add support for subject alt name # Ensure that the hostname in the CSR matches the principal subject_host = get_csr_hostname(csr) if not subject_host: raise errors.ValidationError(name='csr', error=_("No hostname was found in subject of request.")) (servicename, hostname, realm) = split_principal(principal) if subject_host.lower() != hostname.lower(): raise errors.ACIError( info=_("hostname in subject of request '%(subject_host)s' " "does not match principal hostname '%(hostname)s'") % dict( subject_host=subject_host, hostname=hostname)) dn = None service = None # See if the service exists and punt if it doesn't and we aren't # going to add it try: if not principal.startswith('host/'): service = api.Command['service_show'](principal, all=True)['result'] dn = service['dn'] else: hostname = get_host_from_principal(principal) service = api.Command['host_show'](hostname, all=True)['result'] dn = service['dn'] except errors.NotFound, e: if not add: raise errors.NotFound(reason=_("The service principal for " "this request doesn't exist.")) try: service = api.Command['service_add'](principal, **{'force': True})['result'] dn = service['dn'] except errors.ACIError: raise errors.ACIError(info=_('You need to be a member of ' 'the serviceadmin role to add services')) # We got this far so the service entry exists, can we write it? if not ldap.can_write(dn, "usercertificate"): raise errors.ACIError(info=_("Insufficient 'write' privilege " "to the 'userCertificate' attribute of entry '%s'.") % dn) # Validate the subject alt name, if any request = pkcs10.load_certificate_request(csr) subjectaltname = pkcs10.get_subjectaltname(request) if subjectaltname is not None: for name in subjectaltname: name = unicode(name) try: hostentry = api.Command['host_show'](name, all=True)['result'] hostdn = hostentry['dn'] except errors.NotFound: # We don't want to issue any certificates referencing # machines we don't know about. Nothing is stored in this # host record related to this certificate. raise errors.NotFound(reason=_('no host record for ' 'subject alt name %s in certificate request') % name) authprincipal = getattr(context, 'principal') if authprincipal.startswith("host/"): if not hostdn in service.get('managedby_host', []): raise errors.ACIError(info=_( "Insufficient privilege to create a certificate " "with subject alt name '%s'.") % name) if 'usercertificate' in service: serial = x509.get_serial_number(service['usercertificate'][0], datatype=x509.DER) # revoke the certificate and remove it from the service # entry before proceeding. First we retrieve the certificate to # see if it is already revoked, if not then we revoke it. try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement get pass if not principal.startswith('host/'): api.Command['service_mod'](principal, usercertificate=None) else: hostname = get_host_from_principal(principal) api.Command['host_mod'](hostname, usercertificate=None) # Request the certificate result = self.Backend.ra.request_certificate( csr, request_type=request_type) cert = x509.load_certificate(result['certificate']) result['issuer'] = unicode(cert.issuer) result['valid_not_before'] = unicode(cert.valid_not_before_str) result['valid_not_after'] = unicode(cert.valid_not_after_str) result['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) result['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) # Success? Then add it to the service entry. if 'certificate' in result: if not principal.startswith('host/'): skw = {"usercertificate": str(result.get('certificate'))} api.Command['service_mod'](principal, **skw) else: hostname = get_host_from_principal(principal) skw = {"usercertificate": str(result.get('certificate'))} api.Command['host_mod'](hostname, **skw) return dict( result=result ) api.register(cert_request) class cert_status(VirtualCommand): __doc__ = _('Check the status of a certificate signing request.') takes_args = ( Str('request_id', label=_('Request id'), flags=['no_create', 'no_update', 'no_search'], ), ) has_output_params = ( Str('cert_request_status', label=_('Request status'), ), ) operation = "certificate status" def execute(self, request_id, **kw): self.check_access() return dict( result=self.Backend.ra.check_request_status(request_id) ) api.register(cert_status) _serial_number = Str('serial_number', validate_serial_number, label=_('Serial number'), doc=_('Serial number in decimal or if prefixed with 0x in hexadecimal'), normalizer=normalize_serial_number, ) class cert_show(VirtualCommand): __doc__ = _('Retrieve an existing certificate.') takes_args = _serial_number has_output_params = ( Str('certificate', label=_('Certificate'), ), Str('subject', label=_('Subject'), ), Str('issuer', label=_('Issuer'), ), Str('valid_not_before', label=_('Not Before'), ), Str('valid_not_after', label=_('Not After'), ), Str('md5_fingerprint', label=_('Fingerprint (MD5)'), ), Str('sha1_fingerprint', label=_('Fingerprint (SHA1)'), ), Str('revocation_reason', label=_('Revocation reason'), ), Str('serial_number_hex', label=_('Serial number (hex)'), ), ) takes_options = ( Str('out?', label=_('Output filename'), doc=_('File to store the certificate in.'), exclude='webui', ), ) operation="retrieve certificate" def execute(self, serial_number, **options): hostname = None try: self.check_access() except errors.ACIError, acierr: self.debug("Not granted by ACI to retrieve certificate, looking at principal") bind_principal = getattr(context, 'principal') if not bind_principal.startswith('host/'): raise acierr hostname = get_host_from_principal(bind_principal) result=self.Backend.ra.get_certificate(serial_number) cert = x509.load_certificate(result['certificate']) result['subject'] = unicode(cert.subject) result['issuer'] = unicode(cert.issuer) result['valid_not_before'] = unicode(cert.valid_not_before_str) result['valid_not_after'] = unicode(cert.valid_not_after_str) result['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) result['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) if hostname: # If we have a hostname we want to verify that the subject # of the certificate matches it, otherwise raise an error if hostname != cert.subject.common_name: #pylint: disable=E1101 raise acierr return dict(result=result) def forward(self, *keys, **options): if 'out' in options: util.check_writable_file(options['out']) result = super(cert_show, self).forward(*keys, **options) if 'certificate' in result['result']: x509.write_certificate(result['result']['certificate'], options['out']) return result else: raise errors.NoCertificateError(entry=keys[-1]) else: return super(cert_show, self).forward(*keys, **options) api.register(cert_show) class cert_revoke(VirtualCommand): __doc__ = _('Revoke a certificate.') takes_args = _serial_number has_output_params = ( Flag('revoked', label=_('Revoked'), ), ) operation = "revoke certificate" # FIXME: The default is 0. Is this really an Int param? takes_options = ( Int('revocation_reason', label=_('Reason'), doc=_('Reason for revoking the certificate (0-10)'), minvalue=0, maxvalue=10, default=0, autofill=True ), ) def execute(self, serial_number, **kw): hostname = None try: self.check_access() except errors.ACIError, acierr: self.debug("Not granted by ACI to revoke certificate, looking at principal") try: # Let cert_show() handle verifying that the subject of the # cert we're dealing with matches the hostname in the principal result = api.Command['cert_show'](unicode(serial_number))['result'] except errors.NotImplementedError: pass revocation_reason = kw['revocation_reason'] if revocation_reason == 7: raise errors.CertificateOperationError(error=_('7 is not a valid revocation reason')) return dict( result=self.Backend.ra.revoke_certificate( serial_number, revocation_reason=revocation_reason) ) api.register(cert_revoke) class cert_remove_hold(VirtualCommand): __doc__ = _('Take a revoked certificate off hold.') takes_args = _serial_number has_output_params = ( Flag('unrevoked', label=_('Unrevoked'), ), Str('error_string', label=_('Error'), ), ) operation = "certificate remove hold" def execute(self, serial_number, **kw): self.check_access() return dict( result=self.Backend.ra.take_certificate_off_hold(serial_number) ) api.register(cert_remove_hold) class cert_find(Command): __doc__ = _('Search for existing certificates.') takes_options = ( Str('subject?', label=_('Subject'), doc=_('Subject'), autofill=False, ), Int('revocation_reason?', label=_('Reason'), doc=_('Reason for revoking the certificate (0-10)'), minvalue=0, maxvalue=10, autofill=False, ), Int('min_serial_number?', doc=_("minimum serial number"), autofill=False, minvalue=0, ), Int('max_serial_number?', doc=_("maximum serial number"), autofill=False, maxvalue=2147483647, ), Flag('exactly?', doc=_('match the common name exactly'), autofill=False, ), Str('validnotafter_from?', validate_pkidate, doc=_('Valid not after from this date (YYYY-mm-dd)'), autofill=False, ), Str('validnotafter_to?', validate_pkidate, doc=_('Valid not after to this date (YYYY-mm-dd)'), autofill=False, ), Str('validnotbefore_from?', validate_pkidate, doc=_('Valid not before from this date (YYYY-mm-dd)'), autofill=False, ), Str('validnotbefore_to?', validate_pkidate, doc=_('Valid not before to this date (YYYY-mm-dd)'), autofill=False, ), Str('issuedon_from?', validate_pkidate, doc=_('Issued on from this date (YYYY-mm-dd)'), autofill=False, ), Str('issuedon_to?', validate_pkidate, doc=_('Issued on to this date (YYYY-mm-dd)'), autofill=False, ), Str('revokedon_from?', validate_pkidate, doc=_('Revoked on from this date (YYYY-mm-dd)'), autofill=False, ), Str('revokedon_to?', validate_pkidate, doc=_('Revoked on to this date (YYYY-mm-dd)'), autofill=False, ), Int('sizelimit?', label=_('Size Limit'), doc=_('Maximum number of certs returned'), flags=['no_display'], minvalue=0, default=100, ), ) has_output = output.standard_list_of_entries has_output_params = ( Str('serial_number_hex', label=_('Serial number (hex)'), ), Str('serial_number', label=_('Serial number'), ), Str('status', label=_('Status'), ), ) msg_summary = ngettext( '%(count)d certificate matched', '%(count)d certificates matched', 0 ) def execute(self, **options): ret = dict( result=self.Backend.ra.find(options) ) ret['count'] = len(ret['result']) ret['truncated'] = False return ret api.register(cert_find) freeipa-3.3.4/ipalib/plugins/realmdomains.py0000664000175000017500000001472612271663206020467 0ustar mkosekmkosek# Authors: # Ana Krivokapic # # Copyright (C) 2013 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 . from ipalib import api, errors from ipalib import Str, Flag from ipalib import _ from ipalib.plugins.baseldap import LDAPObject, LDAPUpdate, LDAPRetrieve from ipalib.plugins.dns import _domain_name_validator from ipalib.util import has_soa_or_ns_record from ipapython.dn import DN from ipapython.ipautil import get_domain_name __doc__ = _(""" Realm domains Manage the list of domains associated with IPA realm. EXAMPLES: Display the current list of realm domains: ipa realmdomains-show Replace the list of realm domains: ipa realmdomains-mod --domain=example.com ipa realmdomains-mod --domain={example1.com,example2.com,example3.com} Add a domain to the list of realm domains: ipa realmdomains-mod --add-domain=newdomain.com Delete a domain from the list of realm domains: ipa realmdomains-mod --del-domain=olddomain.com """) def _domain_name_normalizer(d): return d.lower().rstrip('.') class realmdomains(LDAPObject): """ List of domains associated with IPA realm. """ container_dn = api.env.container_realm_domains object_name = _('Realm domains') search_attributes = ['associateddomain'] default_attributes = ['associateddomain'] label = _('Realm Domains') label_singular = _('Realm Domains') takes_params = ( Str('associateddomain+', _domain_name_validator, normalizer=_domain_name_normalizer, cli_name='domain', label=_('Domain'), ), Str('add_domain?', _domain_name_validator, normalizer=_domain_name_normalizer, cli_name='add_domain', label=_('Add domain'), ), Str('del_domain?', _domain_name_validator, normalizer=_domain_name_normalizer, cli_name='del_domain', label=_('Delete domain'), ), ) api.register(realmdomains) class realmdomains_mod(LDAPUpdate): __doc__ = _('Modify realm domains.') takes_options = LDAPUpdate.takes_options + ( Flag('force', label=_('Force'), doc=_('Force adding domain even if not in DNS'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) associateddomain = entry_attrs.get('associateddomain') add_domain = entry_attrs.get('add_domain') del_domain = entry_attrs.get('del_domain') force = options.get('force') if associateddomain: if add_domain or del_domain: raise errors.MutuallyExclusiveError(reason=_("you cannot specify the --domain option together with --add-domain or --del-domain")) if get_domain_name() not in associateddomain: raise errors.ValidationError(name='domain', error=_("cannot delete domain of IPA server")) if not force: bad_domains = [d for d in associateddomain if not has_soa_or_ns_record(d)] if bad_domains: bad_domains = ', '.join(bad_domains) raise errors.ValidationError(name='domain', error=_("no SOA or NS records found for domains: %s" % bad_domains)) return dn # If --add-domain or --del-domain options were provided, read # the curent list from LDAP, modify it, and write the changes back domains = ldap.get_entry(dn)[1]['associateddomain'] if add_domain: if not force and not has_soa_or_ns_record(add_domain): raise errors.ValidationError(name='add_domain', error=_("no SOA or NS records found for domain %s" % add_domain)) del entry_attrs['add_domain'] domains.append(add_domain) if del_domain: if del_domain == get_domain_name(): raise errors.ValidationError(name='del_domain', error=_("cannot delete domain of IPA server")) del entry_attrs['del_domain'] try: domains.remove(del_domain) except ValueError: raise errors.AttrValueNotFound(attr='associateddomain', value=del_domain) entry_attrs['associateddomain'] = domains return dn def execute(self, *keys, **options): dn = self.obj.get_dn(*keys, **options) ldap = self.obj.backend domains_old = set(ldap.get_entry(dn)[1]['associateddomain']) result = super(realmdomains_mod, self).execute(*keys, **options) domains_new = set(ldap.get_entry(dn)[1]['associateddomain']) domains_added = domains_new - domains_old domains_deleted = domains_old - domains_new # Add a _kerberos TXT record for zones that correspond with # domains which were added for d in domains_added: # Skip our own domain if d == api.env.domain: continue try: api.Command['dnsrecord_add']( unicode(d), u'_kerberos', txtrecord=api.env.realm ) except (errors.EmptyModlist, errors.NotFound): pass # Delete _kerberos TXT record from zones that correspond with # domains which were deleted for d in domains_deleted: # Skip our own domain if d == api.env.domain: continue try: api.Command['dnsrecord_del']( unicode(d), u'_kerberos', txtrecord=api.env.realm ) except (errors.AttrValueNotFound, errors.NotFound): pass return result api.register(realmdomains_mod) class realmdomains_show(LDAPRetrieve): __doc__ = _('Display the list of realm domains.') api.register(realmdomains_show) freeipa-3.3.4/ipalib/plugins/virtual.pyc0000664000175000017500000000402212271707517017635 0ustar mkosekmkosekó ­8 Rc@spdZddlmZddlmZddlmZddlmZddlmZdefd„ƒYZ d S( s, Base classes for non-LDAP backend plugins. iÿÿÿÿ(tapi(tCommand(terrors(tDN(t_tVirtualCommandcBs eZdZdZdd„ZRS(sÅ A command that doesn't use the LDAP backend but wants to use the LDAP access control system to make authorization decisions. The class variable operation is the commonName attribute of the entry to be tested against. In advance, you need to create an entry of the form: cn=, api.env.container_virtual, api.env.basedn Ex. cn=request certificate, cn=virtual operations,cn=etc, dc=example, dc=com cCsÿ|jdkr6|dkr6tjdtdƒƒ‚n|dkrN|j}n|jjj}|jj d|ƒt d|f|jj j |jj j ƒ}y1|j|dƒsËtjdtdƒƒ‚nWn,tjk rútjdtdƒƒ‚nXtS( s„ Perform an LDAP query to determine authorization. This should be executed before any actual work is done. tinfosoperation not definedsIPA: virtual verify %stcnt objectclasss#not allowed to perform this commandsNo such virtual commandN(t operationtNoneRtACIErrorRRtBackendtldap2tlogtdebugRtenvtcontainer_virtualtbasednt can_writetNotFoundtTrue(tselfR tldapt operationdn((s4/home/mkosek/freeipa-clean/ipalib/plugins/virtual.pyt check_access-s  * N(t__name__t __module__t__doc__R R R(((s4/home/mkosek/freeipa-clean/ipalib/plugins/virtual.pyRs N( RtipalibRRRt ipapython.dnRt ipalib.textRR(((s4/home/mkosek/freeipa-clean/ipalib/plugins/virtual.pyts freeipa-3.3.4/ipalib/plugins/selinuxusermap.pyc0000664000175000017500000004346412271707517021250 0ustar mkosekmkosekó †fçRc@s4ddlmZmZddlmZmZmZddlTddlmZmZddl m Z edƒZ edƒZ d„Z d „Zd efd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZ eje ƒde!fd„ƒYZ"eje"ƒdefd„ƒYZ#eje#ƒd e!fd!„ƒYZ$eje$ƒd"S(#iÿÿÿÿ(tapiterrors(tStrtStrEnumtBool(t*(t_tngettext(tis_allsü SELinux User Mapping Map IPA users to SELinux users by host. Hosts, hostgroups, users and groups can be either defined within the rule or it may point to an existing HBAC rule. When using --hbacrule option to selinuxusermap-find an exact match is made on the HBAC rule name, so only one or zero entries will be returned. EXAMPLES: Create a rule, "test1", that sets all users to xguest_u:s0 on the host "server": ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1 ipa selinuxusermap-add-host --hosts=server.example.com test1 Create a rule, "test2", that sets all users to guest_u:s0 and uses an existing HBAC rule for users and hosts: ipa selinuxusermap-add --usercat=all --hbacrule=webserver --selinuxuser=guest_u:s0 test2 Display the properties of a rule: ipa selinuxusermap-show test2 Create a rule for a specific user. This sets the SELinux context for user john to unconfined_u:s0-s0:c0.c1023 on any machine: ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0.c1023 john_unconfined ipa selinuxusermap-add-user --users=john john_unconfined Disable a rule: ipa selinuxusermap-disable test1 Enable a rule: ipa selinuxusermap-enable test1 Find a rule referencing a specific HBAC rule: ipa selinuxusermap-find --hbacrule=allow_some Remove a rule: ipa selinuxusermap-del john_unconfined SEEALSO: The list controlling the order in which the SELinux user map is applied and the default SELinux user are available in the config-show command. s.HBAC rule and local members cannot both be setc CsÝtjdƒ}tjdƒ}tjdƒ}|djddƒ\}}}}|j|ƒshtdƒS| s|j|ƒ r‰tdƒS|j|ƒ} |rÙ| sÏ| jdƒrÙt| jdƒƒd krÙtd ƒSd S( sÈ An SELinux user has 3 components: user:MLS:MCS. user and MLS are required. user traditionally ends with _u but this is not mandatory. The regex is ^[a-zA-Z][a-zA-Z_]* The MLS part can only be: Level: s[0-15](-s[0-15]) Then MCS could be c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123] Meaning s0 s0-s1 s0-s15:c0.c1023 s0-s1:c0,c2,c15.c26 s0-s0:c0.c1023 Returns a message on invalid, returns nothing on valid. s^[a-zA-Z][a-zA-Z_]*$s*^s[0-9][1-5]{0,1}(-s[0-9][1-5]{0,1}){0,1}$s^c(\d+)([.,-]c(\d+))*?$s:::t:is5Invalid SELinux user name, only a-Z and _ are alloweds/Invalid MLS value, must match s[0-15](-s[0-15])iÿsMInvalid MCS value, must match c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123]N(tretcompiletsplittmatchRtgrouptinttNone( tugettexttusert regex_namet regex_mlst regex_mcstnametmlstmcstignoretm((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pytvalidate_selinuxuserJs"  7 cCsš|jƒd}|jdgƒ}t|ƒdkrOtjdtdƒƒ‚n|djdƒ}||kr–tjdtdƒtd|ƒƒ‚nd S( sŒ Ensure the user is in the list of allowed SELinux users. Returns nothing if the user is found, raises an exception otherwise. itipaselinuxusermapordertreasons0SELinux user map list not found in configurationit$s<SELinux user %(user)s not found in ordering list (in config)RN(tget_ipa_configtgettlenRtNotFoundRR tdict(tldapRtconfigtitemtuserlist((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pytvalidate_selinuxuser_inlistms   tselinuxusermapcBsJeZdZejjZedƒZedƒZ ddgZ ddddd dd d d d dg Z dZ dZ iddgd 6ddgd 6ZedƒZedƒZeddddedƒdeƒededddedƒƒeddddedƒd ed!ƒƒed"dd#ded$ƒd ed%ƒd&d@ƒed(dd)ded*ƒd ed+ƒd&dAƒed,dd-ded.ƒƒed/ded0ƒd1d2gƒed3ded4ƒd1d5d6d7gƒed8ded9ƒd1d5d6d7gƒed:ded;ƒd1d5d6d7gƒed<ded=ƒd1d5d6d7gƒf Zd>„Zd?„ZRS(Bs" SELinux User Map object. sSELinux User Map rulesSELinux User Map rulestipaassociationtipaselinuxusermaptcntipaenabledflagt descriptiont usercategoryt hostcategoryt memberusert memberhosttmemberhostgrouptseealsotipaselinuxusert ipauniqueidRRthostt hostgroupsSELinux User MapssSELinux User Maptcli_nameRtlabels Rule namet primary_keyt selinuxusers SELinux Usersseealso?thbacrules HBAC Ruletdocs7HBAC Rule that defines the users, groups and hostgroupss usercategory?tusercats User categorys!User category the rule applies totvaluesualls hostcategory?thostcats Host categorys!Host category the rule applies tos description?tdesct Descriptionsipaenabledflag?tEnabledtflagst no_optionsmemberuser_user?tUserst no_createt no_updatet no_searchsmemberuser_group?s User Groupssmemberhost_host?tHostssmemberhost_hostgroup?s Host GroupscCsâ|s dSyt|ƒ}t|ƒSWn·tk rÝyj|jj|jjdjj ||jjdj dgt|jjdj tj j ƒƒ\}}|}WqÞtjk rÙtjdtdƒtd|ƒƒ‚qÞXnX|S(sP Given a HBAC rule name verify its existence and return the dn. R=tRsHBAC rule %(rule)s not foundtruleN(RtDNtstrt ValueErrortbackendtfind_entry_by_attrRtObjectR;Rt object_classt container_dntenvtbasednRR"RR#(tselfR4tdnt entry_attrs((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyt_normalize_seealsoÐs"   + -cKs^|jdtƒrdSd|krZ|j|dddgƒ\}}|dd|dsc3s|]}ˆ|ƒVqdS(N((t.0tattr(t is_to_be_set(s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pys sR/R0R4R(s usercategorys hostcategory( t isinstanceRNtAssertionErrorR(tanyRtMutuallyExclusiveErrort notboth_errtobjR[( RXR$RYRZt attrs_listtkeysR_tare_local_members_to_be_settis_hbacrule_to_be_set((RZRvs;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyt pre_callbackûs    cOs/t|tƒst‚|jj||||S(N(RwRNRxR|Rb(RXR$RYRZR~R_((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyt post_callbacks(RcRdRRet msg_summaryRR‚(((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyRpös   tselinuxusermap_delcBs eZedƒZedƒZRS(sDelete a SELinux User Map.s$Deleted SELinux User Map "%(value)s"(RcRdRReRƒ(((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyR„s tselinuxusermap_modcBs2eZedƒZedƒZd„Zd„ZRS(sModify a SELinux User Map.s%Modified SELinux User Map "%(value)s"c sut|tƒst‚y|j||ƒ\}‰Wn$tjk rW|jj|ŒnX‡‡fd†‰‡‡‡fd†‰t‡fd†d Dƒƒ}ˆdƒ} |rÈ| rÈtj d t ƒ‚nt ˆdƒrødˆkrøtj d d ƒ‚nt ˆdƒr(dˆkr(tj d d ƒ‚nd ˆkrHt |ˆd ƒndˆkrq|jj ˆdƒˆd8sR/R0R1R2R4RsBuser category cannot be set to 'all' while there are allowed userssBhost category cannot be set to 'all' while there are allowed hostsR5(s usercategorys hostcategorys memberusers memberhost(RwRNRxR^RR"R|thandle_not_foundRyRzR{RR(R[( RXR$RYRZR}R~R_t_dnRR€((R†RZR‡Rvs;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyR(s0     cOs/t|tƒst‚|jj||||S(N(RwRNRxR|Rb(RXR$RYRZR~R_((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyR‚Ss(RcRdRReRƒRR‚(((s;/home/mkosek/freeipa-clean/ipalib/plugins/selinuxusermap.pyR…#s   +tselinuxusermap_findcBs8eZedƒZedddƒZd„Zd„ZRS(sSearch for SELinux User Maps.s"%(count)d SELinux User Map matcheds#%(count)d SELinux User Maps matchedicOs—|jdƒr~|d}y+tjd|dtƒd}|d}Wn*tjk rptdddgdtƒSX||dsB +   # r "  5        freeipa-3.3.4/ipalib/plugins/krbtpolicy.py0000664000175000017500000001323512271663206020170 0ustar mkosekmkosek# Authors: # Pavel Zuna # # Copyright (C) 2010 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 . from ipalib import api from ipalib import Int, Str from ipalib.plugins.baseldap import * from ipalib import _ __doc__ = _(""" Kerberos ticket policy There is a single Kerberos ticket policy. This policy defines the maximum ticket lifetime and the maximum renewal age, the period during which the ticket is renewable. You can also create a per-user ticket policy by specifying the user login. For changes to the global policy to take effect, restarting the KDC service is required, which can be achieved using: service krb5kdc restart Changes to per-user policies take effect immediately for newly requested tickets (e.g. when the user next runs kinit). EXAMPLES: Display the current Kerberos ticket policy: ipa krbtpolicy-show Reset the policy to the default: ipa krbtpolicy-reset Modify the policy to 8 hours max life, 1-day max renewal: ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400 Display effective Kerberos ticket policy for user 'admin': ipa krbtpolicy-show admin Reset per-user policy for user 'admin': ipa krbtpolicy-reset admin Modify per-user policy for user 'admin': ipa krbtpolicy-mod admin --maxlife=3600 """) # FIXME: load this from a config file? _default_values = { 'krbmaxticketlife': 86400, 'krbmaxrenewableage': 604800, } class krbtpolicy(LDAPObject): """ Kerberos Ticket Policy object """ container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos')) object_name = _('kerberos ticket policy settings') default_attributes = ['krbmaxticketlife', 'krbmaxrenewableage'] limit_object_classes = ['krbticketpolicyaux'] label=_('Kerberos Ticket Policy') label_singular = _('Kerberos Ticket Policy') takes_params = ( Str('uid?', cli_name='user', label=_('User name'), doc=_('Manage ticket policy for specific user'), primary_key=True, ), Int('krbmaxticketlife?', cli_name='maxlife', label=_('Max life'), doc=_('Maximum ticket life (seconds)'), minvalue=1, ), Int('krbmaxrenewableage?', cli_name='maxrenew', label=_('Max renew'), doc=_('Maximum renewable age (seconds)'), minvalue=1, ), ) def get_dn(self, *keys, **kwargs): if keys[-1] is not None: return self.api.Object.user.get_dn(*keys, **kwargs) return DN(self.container_dn, api.env.basedn) api.register(krbtpolicy) class krbtpolicy_mod(LDAPUpdate): __doc__ = _('Modify Kerberos ticket policy.') def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # disable all flag # ticket policies are attached to objects with unrelated attributes if options.get('all'): options['all'] = False return dn api.register(krbtpolicy_mod) class krbtpolicy_show(LDAPRetrieve): __doc__ = _('Display the current Kerberos ticket policy.') def pre_callback(self, ldap, dn, attrs_list, *keys, **options): assert isinstance(dn, DN) # disable all flag # ticket policies are attached to objects with unrelated attributes if options.get('all'): options['all'] = False return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if keys[-1] is not None: # if policy for a specific user isn't set, display global values if 'krbmaxticketlife' not in entry_attrs or \ 'krbmaxrenewableage' not in entry_attrs: res = self.api.Command.krbtpolicy_show() for a in self.obj.default_attributes: entry_attrs.setdefault(a, res['result'][a]) return dn api.register(krbtpolicy_show) class krbtpolicy_reset(LDAPQuery): __doc__ = _('Reset Kerberos ticket policy to the default values.') has_output = output.standard_entry def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) def_values = {} # if reseting policy for a user - just his values if keys[-1] is not None: for a in self.obj.default_attributes: def_values[a] = None # if reseting global policy - set values to default else: def_values = _default_values try: ldap.update_entry(dn, def_values) except errors.EmptyModlist: pass if keys[-1] is not None: # policy for user was deleted, retrieve global policy dn = self.obj.get_dn(None) (dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes) entry_attrs = entry_to_dict(entry_attrs, **options) if keys[-1] is not None: return dict(result=entry_attrs, value=keys[-1]) return dict(result=entry_attrs, value=u'') api.register(krbtpolicy_reset) freeipa-3.3.4/ipalib/plugins/hbacrule.pyc0000664000175000017500000004317112271707517017744 0ustar mkosekmkosekó †fçRc@sôddlmZmZddlmZmZmZmZmZmZddl Tddlm Z m Z e dƒZ de dƒfZ d„Zd „Zd efd „ƒYZejeƒd efd „ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZ defd„ƒYZ!de"fd„ƒYZ#eje#ƒd e$fd!„ƒYZ%eje%ƒd"e"fd#„ƒYZ&eje&ƒd$e$fd%„ƒYZ'eje'ƒd&e"fd'„ƒYZ(eje(ƒd(e$fd)„ƒYZ)eje)ƒd*e"fd+„ƒYZ*eje*ƒd,e$fd-„ƒYZ+eje+ƒd.S(/iÿÿÿÿ(tapiterrors(t AccessTimetPasswordtStrtStrEnumtBooltDeprecatedParam(t*(t_tngettexts Host-based access control Control who can access what services on what hosts. You can use HBAC to control which users or groups can access a service, or group of services, on a target host. You can also specify a category of users and target hosts. This is currently limited to "all", but might be expanded in the future. Target hosts in HBAC rules must be hosts managed by IPA. The available services and groups of services are controlled by the hbacsvc and hbacsvcgroup plug-ins respectively. EXAMPLES: Create a rule, "test1", that grants all users access to the host "server" from anywhere: ipa hbacrule-add --usercat=all test1 ipa hbacrule-add-host --hosts=server.example.com test1 Display the properties of a named HBAC rule: ipa hbacrule-show test1 Create a rule for a specific service. This lets the user john access the sshd service on any machine from any machine: ipa hbacrule-add --hostcat=all john_sshd ipa hbacrule-add-user --users=john john_sshd ipa hbacrule-add-service --hbacsvcs=sshd john_sshd Create a rule for a new service group. This lets the user john access the FTP service on any machine from any machine: ipa hbacsvcgroup-add ftpers ipa hbacsvc-add sftp ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers ipa hbacrule-add --hostcat=all john_ftp ipa hbacrule-add-user --users=john john_ftp ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp Disable a named HBAC rule: ipa hbacrule-disable test1 Remove a named HBAC rule: ipa hbacrule-del allow_server thbacs"Host-based access control commandscCs7|jƒdkr3tjdddtdƒƒ‚ndS(Ntdenytnamettypeterrors"The deny type has been deprecated.(tlowerRtValidationErrorR (tugettextR((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyt validate_type[scCsz||krr||dk rrt||ƒttfkrO||djƒ}n||jƒ}|dkrvtSntSdS(sF See if options[attribute] is lower-case 'all' in a safe way. itallN(tNoneRtlistttupleRtTruetFalse(toptionst attributetvalue((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pytis_all_s thbacrulecBs÷eZdZejjZedƒZedƒZ ddgZ ddddd d d dd d ddddgZ dZ dZ iddgd 6ddgd6ddgd 6ddgd6ZedƒZedƒZeddddedƒdeƒed edd!d"ed#ƒded$ƒd%dSd(d&d)ed*d+d,d-d.gƒed/dd0ded1ƒd"ed2ƒd%dTƒed4dd5ded6ƒd"ed7ƒd%dUƒed8ƒed9dd:ded;ƒd"ed<ƒd%dVƒed=dd>ded?ƒƒed@dedAƒd,d-gƒedBdedCƒd,dDdEdFgƒedGdedHƒd,dDdEdFgƒedIdedJƒd,dDdEdFgƒedKdedLƒd,dDdEdFgƒedMƒedNƒedOdedPƒd,dDdEdFgƒedQdedRƒd,dDdEdFgƒefZRS(Ws HBAC object. s HBAC rules HBAC rulestipaassociationt ipahbacruletcntipaenabledflagt descriptiont usercategoryt hostcategorytsourcehostcategorytservicecategoryt memberusert sourcehostt memberhostt memberservicetmemberhostgroupt externalhostt ipauniqueidtusertgroupthostt hostgroupthbacsvct hbacsvcgroups HBAC Ruless HBAC Ruletcli_nameR tlabels Rule namet primary_keytaccessruletypeRtdocsRule type (allow)s Rule typetvaluesuallowudenytdefaulttautofilltexcludetwebuitflagst no_optiont no_outputs usercategory?tusercats User categorys!User category the rule applies toualls hostcategory?thostcats Host categorys!Host category the rule applies tossourcehostcategory?sservicecategory?t servicecatsService categorys$Service category the rule applies tos description?tdesct Descriptionsipaenabledflag?tEnabledsmemberuser_user?tUserst no_createt no_updatet no_searchsmemberuser_group?s User Groupssmemberhost_host?tHostssmemberhost_hostgroup?s Host Groupsssourcehost_host?ssourcehost_hostgroup?smemberservice_hbacsvc?tServicessmemberservice_hbacsvcgroup?sService Groups(uallowudeny(uall(uall(uall(t__name__t __module__t__doc__Rtenvtcontainer_hbact container_dnR t object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributet rdn_attributetattribute_membersR6tlabel_singularRRRRRRtexternal_host_paramt takes_params(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRns–                                                t hbacrule_addcBs)eZedƒZedƒZd„ZRS(sCreate a new HBAC rule.sAdded HBAC rule "%(value)s"cOs#t|tƒst‚d|d<|S(NtTRUER"(t isinstancetDNtAssertionError(tselftldaptdnt entry_attrst attrs_listtkeysR((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyt pre_callbackÞs (RNROR RPt msg_summaryRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR^Ùs  t hbacrule_delcBs)eZedƒZedƒZd„ZRS(sDelete an HBAC rule.sDeleted HBAC rule "%(value)s"cOst|tƒst‚td|dƒ}tjjd|}|dr‰tj d|dd|jj dj d|ddd dƒ‚n|S( NtseealsoitcounttkeyR6tselinuxusermapt dependenttresultR!( R`RaRbtdictRtCommandtselinuxusermap_findRRtDependentEntrytObjectR[(RcRdReRhRtkwt_entries((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRiìs  B(RNROR RPRjRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRkçs  t hbacrule_modcBs)eZedƒZedƒZd„ZRS(sModify an HBAC rule.sModified HBAC rule "%(value)s"cOsþt|tƒst‚y|j||ƒ\}}Wn$tjk rW|jj|ŒnXt|dƒrŽd|krŽtj dt dƒƒ‚nt|dƒrÄd|krÄtj dt dƒƒ‚nt|dƒrúd |krútj dt d ƒƒ‚n|S( NR$R(treasonsBuser category cannot be set to 'all' while there are allowed usersR%R*sBhost category cannot be set to 'all' while there are allowed hostsR'R+sHservice category cannot be set to 'all' while there are allowed services( R`RaRbt get_entryRtNotFoundtobjthandle_not_foundRtMutuallyExclusiveErrorR (RcRdReRfRgRhR((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRiýs(RNROR RPRjRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRyøs  t hbacrule_findcBs&eZedƒZedddƒZRS(sSearch for HBAC rules.s%(count)d HBAC rule matcheds%(count)d HBAC rules matchedi(RNROR RPR Rj(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR€s t hbacrule_showcBseZedƒZRS(s'Display the properties of an HBAC rule.(RNROR RP(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRsthbacrule_enablecBs2eZedƒZedƒZejZd„ZRS(sEnable an HBAC rule.sEnabled HBAC rule "%(value)s"cKsŒ|jj}|jj|ƒ}idd6}y|j||ƒWn7tjk rUn$tjk rx|jj|ƒnXtdt d|ƒS(NR_R"RqR( R}tbackendtget_dnt update_entryRt EmptyModlistR|R~RrR(RcR!RRdReRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pytexecute%s  ( RNROR RPRjtoutputtstandard_valuet has_outputR‡(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR‚s   thbacrule_disablecBs2eZedƒZedƒZejZd„ZRS(sDisable an HBAC rule.sDisabled HBAC rule "%(value)s"cKsŒ|jj}|jj|ƒ}idd6}y|j||ƒWn7tjk rUn$tjk rx|jj|ƒnXtdt d|ƒS(NtFALSER"RqR( R}RƒR„R…RR†R|R~RrR(RcR!RRdReRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR‡@s  ( RNROR RPRjRˆR‰RŠR‡(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR‹:s   thbacrule_add_accesstimecBsAeZdZeddddedƒƒfZd„Zd„ZRS(s- Add an access time to an HBAC rule. t accesstimeR5ttimeR6s Access timecKs±|jj}|jj|ƒ}|j|dgƒ\}}|jdgƒj|dƒy|j||ƒWn7tjk r€n$tj k r£|jj |ƒnXt dt ƒS(NRŽRq( R}RƒR„R{t setdefaulttappendR…RR†R|R~RrR(RcR!RRdReRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR‡as  cKs/|j|jƒ|jd|d|fƒdS(Ns(Added access time "%s" to HBAC rule "%s"RŽ(t print_nameR t print_dashed(RcttextuiRqR!R((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pytoutput_for_cliss(RNRORPRR t takes_optionsR‡R•(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRUs   thbacrule_remove_accesstimecBsAeZdZeddddedƒƒfZd„Zd„ZRS(s* Remove access time to HBAC rule. s accesstime?R5RR6s Access timecKs·|jj}|jj|ƒ}|j|dgƒ\}}y1|jdgƒj|dƒ|j||ƒWn=ttj fk r†n$tj k r©|jj |ƒnXt dt ƒS(NRŽRq(R}RƒR„R{RtremoveR…t ValueErrorRR†R|R~RrR(RcR!RRdReRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR‡‰s  cKs/|j|jƒ|jd|d|fƒdS(Ns,Removed access time "%s" from HBAC rule "%s"RŽ(R’R R“(RcR”RqR!R((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR•›s(RNRORPRR R–R‡R•(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR—~s   thbacrule_add_usercBs,eZedƒZdgZdZd„ZRS(s%Add users and groups to an HBAC rule.R(s%i object added.s%i objects added.cOs£t|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXd|krŸ|ddj ƒdkrŸtj dt dƒƒ‚n|S(NR$iRRzs.users cannot be added when user category='all'( R`RaRbR{R}RWRR|R~RRR (RcRdRetfoundt not_foundRhRRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRi¬s"  (s%i object added.s%i objects added.(RNROR RPtmember_attributestmember_count_outRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRš¦s  thbacrule_remove_usercBs#eZedƒZdgZdZRS(s*Remove users and groups from an HBAC rule.R(s%i object removed.s%i objects removed.(s%i object removed.s%i objects removed.(RNROR RPRRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRŸ»s  thbacrule_add_hostcBs,eZedƒZdgZdZd„ZRS(s0Add target hosts and hostgroups to an HBAC rule.R*s%i object added.s%i objects added.cOs£t|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXd|krŸ|ddj ƒdkrŸtj dt dƒƒ‚n|S(NR%iRRzs.hosts cannot be added when host category='all'( R`RaRbR{R}RWRR|R~RRR (RcRdReR›RœRhRRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRiÊs"  (s%i object added.s%i objects added.(RNROR RPRRžRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR Äs  thbacrule_remove_hostcBs#eZedƒZdgZdZRS(s5Remove target hosts and hostgroups from an HBAC rule.R*s%i object removed.s%i objects removed.(s%i object removed.s%i objects removed.(RNROR RPRRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR¡Ùs  thbacrule_add_sourcehostcBs&eZeZdgZdZd„ZRS(R)s%i object added.s%i objects added.cKstjddƒ‚dS(NR R¢(RtDeprecationError(RcRw((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pytvalidateès(s%i object added.s%i objects added.(RNRORtNO_CLIRRžR¤(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR¢âs thbacrule_remove_sourcehostcBs&eZeZdgZdZd„ZRS(R)s%i object removed.s%i objects removed.cKstjddƒ‚dS(NR R¦(RR£(RcRw((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR¤ôs(s%i object removed.s%i objects removed.(RNRORR¥RRžR¤(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR¦îs thbacrule_add_servicecBs,eZedƒZdgZdZd„ZRS(sAdd services to an HBAC rule.R+s%i object added.s%i objects added.cOs£t|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXd|krŸ|ddj ƒdkrŸtj dt dƒƒ‚n|S(NR'iRRzs4services cannot be added when service category='all'( R`RaRbR{R}RWRR|R~RRR (RcRdReR›RœRhRRf((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyRis"  (s%i object added.s%i objects added.(RNROR RPRRžRi(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR§ús  thbacrule_remove_servicecBs#eZedƒZdgZdZRS(s4Remove service and service groups from an HBAC rule.R+s%i object removed.s%i objects removed.(s%i object removed.s%i objects removed.(RNROR RPRRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pyR¨s  N(,tipalibRRRRRRRRtipalib.plugins.baseldapR R RPttopicRRt LDAPObjectRtregistert LDAPCreateR^t LDAPDeleteRkt LDAPUpdateRyt LDAPSearchR€t LDAPRetrieveRt LDAPQueryR‚R‹RR—t LDAPAddMemberRštLDAPRemoveMemberRŸR R¡R¢R¦R§R¨(((s5/home/mkosek/freeipa-clean/ipalib/plugins/hbacrule.pytsT. .   h        )(       freeipa-3.3.4/ipalib/plugins/service.py0000664000175000017500000005600512271663206017450 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # Rob Crittenden # Pavel Zuna # # 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 . import base64 import os from ipalib import api, errors, util from ipalib import Str, Flag, Bytes, StrEnum, Bool from ipalib.plugins.baseldap import * from ipalib import x509 from ipalib import _, ngettext from ipalib import util import nss.nss as nss from nss.error import NSPRError from ipapython.ipautil import file_exists __doc__ = _(""" Services A IPA service represents a service that runs on a host. The IPA service record can store a Kerberos principal, an SSL certificate, or both. An IPA service can be managed directly from a machine, provided that machine has been given the correct permission. This is true even for machines other than the one the service is associated with. For example, requesting an SSL certificate using the host service principal credentials of the host. To manage a service using host credentials you need to kinit as the host: # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM Adding an IPA service allows the associated service to request an SSL certificate or keytab, but this is performed as a separate step; they are not produced as a result of adding the service. Only the public aspect of a certificate is stored in a service record; the private key is not stored. EXAMPLES: Add a new IPA service: ipa service-add HTTP/web.example.com Allow a host to manage an IPA service certificate: ipa service-add-host --hosts=web.example.com HTTP/web.example.com ipa role-add-member --hosts=web.example.com certadmin Override a default list of supported PAC types for the service: ipa service-mod HTTP/web.example.com --pac-type=MS-PAC A typical use case where overriding the PAC type is needed is NFS. Currently the related code in the Linux kernel can only handle Kerberos tickets up to a maximal size. Since the PAC data can become quite large it is recommended to set --pac-type=NONE for NFS services. Delete an IPA service: ipa service-del HTTP/web.example.com Find all IPA services associated with a host: ipa service-find web.example.com Find all HTTP services: ipa service-find HTTP Disable the service Kerberos key and SSL certificate: ipa service-disable HTTP/web.example.com Request a certificate for an IPA service: ipa cert-request --principal=HTTP/web.example.com example.csr Generate and retrieve a keytab for an IPA service: ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/httpd.keytab """) output_params = ( Flag('has_keytab', label=_('Keytab'), ), Str('managedby_host', label='Managed by', ), Str('subject', label=_('Subject'), ), Str('serial_number', label=_('Serial Number'), ), Str('serial_number_hex', label=_('Serial Number (hex)'), ), Str('issuer', label=_('Issuer'), ), Str('valid_not_before', label=_('Not Before'), ), Str('valid_not_after', label=_('Not After'), ), Str('md5_fingerprint', label=_('Fingerprint (MD5)'), ), Str('sha1_fingerprint', label=_('Fingerprint (SHA1)'), ), Str('revocation_reason?', label=_('Revocation reason'), ) ) ticket_flags_params = ( Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth', label=_('Requires pre-authentication'), doc=_('Pre-authentication is required for the service'), flags=['virtual_attribute', 'no_search'], ), Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate', label=_('Trusted for delegation'), doc=_('Client credentials may be delegated to the service'), flags=['virtual_attribute', 'no_search'], ), ) _ticket_flags_map = { 'ipakrbrequirespreauth': 0x00000080, 'ipakrbokasdelegate': 0x00100000, } _ticket_flags_default = _ticket_flags_map['ipakrbrequirespreauth'] def split_principal(principal): service = hostname = realm = None # Break down the principal into its component parts, which may or # may not include the realm. sp = principal.split('/') if len(sp) != 2: raise errors.MalformedServicePrincipal(reason=_('missing service')) service = sp[0] if len(service) == 0: raise errors.MalformedServicePrincipal(reason=_('blank service')) sr = sp[1].split('@') if len(sr) > 2: raise errors.MalformedServicePrincipal( reason=_('unable to determine realm')) hostname = sr[0].lower() if len(sr) == 2: realm = sr[1].upper() # At some point we'll support multiple realms if realm != api.env.realm: raise errors.RealmMismatch() else: realm = api.env.realm # Note that realm may be None. return (service, hostname, realm) def validate_principal(ugettext, principal): (service, hostname, principal) = split_principal(principal) return None def normalize_principal(principal): # The principal is already validated when it gets here (service, hostname, realm) = split_principal(principal) # Put the principal back together again principal = '%s/%s@%s' % (service, hostname, realm) return unicode(principal) def validate_certificate(ugettext, cert): """ For now just verify that it is properly base64-encoded. """ if cert and util.isvalid_base64(cert): try: base64.b64decode(cert) except Exception, e: raise errors.Base64DecodeError(reason=str(e)) else: # We'll assume this is DER data pass def set_certificate_attrs(entry_attrs): """ Set individual attributes from some values from a certificate. entry_attrs is a dict of an entry returns nothing """ if not 'usercertificate' in entry_attrs: return if type(entry_attrs['usercertificate']) in (list, tuple): cert = entry_attrs['usercertificate'][0] else: cert = entry_attrs['usercertificate'] cert = x509.normalize_certificate(cert) cert = x509.load_certificate(cert, datatype=x509.DER) entry_attrs['subject'] = unicode(cert.subject) entry_attrs['serial_number'] = unicode(cert.serial_number) entry_attrs['serial_number_hex'] = u'0x%X' % cert.serial_number entry_attrs['issuer'] = unicode(cert.issuer) entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str) entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str) entry_attrs['md5_fingerprint'] = unicode(nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0]) entry_attrs['sha1_fingerprint'] = unicode(nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0]) def check_required_principal(ldap, hostname, service): """ Raise an error if the host of this prinicipal is an IPA master and one of the principals required for proper execution. """ try: host_is_master(ldap, hostname) except errors.ValidationError, e: service_types = ['HTTP', 'ldap', 'DNS', 'dogtagldap'] if service in service_types: raise errors.ValidationError(name='principal', error=_('This principal is required by the IPA master')) def update_krbticketflags(ldap, entry_attrs, attrs_list, options, existing): add = remove = 0 for (name, value) in _ticket_flags_map.iteritems(): if name not in options: continue if options[name]: add |= value else: remove |= value if not add and not remove: return if 'krbticketflags' not in entry_attrs and existing: old_entry_attrs = ldap.get_entry(entry_attrs.dn, ['krbticketflags']) else: old_entry_attrs = entry_attrs try: ticket_flags = old_entry_attrs.single_value('krbticketflags') ticket_flags = int(ticket_flags) except (KeyError, ValueError): ticket_flags = _ticket_flags_default ticket_flags |= add ticket_flags &= ~remove entry_attrs['krbticketflags'] = [ticket_flags] attrs_list.append('krbticketflags') def set_kerberos_attrs(entry_attrs, options): if options.get('raw', False): return try: ticket_flags = entry_attrs.single_value('krbticketflags', _ticket_flags_default) ticket_flags = int(ticket_flags) except ValueError: return all_opt = options.get('all', False) for (name, value) in _ticket_flags_map.iteritems(): if name in options or all_opt: entry_attrs[name] = bool(ticket_flags & value) class service(LDAPObject): """ Service object. """ container_dn = api.env.container_service object_name = _('service') object_name_plural = _('services') object_class = [ 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', 'ipaservice', 'pkiuser' ] possible_objectclasses = ['ipakrbprincipal'] search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata'] default_attributes = ['krbprincipalname', 'usercertificate', 'managedby', 'ipakrbauthzdata',] uuid_attribute = 'ipauniqueid' attribute_members = { 'managedby': ['host'], } bindable = True relationships = { 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), } password_attributes = [('krbprincipalkey', 'has_keytab')] label = _('Services') label_singular = _('Service') takes_params = ( Str('krbprincipalname', validate_principal, cli_name='principal', label=_('Principal'), doc=_('Service principal'), primary_key=True, normalizer=lambda value: normalize_principal(value), ), Bytes('usercertificate?', validate_certificate, cli_name='certificate', label=_('Certificate'), doc=_('Base-64 encoded server certificate'), flags=['no_search',], ), StrEnum('ipakrbauthzdata*', cli_name='pac_type', label=_('PAC type'), doc=_("Override default list of supported PAC types." " Use 'NONE' to disable PAC support for this service," " e.g. this might be necessary for NFS services."), values=(u'MS-PAC', u'PAD', u'NONE'), csv=True, ), ) + ticket_flags_params def validate_ipakrbauthzdata(self, entry): new_value = entry.get('ipakrbauthzdata', []) if not new_value: return if not isinstance(new_value, (list, tuple)): new_value = set([new_value]) else: new_value = set(new_value) if u'NONE' in new_value and len(new_value) > 1: raise errors.ValidationError(name='ipakrbauthzdata', error=_('NONE value cannot be combined with other PAC types')) api.register(service) class service_add(LDAPCreate): __doc__ = _('Add a new IPA new service.') msg_summary = _('Added service "%(value)s"') member_attributes = ['managedby'] has_output_params = LDAPCreate.has_output_params + output_params takes_options = LDAPCreate.takes_options + ( Flag('force', label=_('Force'), doc=_('force principal name even if not in DNS'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) (service, hostname, realm) = split_principal(keys[-1]) if service.lower() == 'host' and not options['force']: raise errors.HostService() try: hostresult = api.Command['host_show'](hostname)['result'] except errors.NotFound: raise errors.NotFound( reason=_("The host '%s' does not exist to add a service to.") % hostname) self.obj.validate_ipakrbauthzdata(entry_attrs) cert = options.get('usercertificate') if cert: dercert = x509.normalize_certificate(cert) x509.verify_cert_subject(ldap, hostname, dercert) entry_attrs['usercertificate'] = dercert if not options.get('force', False): # We know the host exists if we've gotten this far but we # really want to discourage creating services for hosts that # don't exist in DNS. util.validate_host_dns(self.log, hostname) if not 'managedby' in entry_attrs: entry_attrs['managedby'] = hostresult['dn'] # Enforce ipaKrbPrincipalAlias to aid case-insensitive searches # as krbPrincipalName/krbCanonicalName are case-sensitive in Kerberos # schema entry_attrs['ipakrbprincipalalias'] = keys[-1] # Objectclass ipakrbprincipal providing ipakrbprincipalalias is not in # in a list of default objectclasses, add it manually entry_attrs['objectclass'].append('ipakrbprincipal') update_krbticketflags(ldap, entry_attrs, attrs_list, options, False) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): set_kerberos_attrs(entry_attrs, options) return dn api.register(service_add) class service_del(LDAPDelete): __doc__ = _('Delete an IPA service.') msg_summary = _('Deleted service "%(value)s"') member_attributes = ['managedby'] def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # In the case of services we don't want IPA master services to be # deleted. This is a limited few though. If the user has their own # custom services allow them to manage them. (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) if self.api.env.enable_ra: try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.get('usercertificate') if cert: cert = cert[0] try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the service. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr return dn api.register(service_del) class service_mod(LDAPUpdate): __doc__ = _('Modify an existing IPA service.') msg_summary = _('Modified service "%(value)s"') takes_options = LDAPUpdate.takes_options has_output_params = LDAPUpdate.has_output_params + output_params member_attributes = ['managedby'] def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) self.obj.validate_ipakrbauthzdata(entry_attrs) if 'usercertificate' in options: (service, hostname, realm) = split_principal(keys[-1]) cert = options.get('usercertificate') if cert: dercert = x509.normalize_certificate(cert) x509.verify_cert_subject(ldap, hostname, dercert) try: (dn, entry_attrs_old) = ldap.get_entry( dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) if 'usercertificate' in entry_attrs_old: # FIXME: what to do here? do we revoke the old cert? fmt = 'entry already has a certificate, serial number: %s' % ( x509.get_serial_number(entry_attrs_old['usercertificate'][0], x509.DER) ) raise errors.GenericError(format=fmt) entry_attrs['usercertificate'] = dercert else: entry_attrs['usercertificate'] = None update_krbticketflags(ldap, entry_attrs, attrs_list, options, True) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) return dn api.register(service_mod) class service_find(LDAPSearch): __doc__ = _('Search for IPA services.') msg_summary = ngettext( '%(count)d service matched', '%(count)d services matched', 0 ) member_attributes = ['managedby'] takes_options = LDAPSearch.takes_options has_output_params = LDAPSearch.has_output_params + output_params def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) # lisp style! custom_filter = '(&(objectclass=ipaService)' \ '(!(objectClass=posixAccount))' \ '(!(|(krbprincipalname=kadmin/*)' \ '(krbprincipalname=K/M@*)' \ '(krbprincipalname=krbtgt/*))' \ ')' \ ')' return ( ldap.combine_filters((custom_filter, filter), rules=ldap.MATCH_ALL), base_dn, scope ) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, entry_attrs) = entry self.obj.get_password_attributes(ldap, dn, entry_attrs) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) return truncated api.register(service_find) class service_show(LDAPRetrieve): __doc__ = _('Display information about an IPA service.') member_attributes = ['managedby'] takes_options = LDAPRetrieve.takes_options + ( Str('out?', doc=_('file to store certificate in'), ), ) has_output_params = LDAPRetrieve.has_output_params + output_params def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.get_password_attributes(ldap, dn, entry_attrs) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) return dn def forward(self, *keys, **options): if 'out' in options: util.check_writable_file(options['out']) result = super(service_show, self).forward(*keys, **options) if 'usercertificate' in result['result']: x509.write_certificate(result['result']['usercertificate'][0], options['out']) result['summary'] = _('Certificate stored in file \'%(file)s\'') % dict(file=options['out']) return result else: raise errors.NoCertificateError(entry=keys[-1]) else: return super(service_show, self).forward(*keys, **options) api.register(service_show) class service_add_host(LDAPAddMember): __doc__ = _('Add hosts that can manage this service.') member_attributes = ['managedby'] has_output_params = LDAPAddMember.has_output_params + output_params api.register(service_add_host) class service_remove_host(LDAPRemoveMember): __doc__ = _('Remove hosts that can manage this service.') member_attributes = ['managedby'] has_output_params = LDAPRemoveMember.has_output_params + output_params api.register(service_remove_host) class service_disable(LDAPQuery): __doc__ = _('Disable the Kerberos key and SSL certificate of a service.') has_output = output.standard_value msg_summary = _('Disabled service "%(value)s"') has_output_params = LDAPQuery.has_output_params + output_params def execute(self, *keys, **options): ldap = self.obj.backend dn = self.obj.get_dn(*keys, **options) (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) (service, hostname, realm) = split_principal(keys[-1]) check_required_principal(ldap, hostname, service) # See if we do any work at all here and if not raise an exception done_work = False if 'usercertificate' in entry_attrs: if self.api.env.enable_ra: cert = x509.normalize_certificate(entry_attrs.get('usercertificate')[0]) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](unicode(serial))['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](unicode(serial), revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the service self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr # Remove the usercertificate altogether ldap.update_entry(dn, {'usercertificate': None}) done_work = True self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_keytab']: ldap.remove_principal_key(dn) done_work = True if not done_work: raise errors.AlreadyInactive() return dict( result=True, value=keys[0], ) api.register(service_disable) freeipa-3.3.4/ipalib/plugins/sudorule.pyc0000664000175000017500000006651112271707517020024 0ustar mkosekmkosekó †fçRc@sªddlmZmZddlmZmZmZddlTddlmZddlm Z m Z e dƒZ de dƒfZ d „Z d „Zd „Zd „Zd efd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZ eje ƒde!fd„ƒYZ"eje"ƒde#fd „ƒYZ$eje$ƒd!e!fd"„ƒYZ%eje%ƒd#e#fd$„ƒYZ&eje&ƒd%e!fd&„ƒYZ'eje'ƒd'e#fd(„ƒYZ(eje(ƒd)e!fd*„ƒYZ)eje)ƒd+e#fd,„ƒYZ*eje*ƒd-e!fd.„ƒYZ+eje+ƒd/e#fd0„ƒYZ,eje,ƒd1e!fd2„ƒYZ-eje-ƒd3e#fd4„ƒYZ.eje.ƒd5efd6„ƒYZ/eje/ƒd7efd8„ƒYZ0eje0ƒd9S(:iÿÿÿÿ(tapiterrors(tStrtStrEnumtBool(t*(tis_all(t_tngettexts Sudo Rules Sudo (su "do") allows a system administrator to delegate authority to give certain users (or groups of users) the ability to run some (or all) commands as root or another user while providing an audit trail of the commands and their arguments. FreeIPA provides a means to configure the various aspects of Sudo: Users: The user(s)/group(s) allowed to invoke Sudo. Hosts: The host(s)/hostgroup(s) which the user is allowed to to invoke Sudo. Allow Command: The specific command(s) permitted to be run via Sudo. Deny Command: The specific command(s) prohibited to be run via Sudo. RunAsUser: The user(s) or group(s) of users whose rights Sudo will be invoked with. RunAsGroup: The group(s) whose gid rights Sudo will be invoked with. Options: The various Sudoers Options that can modify Sudo's behavior. An order can be added to a sudorule to control the order in which they are evaluated (if the client supports it). This order is an integer and must be unique. FreeIPA provides a designated binddn to use with Sudo located at: uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com To enable the binddn run the following command to set the password: LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -ZZ -D "cn=Directory Manager" uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com EXAMPLES: Create a new rule: ipa sudorule-add readfiles Add sudo command object and add it as allowed command in the rule: ipa sudocmd-add /usr/bin/less ipa sudorule-add-allow-command readfiles --sudocmds /usr/bin/less Add a host to the rule: ipa sudorule-add-host readfiles --hosts server.example.com Add a user to the rule: ipa sudorule-add-user readfiles --users jsmith Add a special Sudo rule for default Sudo server configuration: ipa sudorule-add defaults Set a default Sudo option: ipa sudorule-add-option defaults --sudooption '!authenticate' tsudos+Commands for controlling sudo configurationcCs"tjd|dtdƒƒ‚dS(Ntnameterrors this option has been deprecated.(RtValidationErrorR(t attribute((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyt deprecatedOscCstdƒdS(Nt externaluser(R(tugettexttvalue((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytvalidate_externaluserRscCstdƒdS(Ntrunasexternaluser(R(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytvalidate_runasextuserUscCstdƒdS(Ntrunasexternalgroup(R(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytvalidate_runasextgroupXstsudorulec!BsÊeZdZejjZedƒZedƒZ ddgZ ddddd d d d d ddddddddgZ dZ dZ iddgd 6ddgd 6ddgd6ddgd6ddgd6dgd6ZedƒZedƒZeddd d!ed"ƒd#eƒed$dd%d!ed&ƒƒed'd!ed(ƒd)d*gƒed+dd,d!ed-ƒd.ed/ƒd0dtƒed2dd3d!ed4ƒd.ed5ƒd0duƒed6dd7d!ed8ƒd.ed9ƒd0dvƒed:dd;d!ed<ƒd.ed=ƒd0dwƒed>dd?d!ed@ƒd.edAƒd0dxƒedBddCd!edDƒd.edEƒdFdGdHdGƒedId!edJƒd)dKdLdMgƒedNd!edOƒd)dKdLdMgƒedPd!edQƒd)dKdLdMgƒedRd!edSƒd)dKdLdMgƒedTd!edUƒd)dKdLdMgƒedVd!edWƒd)dKdLdMgƒedXd!edYƒd)dKdLdMgƒedZd!ed[ƒd)dKdLdMgƒed\d!ed]ƒd.ed^ƒd)dKdLdMgƒed_d!ed`ƒd.edaƒd)dKdLdMgƒedbeddd!edcƒd.eddƒƒedeeddfd!edgƒd.edhƒƒedieddjd!edkƒd.edlƒƒedmd!ednƒd)dKdLdMgƒedod!edpƒd.edqƒd)dKdLdMgƒefZedrƒZds„ZRS(ys Sudo Rule object. s sudo rules sudo rulestipaassociationt ipasudoruletcntipaenabledflagRt descriptiont usercategoryt hostcategoryt cmdcategoryt memberusert memberhosttmemberallowcmdt memberdenycmdt ipasudooptt ipasudorunastipasudorunasgrouptipasudorunasusercategorytipasudorunasgroupcategoryt sudoordert ipauniqueidtusertgroupthostt hostgrouptsudocmdt sudocmdgroups Sudo Ruless Sudo Ruletcli_namet sudorule_nametlabels Rule namet primary_keys description?tdesct Descriptionsipaenabledflag?tEnabledtflagst no_options usercategory?tusercats User categorytdocs!User category the rule applies totvaluesualls hostcategory?thostcats Host categorys!Host category the rule applies tos cmdcategory?tcmdcatsCommand categorys$Command category the rule applies tosipasudorunasusercategory?t runasusercatsRunAs User categorys'RunAs User category the rule applies tosipasudorunasgroupcategory?t runasgroupcatsRunAs Group categorys(RunAs Group category the rule applies tos sudoorder?torders Sudo ordersinteger to order the Sudo rulestdefaultitminvaluesmemberuser_user?tUserst no_createt no_updatet no_searchsmemberuser_group?s User Groupssmemberhost_host?tHostssmemberhost_hostgroup?s Host Groupssmemberallowcmd_sudocmd?sSudo Allow Commandssmemberdenycmd_sudocmd?sSudo Deny Commandssmemberallowcmd_sudocmdgroup?sSudo Allow Command Groupssmemberdenycmd_sudocmdgroup?sSudo Deny Command Groupssipasudorunas_user?s RunAs Userss Run as a usersipasudorunas_group?sGroups of RunAs Userss(Run as any user within a specified groups externaluser?s External Users6External User the rule applies to (sudorule-find only)sipasudorunasextuser?RsRunAs External Users:External User the commands can run as (sudorule-find only)sipasudorunasextgroup?RsRunAs External Groups;External Group the commands can run as (sudorule-find only)s ipasudoopt?s Sudo Optionsipasudorunasgroup_group?s RunAs Groupss+Run with the gid of a specified POSIX groupsAorder must be a unique value (%(order)d already used by %(rule)s)cOsˆd|kr„|jjd|dƒd}t|ƒdkr„|ddd}tjddd|ji|dd6|d6ƒ‚q„ndS( NR)tresultiRR RAR trule(tmethodstfindtlenRR torder_not_unique_msg(tselftkeystoptionstentriest rule_name((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytcheck_order_uniquenessös      (uall(uall(uall(uall(uall(t__name__t __module__t__doc__Rtenvtcontainer_sudorulet container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributet rdn_attributetattribute_membersR3tlabel_singularRtTrueRRtIntRRRtexternal_host_paramt takes_paramsRNRT(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR[sî                                                                                t sudorule_addcBs)eZedƒZd„ZedƒZRS(sCreate new Sudo Rule.cOs6t|tƒst‚|jj||Žd|d<|S(NtTRUER(t isinstancetDNtAssertionErrortobjRT(ROtldaptdnt entry_attrst attrs_listRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyt pre_callback s sAdded Sudo Rule "%(value)s"(RURVRRWRqt msg_summary(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRgs  t sudorule_delcBs eZedƒZedƒZRS(sDelete Sudo Rule.sDeleted Sudo Rule "%(value)s"(RURVRRWRr(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRss t sudorule_modcBs)eZedƒZedƒZd„ZRS(sModify Sudo Rule.sModified Sudo Rule "%(value)s"c Os t|tƒst‚d|kr¨|jdƒ}|jjj|dƒd}d|kr’t|ddƒ} | |kr¥|jj ||Žq¥q¨|jj ||Žny"|j ||jj ƒ\} } Wn$t j k rð|jj|ŒnXt|dƒr'd| kr't jdtdƒƒ‚nt|d ƒr]d | kr]t jdtd ƒƒ‚nt|d ƒr™d pud| kr™t jdtdƒƒ‚nt|dƒrÏd| krÏt jdtdƒƒ‚nt|dƒrd| krt jdtdƒƒ‚n|S(NR)iÿÿÿÿRIiRR treasonsBuser category cannot be set to 'all' while there are allowed usersRR!sBhost category cannot be set to 'all' while there are allowed hostsRR"tmemberdenywcmdsNcommand category cannot be set to 'all' while there are allow or deny commandsR'R%s@user runAs category cannot be set to 'all' while there are usersR(R&sBgroup runAs category cannot be set to 'all' while there are groups(RiRjRktgetRtCommandt sudorule_showtintRlRTt get_entryR^RtNotFoundthandle_not_foundRtMutuallyExclusiveErrorR( RORmRnRoRpRPRQt new_ordert old_entryt old_ordert_dnt _entry_attrs((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRq#s2   " (RURVRRWRrRq(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRts  t sudorule_findcBs&eZedƒZedddƒZRS(sSearch for Sudo Rule.s%(count)d Sudo Rule matcheds%(count)d Sudo Rules matchedi(RURVRRWRRr(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR„Ds RycBseZedƒZRS(sDisplay Sudo Rule.(RURVRRW(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRyNstsudorule_enablecBs&eZedƒZd„Zd„ZRS(sEnable a Sudo Rule.cKs†|jj}|jj|ƒ}idd6}y|j||ƒWn7tjk rUn$tjk rx|jj|ƒnXtdt ƒS(NRhRRI( Rltbackendtget_dnt update_entryRt EmptyModlistR|R}tdictRc(RORRQRmRnRo((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytexecuteWs  cKs|jtdƒ|ƒdS(NsEnabled Sudo Rule "%s"(t print_dashedR(ROttextuiRIRRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytoutput_for_clifs(RURVRRWR‹RŽ(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR…Ts  tsudorule_disablecBs&eZedƒZd„Zd„ZRS(sDisable a Sudo Rule.cKs†|jj}|jj|ƒ}idd6}y|j||ƒWn7tjk rUn$tjk rx|jj|ƒnXtdt ƒS(NtFALSERRI( RlR†R‡RˆRR‰R|R}RŠRc(RORRQRmRnRo((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR‹os  cKs|jtdƒ|ƒdS(NsDisabled Sudo Rule "%s"(RŒR(RORRIRRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRŽ~s(RURVRRWR‹RŽ(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRls  tsudorule_add_allow_commandcBs,eZedƒZdgZdZd„ZRS(s;Add commands and sudo command groups affected by Sudo Rule.R"s%i object added.s%i objects added.c OsŒt|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXt |dƒrˆtj dt dƒƒ‚n|S(NRRus4commands cannot be added when command category='all'( RiRjRkR{RlR^RR|R}RR~R( RORmRntfoundt not_foundRPRQR‚Rƒ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRqŠs"(s%i object added.s%i objects added.(RURVRRWtmember_attributestmember_count_outRq(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR‘„s  tsudorule_remove_allow_commandcBs#eZedƒZdgZdZRS(s>Remove commands and sudo command groups affected by Sudo Rule.R"s%i object removed.s%i objects removed.(s%i object removed.s%i objects removed.(RURVRRWR”R•(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR–˜s  tsudorule_add_deny_commandcBs,eZedƒZdgZdZd„ZRS(s;Add commands and sudo command groups affected by Sudo Rule.R#s%i object added.s%i objects added.c OsŒt|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXt |dƒrˆtj dt dƒƒ‚n|S(NRRus4commands cannot be added when command category='all'( RiRjRkR{RlR^RR|R}RR~R( RORmRnR’R“RPRQR‚Rƒ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRq§s"(s%i object added.s%i objects added.(RURVRRWR”R•Rq(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR—¡s  tsudorule_remove_deny_commandcBs#eZedƒZdgZdZRS(s>Remove commands and sudo command groups affected by Sudo Rule.R#s%i object removed.s%i objects removed.(s%i object removed.s%i objects removed.(RURVRRWR”R•(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR˜´s  tsudorule_add_usercBs5eZedƒZdgZdZd„Zd„ZRS(s+Add users and groups affected by Sudo Rule.R s%i object added.s%i objects added.c Osžt|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXt |dƒrˆtj dt dƒƒ‚nt d||||ƒS(NRRus.users cannot be added when user category='all'R+( RiRjRkR{RlR^RR|R}RR~Rtadd_external_pre_callback( RORmRnR’R“RPRQR‚Rƒ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRqÃs"c Os:t|tƒst‚tddd|||||||ƒ S(NR R+R(RiRjRktadd_external_post_callback(RORmt completedtfailedRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyt post_callbackÍs(s%i object added.s%i objects added.(RURVRRWR”R•RqRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR™½s    tsudorule_remove_usercBs,eZedƒZdgZdZd„ZRS(s.Remove users and groups affected by Sudo Rule.R s%i object removed.s%i objects removed.c Os:t|tƒst‚tddd|||||||ƒ S(NR R+R(RiRjRktremove_external_post_callback(RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRžÚs(s%i object removed.s%i objects removed.(RURVRRWR”R•Rž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRŸÔs  tsudorule_add_hostcBs5eZedƒZdgZdZd„Zd„ZRS(s/Add hosts and hostgroups affected by Sudo Rule.R!s%i object added.s%i objects added.c Osžt|tƒst‚y"|j||jjƒ\}}Wn$tjk r]|jj|ŒnXt |dƒrˆtj dt dƒƒ‚nt d||||ƒS(NRRus.hosts cannot be added when host category='all'R-( RiRjRkR{RlR^RR|R}RR~RRš( RORmRnR’R“RPRQR‚Rƒ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRqçs"c Os:t|tƒst‚tddd|||||||ƒ S(NR!R-t externalhost(RiRjRkR›(RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRžñs(s%i object added.s%i objects added.(RURVRRWR”R•RqRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR¡ás    tsudorule_remove_hostcBs,eZedƒZdgZdZd„ZRS(s2Remove hosts and hostgroups affected by Sudo Rule.R!s%i object removed.s%i objects removed.c Os:t|tƒst‚tddd|||||||ƒ S(NR!R-R¢(RiRjRkR (RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRžþs(s%i object removed.s%i objects removed.(RURVRRWR”R•Rž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR£øs  tsudorule_add_runasusercBs5eZedƒZdgZdZd„Zd„ZRS(s,Add users and groups for Sudo to execute as.R%s%i object added.s%i objects added.c Os~t|tƒst‚d„}y"|j||jjƒ\}} Wn$tjk rf|jj|ŒnXt | dƒs…t | dƒr tj dt dƒƒ‚nd|krxU|dD]F} || ƒs·tj ddd t t d ƒƒtd| ƒƒ‚q·q·Wnd |krhxU|d D]F} || ƒstj ddd t t d ƒƒtd| ƒƒ‚qqWntd||||ƒS( NcSs&t|ƒ}|jƒdkr"tStS(NuALL(tunicodetuppertFalseRc(trunastv((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytcheck_validity s R'R(RusCusers cannot be added when runAs user or runAs group category='all'R+R s runas-userR s3RunAsUser does not accept '%(name)s' as a user nameR,s4RunAsUser does not accept '%(name)s' as a group name(RiRjRkR{RlR^RR|R}RR~RR R¥RŠRš( RORmRnRoRpRPRQRªR‚RƒR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRq s, "    c Os:t|tƒst‚tddd|||||||ƒ S(NR%R+tipasudorunasextuser(RiRjRkR›(RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRž)s(s%i object added.s%i objects added.(RURVRRWR”R•RqRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR¤s    tsudorule_remove_runasusercBs,eZedƒZdgZdZd„ZRS(s/Remove users and groups for Sudo to execute as.R%s%i object removed.s%i objects removed.c Os:t|tƒst‚tddd|||||||ƒ S(NR%R+R«(RiRjRkR (RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRž6s(s%i object removed.s%i objects removed.(RURVRRWR”R•Rž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR¬0s  tsudorule_add_runasgroupcBs5eZedƒZdgZdZd„Zd„ZRS(s!Add group for Sudo to execute as.R&s%i object added.s%i objects added.c Ost|tƒst‚d„}y"|j||jjƒ\}} Wn$tjk rf|jj|ŒnXt | dƒs…t | dƒr tj dt dƒƒ‚nd|krxU|dD]F} || ƒs·tj ddd t t d ƒƒtd| ƒƒ‚q·q·Wntd||||ƒS( NcSs&t|ƒ}|jƒdkr"tStS(NuALL(R¥R¦R§Rc(R¨R©((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRªEs R'R(RusCusers cannot be added when runAs user or runAs group category='all'R,R s runas-groupR s5RunAsGroup does not accept '%(name)s' as a group name(RiRjRkR{RlR^RR|R}RR~RR R¥RŠRš( RORmRnRoRpRPRQRªR‚RƒR ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRqCs  "  c Os:t|tƒst‚tddd|||||||ƒ S(NR&R,tipasudorunasextgroup(RiRjRkR›(RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRž\s(s%i object added.s%i objects added.(RURVRRWR”R•RqRž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR­=s    tsudorule_remove_runasgroupcBs,eZedƒZdgZdZd„ZRS(s$Remove group for Sudo to execute as.R&s%i object removed.s%i objects removed.c Os:t|tƒst‚tddd|||||||ƒ S(NR&R,R®(RiRjRkR (RORmRœRRnRoRPRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRžis(s%i object removed.s%i objects removed.(RURVRRWR”R•Rž(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR¯cs  tsudorule_add_optioncBsPeZedƒZejZeddddedƒƒfZd„Z d„Z RS(sAdd an option to the Sudo Rule.R$R1t sudooptionR3s Sudo OptioncKs^|jj}|jj|ƒ}|djƒs=tjƒ‚n|j|dgƒ\}}yA|d|dkr|jdgƒj|dƒn tj ‚Wn.t k rÉ|jdgƒj|dƒnXy|j ||ƒWn7tjk rôn$tj k r|jj |ƒnX|jj}|j||ƒ\}}t||}td|d|ƒS(NR$RIR(RlR†R‡tstripRR‰R{t setdefaulttappendtDuplicateEntrytKeyErrorRˆR|R}R^t entry_to_dictRŠ(RORRQRmRnRoRp((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR‹{s.    cKsM|jtdƒtd|dd|ƒƒtt|ƒj||||dS(Ns1Added option "%(option)s" to Sudo Rule "%(rule)s"toptionR$RJ(RŒRRŠtsuperR°RŽ(RORRIRRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRŽ›s( RURVRRWtoutputtstandard_entryt has_outputRt takes_optionsR‹RŽ(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR°ps    tsudorule_remove_optioncBsPeZedƒZejZeddddedƒƒfZd„Z d„Z RS(s Remove an option from Sudo Rule.R$R1R±R3s Sudo OptioncKsg|jj}|jj|ƒ}|djƒs=tjƒ‚n|j|dgƒ\}}yd|d|dkrŸ|jdgƒj|dƒ|j ||ƒntj ddd|dƒ‚Wnbt k rÑ}nPt k rýtj ddd|dƒ‚n$tj k r |jj|ƒnX|jj}|j||ƒ\}}t||}td|d|ƒS(NR$tattrRRI(RlR†R‡R²RR‰R{R³tremoveRˆtAttrValueNotFoundt ValueErrorR¶R|R}R^R·RŠ(RORRQRmRnRoteRp((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR‹°s2      cKsM|jtdƒtd|dd|ƒƒtt|ƒj||||dS(Ns5Removed option "%(option)s" from Sudo Rule "%(rule)s"R¸R$RJ(RŒRRŠR¹R¾RŽ(RORRIRRQ((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyRŽÓs( RURVRRWRºR»R¼RR½R‹RŽ(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pyR¾¥s    #N(1tipalibRRRRRtipalib.plugins.baseldaptipalib.plugins.hbacruleRRRRWttopicRRRRt LDAPObjectRtregistert LDAPCreateRgt LDAPDeleteRst LDAPUpdateRtt LDAPSearchR„t LDAPRetrieveRyt LDAPQueryR…Rt LDAPAddMemberR‘tLDAPRemoveMemberR–R—R˜R™RŸR¡R£R¤R¬R­R¯R°R¾(((s5/home/mkosek/freeipa-clean/ipalib/plugins/sudorule.pytsn 1     ª   "             )  #  2 3freeipa-3.3.4/ipalib/plugins/privilege.py0000664000175000017500000001136112270466515017775 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . from ipalib.plugins.baseldap import * from ipalib import api, _, ngettext __doc__ = _(""" Privileges A privilege combines permissions into a logical task. A permission provides the rights to do a single task. There are some IPA operations that require multiple permissions to succeed. A privilege is where permissions are combined in order to perform a specific task. For example, adding a user requires the following permissions: * Creating a new user entry * Resetting a user password * Adding the new user to the default IPA users group Combining these three low-level tasks into a higher level task in the form of a privilege named "Add User" makes it easier to manage Roles. A privilege may not contain other privileges. See role and permission for additional information. """) class privilege(LDAPObject): """ Privilege object. """ container_dn = api.env.container_privilege object_name = _('privilege') object_name_plural = _('privileges') object_class = ['nestedgroup', 'groupofnames'] default_attributes = ['cn', 'description', 'member', 'memberof'] attribute_members = { 'member': ['role'], 'memberof': ['permission'], } reverse_members = { 'member': ['permission'], } rdn_is_primary_key = True label = _('Privileges') label_singular = _('Privilege') takes_params = ( Str('cn', cli_name='name', label=_('Privilege name'), primary_key=True, ), Str('description', cli_name='desc', label=_('Description'), doc=_('Privilege description'), ), ) api.register(privilege) class privilege_add(LDAPCreate): __doc__ = _('Add a new privilege.') msg_summary = _('Added privilege "%(value)s"') api.register(privilege_add) class privilege_del(LDAPDelete): __doc__ = _('Delete a privilege.') msg_summary = _('Deleted privilege "%(value)s"') api.register(privilege_del) class privilege_mod(LDAPUpdate): __doc__ = _('Modify a privilege.') msg_summary = _('Modified privilege "%(value)s"') api.register(privilege_mod) class privilege_find(LDAPSearch): __doc__ = _('Search for privileges.') msg_summary = ngettext( '%(count)d privilege matched', '%(count)d privileges matched', 0 ) api.register(privilege_find) class privilege_show(LDAPRetrieve): __doc__ = _('Display information about a privilege.') api.register(privilege_show) class privilege_add_member(LDAPAddMember): __doc__ = _('Add members to a privilege.') NO_CLI=True api.register(privilege_add_member) class privilege_remove_member(LDAPRemoveMember): """ Remove members from a privilege """ NO_CLI=True api.register(privilege_remove_member) class privilege_add_permission(LDAPAddReverseMember): __doc__ = _('Add permissions to a privilege.') show_command = 'privilege_show' member_command = 'permission_add_member' reverse_attr = 'permission' member_attr = 'privilege' has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of permissions added'), ), ) api.register(privilege_add_permission) class privilege_remove_permission(LDAPRemoveReverseMember): __doc__ = _('Remove permissions from a privilege.') show_command = 'privilege_show' member_command = 'permission_remove_member' reverse_attr = 'permission' member_attr = 'privilege' permission_count_out = ('%i permission removed.', '%i permissions removed.') has_output = ( output.Entry('result'), output.Output('failed', type=dict, doc=_('Members that could not be added'), ), output.Output('completed', type=int, doc=_('Number of permissions removed'), ), ) api.register(privilege_remove_permission) freeipa-3.3.4/ipalib/plugins/host.py0000664000175000017500000011442512271663206016766 0ustar mkosekmkosek# Authors: # Rob Crittenden # Pavel Zuna # # 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 . import platform import os import sys from nss.error import NSPRError import nss.nss as nss import netaddr import string from ipalib import api, errors, util from ipalib import Str, Flag, Bytes from ipalib.plugins.baseldap import * from ipalib.plugins.service import (split_principal, validate_certificate, set_certificate_attrs, ticket_flags_params, update_krbticketflags, set_kerberos_attrs) from ipalib.plugins.dns import (dns_container_exists, _record_types, add_records_for_host_validation, add_records_for_host, _hostname_validator, get_reverse_zone) from ipalib.plugins.dns import get_reverse_zone from ipalib import _, ngettext from ipalib import x509 from ipalib.request import context from ipalib.util import (normalize_sshpubkey, validate_sshpubkey_no_options, convert_sshpubkey_post) from ipapython.ipautil import ipa_generate_password, CheckedIPAddress from ipapython.ssh import SSHPublicKey from ipapython.dn import DN __doc__ = _(""" Hosts/Machines A host represents a machine. It can be used in a number of contexts: - service entries are associated with a host - a host stores the host/ service principal - a host can be used in Host-based Access Control (HBAC) rules - every enrolled client generates a host entry ENROLLMENT: There are three enrollment scenarios when enrolling a new client: 1. You are enrolling as a full administrator. The host entry may exist or not. A full administrator is a member of the hostadmin role or the admins group. 2. You are enrolling as a limited administrator. The host must already exist. A limited administrator is a member a role with the Host Enrollment privilege. 3. The host has been created with a one-time password. RE-ENROLLMENT: Host that has been enrolled at some point, and lost its configuration (e.g. VM destroyed) can be re-enrolled. For more information, consult the manual pages for ipa-client-install. A host can optionally store information such as where it is located, the OS that it runs, etc. EXAMPLES: Add a new host: ipa host-add --location="3rd floor lab" --locality=Dallas test.example.com Delete a host: ipa host-del test.example.com Add a new host with a one-time password: ipa host-add --os='Fedora 12' --password=Secret123 test.example.com Add a new host with a random one-time password: ipa host-add --os='Fedora 12' --random test.example.com Modify information about a host: ipa host-mod --os='Fedora 12' test.example.com Remove SSH public keys of a host and update DNS to reflect this change: ipa host-mod --sshpubkey= --updatedns test.example.com Disable the host Kerberos key, SSL certificate and all of its services: ipa host-disable test.example.com Add a host that can manage this host's keytab and certificate: ipa host-add-managedby --hosts=test2 test """) # Characters to be used by random password generator # The set was chosen to avoid the need for escaping the characters by user host_pwd_chars=string.digits + string.ascii_letters + '_,.@+-=' def remove_fwd_ptr(ipaddr, host, domain, recordtype): api.log.debug('deleting ipaddr %s' % ipaddr) try: revzone, revname = get_reverse_zone(ipaddr) # in case domain is in FQDN form with a trailing dot, we needn't add # another one, in case it has no trailing dot, dnsrecord-del will # normalize the entry delkw = { 'ptrrecord' : "%s.%s" % (host, domain) } api.Command['dnsrecord_del'](revzone, revname, **delkw) except errors.NotFound: pass try: delkw = { recordtype : ipaddr } api.Command['dnsrecord_del'](domain, host, **delkw) except errors.NotFound: pass def update_sshfp_record(zone, record, entry_attrs): if 'ipasshpubkey' not in entry_attrs: return pubkeys = entry_attrs['ipasshpubkey'] or () sshfps=[] for pubkey in pubkeys: try: sshfp = SSHPublicKey(pubkey).fingerprint_dns_sha1() except ValueError, UnicodeDecodeError: continue if sshfp is not None: sshfps.append(sshfp) try: sshfp = SSHPublicKey(pubkey).fingerprint_dns_sha256() except ValueError, UnicodeDecodeError: continue if sshfp is not None: sshfps.append(sshfp) try: api.Command['dnsrecord_mod'](zone, record, sshfprecord=sshfps) except errors.EmptyModlist: pass host_output_params = ( Flag('has_keytab', label=_('Keytab'), ), Str('managedby_host', label='Managed by', ), Str('managing_host', label='Managing', ), Str('subject', label=_('Subject'), ), Str('serial_number', label=_('Serial Number'), ), Str('serial_number_hex', label=_('Serial Number (hex)'), ), Str('issuer', label=_('Issuer'), ), Str('valid_not_before', label=_('Not Before'), ), Str('valid_not_after', label=_('Not After'), ), Str('md5_fingerprint', label=_('Fingerprint (MD5)'), ), Str('sha1_fingerprint', label=_('Fingerprint (SHA1)'), ), Str('revocation_reason?', label=_('Revocation reason'), ), Str('managedby', label=_('Failed managedby'), ), Str('sshpubkeyfp*', label=_('SSH public key fingerprint'), ), ) def validate_ipaddr(ugettext, ipaddr): """ Verify that we have either an IPv4 or IPv6 address. """ try: ip = CheckedIPAddress(ipaddr, match_local=False) except Exception, e: return unicode(e) return None def normalize_hostname(hostname): """Use common fqdn form without the trailing dot""" if hostname.endswith(u'.'): hostname = hostname[:-1] hostname = hostname.lower() return hostname class host(LDAPObject): """ Host object. """ container_dn = api.env.container_host object_name = _('host') object_name_plural = _('hosts') object_class = ['ipaobject', 'nshost', 'ipahost', 'pkiuser', 'ipaservice'] # object_class_config = 'ipahostobjectclasses' search_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', 'nshardwareplatform', 'nsosversion', 'managedby' ] default_attributes = [ 'fqdn', 'description', 'l', 'nshostlocation', 'krbprincipalname', 'nshardwareplatform', 'nsosversion', 'usercertificate', 'memberof', 'managedby', 'memberindirect', 'memberofindirect', 'macaddress', 'userclass' ] uuid_attribute = 'ipauniqueid' attribute_members = { 'enrolledby': ['user'], 'memberof': ['hostgroup', 'netgroup', 'role', 'hbacrule', 'sudorule'], 'managedby': ['host'], 'managing': ['host'], 'memberofindirect': ['hostgroup', 'netgroup', 'role', 'hbacrule', 'sudorule'], } bindable = True relationships = { 'memberof': ('Member Of', 'in_', 'not_in_'), 'enrolledby': ('Enrolled by', 'enroll_by_', 'not_enroll_by_'), 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), 'managing': ('Managing', 'man_', 'not_man_'), } password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] label = _('Hosts') label_singular = _('Host') takes_params = ( Str('fqdn', _hostname_validator, cli_name='hostname', label=_('Host name'), primary_key=True, normalizer=normalize_hostname, ), Str('description?', cli_name='desc', label=_('Description'), doc=_('A description of this host'), ), Str('l?', cli_name='locality', label=_('Locality'), doc=_('Host locality (e.g. "Baltimore, MD")'), ), Str('nshostlocation?', cli_name='location', label=_('Location'), doc=_('Host location (e.g. "Lab 2")'), ), Str('nshardwareplatform?', cli_name='platform', label=_('Platform'), doc=_('Host hardware platform (e.g. "Lenovo T61")'), ), Str('nsosversion?', cli_name='os', label=_('Operating system'), doc=_('Host operating system and version (e.g. "Fedora 9")'), ), Str('userpassword?', cli_name='password', label=_('User password'), doc=_('Password used in bulk enrollment'), ), Flag('random?', doc=_('Generate a random password to be used in bulk enrollment'), flags=('no_search', 'virtual_attribute'), default=False, ), Str('randompassword?', label=_('Random password'), flags=('no_create', 'no_update', 'no_search', 'virtual_attribute'), ), Bytes('usercertificate?', validate_certificate, cli_name='certificate', label=_('Certificate'), doc=_('Base-64 encoded server certificate'), ), Str('krbprincipalname?', label=_('Principal name'), flags=['no_create', 'no_update', 'no_search'], ), Str('macaddress*', normalizer=lambda value: value.upper(), pattern='^([a-fA-F0-9]{2}[:|\-]?){5}[a-fA-F0-9]{2}$', pattern_errmsg='Must be of the form HH:HH:HH:HH:HH:HH, where each H is a hexadecimal character.', csv=True, label=_('MAC address'), doc=_('Hardware MAC address(es) on this host'), ), Str('ipasshpubkey*', validate_sshpubkey_no_options, cli_name='sshpubkey', label=_('SSH public key'), normalizer=normalize_sshpubkey, csv=True, flags=['no_search'], ), Str('userclass*', cli_name='class', label=_('Class'), doc=_('Host category (semantics placed on this attribute are for ' 'local interpretation)'), ), ) + ticket_flags_params def get_dn(self, *keys, **options): hostname = keys[-1] dn = super(host, self).get_dn(hostname, **options) try: self.backend.get_entry(dn, ['']) except errors.NotFound: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( 'serverhostname', hostname, self.object_class, [''], DN(self.container_dn, api.env.basedn)) except errors.NotFound: pass return dn def get_managed_hosts(self, dn): host_filter = 'managedBy=%s' % dn host_attrs = ['fqdn'] ldap = self.api.Backend.ldap2 managed_hosts = [] try: (hosts, truncated) = ldap.find_entries( base_dn=DN(self.container_dn, api.env.basedn), filter=host_filter, attrs_list=host_attrs) for host in hosts: managed_hosts.append(host[0]) except errors.NotFound: return [] return managed_hosts def suppress_netgroup_memberof(self, ldap, entry_attrs): """ We don't want to show managed netgroups so remove them from the memberofindirect list. """ ng_container = DN(api.env.container_netgroup, api.env.basedn) for member in list(entry_attrs.get('memberofindirect', [])): memberdn = DN(member) if not memberdn.endswith(ng_container): continue filter = ldap.make_filter({'objectclass': 'mepmanagedentry'}) try: ldap.get_entries(memberdn, ldap.SCOPE_BASE, filter, ['']) except errors.NotFound: pass else: entry_attrs['memberofindirect'].remove(member) api.register(host) class host_add(LDAPCreate): __doc__ = _('Add a new host.') has_output_params = LDAPCreate.has_output_params + host_output_params msg_summary = _('Added host "%(value)s"') member_attributes = ['managedby'] takes_options = LDAPCreate.takes_options + ( Flag('force', label=_('Force'), doc=_('force host name even if not in DNS'), ), Flag('no_reverse', doc=_('skip reverse DNS detection'), ), Str('ip_address?', validate_ipaddr, doc=_('Add the host to DNS with this IP address'), label=_('IP Address'), ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) if options.get('ip_address') and dns_container_exists(ldap): parts = keys[-1].split('.') host = parts[0] domain = unicode('.'.join(parts[1:])) check_reverse = not options.get('no_reverse', False) add_records_for_host_validation('ip_address', host, domain, options['ip_address'], check_forward=True, check_reverse=check_reverse) if not options.get('force', False) and not 'ip_address' in options: util.validate_host_dns(self.log, keys[-1]) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] entry_attrs['cn'] = keys[-1] entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0] if not entry_attrs.get('userpassword', False) and not options.get('random', False): entry_attrs['krbprincipalname'] = 'host/%s@%s' % ( keys[-1], self.api.env.realm ) if 'krbprincipalaux' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipalaux') if 'krbprincipal' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbprincipal') else: if 'krbprincipalaux' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipalaux') if 'krbprincipal' in entry_attrs['objectclass']: entry_attrs['objectclass'].remove('krbprincipal') if options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) cert = options.get('usercertificate') if cert: cert = x509.normalize_certificate(cert) x509.verify_cert_subject(ldap, keys[-1], cert) entry_attrs['usercertificate'] = cert entry_attrs['managedby'] = dn entry_attrs['objectclass'].append('ieee802device') entry_attrs['objectclass'].append('ipasshhost') update_krbticketflags(ldap, entry_attrs, attrs_list, options, False) if 'krbticketflags' in entry_attrs: entry_attrs['objectclass'].append('krbticketpolicyaux') return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) exc = None if dns_container_exists(ldap): try: parts = keys[-1].split('.') host = parts[0] domain = unicode('.'.join(parts[1:])) if options.get('ip_address'): add_reverse = not options.get('no_reverse', False) add_records_for_host(host, domain, options['ip_address'], add_forward=True, add_reverse=add_reverse) del options['ip_address'] update_sshfp_record(domain, unicode(parts[0]), entry_attrs) except Exception, e: exc = e if options.get('random', False): try: entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) except AttributeError: # On the off-chance some other extension deletes this from the # context, don't crash. pass if exc: raise errors.NonFatalError( reason=_('The host was added but the DNS update failed with: %(exc)s') % dict(exc=exc) ) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(dn) self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_password']: # If an OTP is set there is no keytab, at least not one # fetched anywhere. entry_attrs['has_keytab'] = False convert_sshpubkey_post(ldap, dn, entry_attrs) return dn api.register(host_add) class host_del(LDAPDelete): __doc__ = _('Delete a host.') msg_summary = _('Deleted host "%(value)s"') member_attributes = ['managedby'] takes_options = ( Flag('updatedns?', doc=_('Remove entries from DNS'), default=False, ), ) def pre_callback(self, ldap, dn, *keys, **options): assert isinstance(dn, DN) # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # Remove all service records for this host truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: api.Command['service_del'](principal) updatedns = options.get('updatedns', False) if updatedns: try: updatedns = dns_container_exists(ldap) except errors.NotFound: updatedns = False if updatedns: # Remove DNS entries parts = fqdn.split('.') domain = unicode('.'.join(parts[1:])) try: result = api.Command['dnszone_show'](domain)['result'] domain = result['idnsname'][0] except errors.NotFound: self.obj.handle_not_found(*keys) # Get all forward resources for this host records = api.Command['dnsrecord_find'](domain, idnsname=parts[0])['result'] for record in records: if 'arecord' in record: remove_fwd_ptr(record['arecord'][0], parts[0], domain, 'arecord') if 'aaaarecord' in record: remove_fwd_ptr(record['aaaarecord'][0], parts[0], domain, 'aaaarecord') else: # Try to delete all other record types too _attribute_types = [str('%srecord' % t.lower()) for t in _record_types] for attr in _attribute_types: if attr not in ['arecord', 'aaaarecord'] and attr in record: for i in xrange(len(record[attr])): if (record[attr][i].endswith(parts[0]) or record[attr][i].endswith(fqdn+'.')): delkw = { unicode(attr) : record[attr][i] } api.Command['dnsrecord_del'](domain, record['idnsname'][0], **delkw) break if self.api.env.enable_ra: try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.single_value('usercertificate', None) if cert: cert = x509.normalize_certificate(cert) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # removing the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr return dn api.register(host_del) class host_mod(LDAPUpdate): __doc__ = _('Modify information about a host.') has_output_params = LDAPUpdate.has_output_params + host_output_params msg_summary = _('Modified host "%(value)s"') member_attributes = ['managedby'] takes_options = LDAPUpdate.takes_options + ( Str('krbprincipalname?', cli_name='principalname', label=_('Principal name'), doc=_('Kerberos principal name for this host'), attribute=True, ), Flag('updatedns?', doc=_('Update DNS entries'), default=False, ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # Allow an existing OTP to be reset but don't allow a OTP to be # added to an enrolled host. if options.get('userpassword') or options.get('random'): entry = {} self.obj.get_password_attributes(ldap, dn, entry) if not entry['has_password'] and entry['has_keytab']: raise errors.ValidationError(name='password', error=_('Password cannot be set on enrolled host.')) # Once a principal name is set it cannot be changed if 'cn' in entry_attrs: raise errors.ACIError(info=_('cn is immutable')) if 'locality' in entry_attrs: entry_attrs['l'] = entry_attrs['locality'] if 'krbprincipalname' in entry_attrs: (dn, entry_attrs_old) = ldap.get_entry( dn, ['objectclass', 'krbprincipalname'] ) if 'krbprincipalname' in entry_attrs_old: msg = 'Principal name already set, it is unchangeable.' raise errors.ACIError(info=msg) obj_classes = entry_attrs_old['objectclass'] if 'krbprincipalaux' not in obj_classes: obj_classes.append('krbprincipalaux') entry_attrs['objectclass'] = obj_classes cert = x509.normalize_certificate(entry_attrs.get('usercertificate')) if cert: if self.api.env.enable_ra: x509.verify_cert_subject(ldap, keys[-1], cert) (dn, entry_attrs_old) = ldap.get_entry(dn, ['usercertificate']) oldcert = entry_attrs_old.single_value('usercertificate', None) if oldcert: oldcert = x509.normalize_certificate(oldcert) try: serial = x509.get_serial_number(oldcert, x509.DER) serial = unicode(serial) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke']( serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # modifying the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr entry_attrs['usercertificate'] = cert if options.get('random'): entry_attrs['userpassword'] = ipa_generate_password(characters=host_pwd_chars) setattr(context, 'randompassword', entry_attrs['userpassword']) if 'macaddress' in entry_attrs: if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: (_dn, _entry_attrs) = ldap.get_entry( dn, ['objectclass'] ) obj_classes = _entry_attrs['objectclass'] if 'ieee802device' not in obj_classes: obj_classes.append('ieee802device') entry_attrs['objectclass'] = obj_classes if options.get('updatedns', False) and dns_container_exists(ldap): parts = keys[-1].split('.') domain = unicode('.'.join(parts[1:])) try: result = api.Command['dnszone_show'](domain)['result'] domain = result['idnsname'][0] except errors.NotFound: self.obj.handle_not_found(*keys) update_sshfp_record(domain, unicode(parts[0]), entry_attrs) if 'ipasshpubkey' in entry_attrs: if 'objectclass' in entry_attrs: obj_classes = entry_attrs['objectclass'] else: (_dn, _entry_attrs) = ldap.get_entry(dn, ['objectclass']) obj_classes = entry_attrs['objectclass'] = _entry_attrs['objectclass'] if 'ipasshhost' not in obj_classes: obj_classes.append('ipasshhost') update_krbticketflags(ldap, entry_attrs, attrs_list, options, True) if 'krbticketflags' in entry_attrs: if 'objectclass' not in entry_attrs: entry_attrs_old = ldap.get_entry(dn, ['objectclass']) entry_attrs['objectclass'] = entry_attrs_old['objectclass'] if 'krbticketpolicyaux' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append('krbticketpolicyaux') return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) if options.get('random', False): entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword')) set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_password']: # If an OTP is set there is no keytab, at least not one # fetched anywhere. entry_attrs['has_keytab'] = False if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(dn) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) convert_sshpubkey_post(ldap, dn, entry_attrs) return dn api.register(host_mod) class host_find(LDAPSearch): __doc__ = _('Search for hosts.') has_output_params = LDAPSearch.has_output_params + host_output_params msg_summary = ngettext( '%(count)d host matched', '%(count)d hosts matched', 0 ) member_attributes = ['memberof', 'enrolledby', 'managedby'] def get_options(self): for option in super(host_find, self).get_options(): yield option # "managing" membership has to be added and processed separately for option in self.get_member_options('managing'): yield option def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options): assert isinstance(base_dn, DN) if 'locality' in attrs_list: attrs_list.remove('locality') attrs_list.append('l') if 'man_host' in options or 'not_man_host' in options: hosts = [] if options.get('man_host') is not None: for pkey in options.get('man_host', []): dn = self.obj.get_dn(pkey) try: (dn, entry_attrs) = ldap.get_entry(dn, ['managedby']) except errors.NotFound: self.obj.handle_not_found(pkey) hosts.append(set(entry_attrs.get('managedby', ''))) hosts = list(reduce(lambda s1, s2: s1 & s2, hosts)) if not hosts: # There is no host managing _all_ hosts in --man-hosts filter = ldap.combine_filters( (filter, '(objectclass=disabled)'), ldap.MATCH_ALL ) not_hosts = [] if options.get('not_man_host') is not None: for pkey in options.get('not_man_host', []): dn = self.obj.get_dn(pkey) try: (dn, entry_attrs) = ldap.get_entry(dn, ['managedby']) except errors.NotFound: self.obj.handle_not_found(pkey) not_hosts += entry_attrs.get('managedby', []) not_hosts = list(set(not_hosts)) for target_hosts, filter_op in ((hosts, ldap.MATCH_ANY), (not_hosts, ldap.MATCH_NONE)): hosts_avas = [DN(host)[0][0] for host in target_hosts] hosts_filters = [ldap.make_filter_from_attr(ava.attr, ava.value) for ava in hosts_avas] hosts_filter = ldap.combine_filters(hosts_filters, filter_op) filter = ldap.combine_filters( (filter, hosts_filter), ldap.MATCH_ALL ) return (filter.replace('locality', 'l'), base_dn, scope) def post_callback(self, ldap, entries, truncated, *args, **options): if options.get('pkey_only', False): return truncated for entry in entries: (dn, entry_attrs) = entry set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) self.obj.get_password_attributes(ldap, dn, entry_attrs) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) if entry_attrs['has_password']: # If an OTP is set there is no keytab, at least not one # fetched anywhere. entry_attrs['has_keytab'] = False if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(entry[0]) convert_sshpubkey_post(ldap, dn, entry_attrs) return truncated api.register(host_find) class host_show(LDAPRetrieve): __doc__ = _('Display information about a host.') has_output_params = LDAPRetrieve.has_output_params + host_output_params takes_options = LDAPRetrieve.takes_options + ( Str('out?', doc=_('file to store certificate in'), ), ) member_attributes = ['managedby'] def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_password']: # If an OTP is set there is no keytab, at least not one # fetched anywhere. entry_attrs['has_keytab'] = False set_certificate_attrs(entry_attrs) set_kerberos_attrs(entry_attrs, options) if options.get('all', False): entry_attrs['managing'] = self.obj.get_managed_hosts(dn) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) convert_sshpubkey_post(ldap, dn, entry_attrs) return dn def forward(self, *keys, **options): if 'out' in options: util.check_writable_file(options['out']) result = super(host_show, self).forward(*keys, **options) if 'usercertificate' in result['result']: x509.write_certificate(result['result']['usercertificate'][0], options['out']) result['summary'] = _('Certificate stored in file \'%(file)s\'') % dict(file=options['out']) return result else: raise errors.NoCertificateError(entry=keys[-1]) else: return super(host_show, self).forward(*keys, **options) api.register(host_show) class host_disable(LDAPQuery): __doc__ = _('Disable the Kerberos key, SSL certificate and all services of a host.') has_output = output.standard_value msg_summary = _('Disabled host "%(value)s"') def execute(self, *keys, **options): ldap = self.obj.backend # If we aren't given a fqdn, find it if _hostname_validator(None, keys[-1]) is not None: hostentry = api.Command['host_show'](keys[-1])['result'] fqdn = hostentry['fqdn'][0] else: fqdn = keys[-1] host_is_master(ldap, fqdn) # See if we actually do anthing here, and if not raise an exception done_work = False truncated = True while truncated: try: ret = api.Command['service_find'](fqdn) truncated = ret['truncated'] services = ret['result'] except errors.NotFound: break else: for entry_attrs in services: principal = entry_attrs['krbprincipalname'][0] (service, hostname, realm) = split_principal(principal) if hostname.lower() == fqdn: try: api.Command['service_disable'](principal) done_work = True except errors.AlreadyInactive: pass dn = self.obj.get_dn(*keys, **options) try: (dn, entry_attrs) = ldap.get_entry(dn, ['usercertificate']) except errors.NotFound: self.obj.handle_not_found(*keys) cert = entry_attrs.single_value('usercertificate', None) if cert: if self.api.env.enable_ra: cert = x509.normalize_certificate(cert) try: serial = unicode(x509.get_serial_number(cert, x509.DER)) try: result = api.Command['cert_show'](serial)['result'] if 'revocation_reason' not in result: try: api.Command['cert_revoke'](serial, revocation_reason=4) except errors.NotImplementedError: # some CA's might not implement revoke pass except errors.NotImplementedError: # some CA's might not implement revoke pass except NSPRError, nsprerr: if nsprerr.errno == -8183: # If we can't decode the cert them proceed with # disabling the host. self.log.info("Problem decoding certificate %s" % nsprerr.args[1]) else: raise nsprerr # Remove the usercertificate altogether ldap.update_entry(dn, {'usercertificate': None}) done_work = True self.obj.get_password_attributes(ldap, dn, entry_attrs) if entry_attrs['has_keytab']: ldap.remove_principal_key(dn) done_work = True if not done_work: raise errors.AlreadyInactive() return dict( result=True, value=keys[0], ) def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) return dn api.register(host_disable) class host_add_managedby(LDAPAddMember): __doc__ = _('Add hosts that can manage this host.') member_attributes = ['managedby'] has_output_params = LDAPAddMember.has_output_params + host_output_params allow_same = True def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) return (completed, dn) api.register(host_add_managedby) class host_remove_managedby(LDAPRemoveMember): __doc__ = _('Remove hosts that can manage this host.') member_attributes = ['managedby'] has_output_params = LDAPRemoveMember.has_output_params + host_output_params def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) self.obj.suppress_netgroup_memberof(ldap, entry_attrs) return (completed, dn) api.register(host_remove_managedby) freeipa-3.3.4/ipalib/plugins/passwd.py0000664000175000017500000001020612271663206017302 0ustar mkosekmkosek# Authors: # Rob Crittenden # # 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 . from ipalib import api, errors, util from ipalib import Command from ipalib import Str, Password from ipalib import _ from ipalib import output from ipalib.plugins.user import split_principal, validate_principal, normalize_principal from ipalib.request import context from ipapython.dn import DN __doc__ = _(""" Set a user's password If someone other than a user changes that user's password (e.g., Helpdesk resets it) then the password will need to be changed the first time it is used. This is so the end-user is the only one who knows the password. The IPA password policy controls how often a password may be changed, what strength requirements exist, and the length of the password history. EXAMPLES: To reset your own password: ipa passwd To change another user's password: ipa passwd tuser1 """) # We only need to prompt for the current password when changing a password # for yourself, but the parameter is still required MAGIC_VALUE = u'CHANGING_PASSWORD_FOR_ANOTHER_USER' def get_current_password(principal): """ If the user is changing their own password then return None so the current password is prompted for, otherwise return a fixed value to be ignored later. """ current_principal = util.get_current_principal() if current_principal == normalize_principal(principal): return None else: return MAGIC_VALUE class passwd(Command): __doc__ = _("Set a user's password.") takes_args = ( Str('principal', validate_principal, cli_name='user', label=_('User name'), primary_key=True, autofill=True, default_from=lambda: util.get_current_principal(), normalizer=lambda value: normalize_principal(value), ), Password('password', label=_('New Password'), ), Password('current_password', label=_('Current Password'), confirm=False, default_from=lambda principal: get_current_password(principal), autofill=True, sortorder=-1, ), ) has_output = output.standard_value msg_summary = _('Changed password for "%(value)s"') def execute(self, principal, password, current_password, **options): """ Execute the passwd operation. The dn should not be passed as a keyword argument as it is constructed by this method. Returns the entry :param principal: The login name or principal of the user :param password: the new password :param current_password: the existing password, if applicable """ ldap = self.api.Backend.ldap2 (dn, entry_attrs) = ldap.find_entry_by_attr( 'krbprincipalname', principal, 'posixaccount', [''], DN(api.env.container_user, api.env.basedn) ) if principal == getattr(context, 'principal') and \ current_password == MAGIC_VALUE: # No cheating self.log.warn('User attempted to change password using magic value') raise errors.ACIError(info=_('Invalid credentials')) if current_password == MAGIC_VALUE: ldap.modify_password(dn, password) else: ldap.modify_password(dn, password, current_password) return dict( result=True, value=principal, ) api.register(passwd) freeipa-3.3.4/ipalib/plugins/migration.pyc0000664000175000017500000006516012271707517020152 0ustar mkosekmkosekó †fçRc@s×ddlZddlmZmZmZddlmZmZmZmZm Z m Z ddl m Z ddl mZejjo—ejjddgkrÍyddlmZWnek rÉZe‚nXndd lmZdd lmZddlZed ƒZed ƒZed ƒZedƒZedƒZedƒZddfZ eddfddfddfƒZ!d„Z"d„Z#d„Z$d„Z%d„Z&d„Z'd„Z(defd„ƒYZ)ej*e)ƒdS( iÿÿÿÿN(tapiterrorstoutput(tCommandtPasswordtStrtFlagtStrEnumtDNParam(tto_cli(t NO_UPG_MAGICtlitetserver(tldap2(t_(tDNsî Migration to IPA Migrate users and groups from an LDAP server to IPA. This performs an LDAP query against the remote server searching for users and groups in a container. In order to migrate passwords you need to bind as a user that can read the userPassword attribute on the remote server. This is generally restricted to high-level admins such as cn=Directory Manager in 389-ds (this is the default bind user). The default user container is ou=People. The default group container is ou=Groups. Users and groups that already exist on the IPA server are skipped. Two LDAP schemas define how group members are stored: RFC2307 and RFC2307bis. RFC2307bis uses member and uniquemember to specify group members, RFC2307 uses memberUid. The default schema is RFC2307bis. The schema compat feature allows IPA to reformat data for systems that do not support RFC2307bis. It is recommended that this feature is disabled during migration to reduce system overhead. It can be re-enabled after migration. To migrate with it enabled use the "--with-compat" option. Migrated users do not have Kerberos credentials, they have only their LDAP password. To complete the migration process, users need to go to http://ipa.example.com/ipa/migration and authenticate using their LDAP password in order to generate their Kerberos credentials. Migration is disabled by default. Use the command ipa config-mod to enable it: ipa config-mod --enable-migration=TRUE If a base DN is not provided with --basedn then IPA will use either the value of defaultNamingContext if it is set or the first value in namingContexts set in the root of the remote LDAP server. Users are added as members to the default user group. This can be a time-intensive task so during migration this is done in a batch mode for every 100 users. As a result there will be a window in which users will be added to IPA but will not be members of the default user group. EXAMPLES: The simplest migration, accepting all defaults: ipa migrate-ds ldap://ds.example.com:389 Specify the user and group container. This can be used to migrate user and group data from an IPA v1 server: ipa migrate-ds --user-container='cn=users,cn=accounts' \ --group-container='cn=groups,cn=accounts' \ ldap://ds.example.com:389 Since IPA v2 server already contain predefined groups that may collide with groups in migrated (IPA v1) server (for example admins, ipausers), users having colliding group as their primary group may happen to belong to an unknown group on new IPA v2 server. Use --group-overwrite-gid option to overwrite GID of already existing groups to prevent this issue: ipa migrate-ds --group-overwrite-gid \ --user-container='cn=users,cn=accounts' \ --group-container='cn=groups,cn=accounts' \ ldap://ds.example.com:389 Migrated users or groups may have object class and accompanied attributes unknown to the IPA v2 server. These object classes and attributes may be left out of the migration process: ipa migrate-ds --user-container='cn=users,cn=accounts' \ --group-container='cn=groups,cn=accounts' \ --user-ignore-objectclass=radiusprofile \ --user-ignore-attribute=radiusgroupname \ ldap://ds.example.com:389 LOGGING Migration will log warnings and errors to the Apache error log. This file should be evaluated post-migration to correct or investigate any issues that were discovered. For every 100 users migrated an info-level message will be displayed to give the current progress and duration to make it possible to track the progress of migration. If the log level is debug, either by setting debug = True in /etc/ipa/default.conf or /etc/ipa/server.conf, then an entry will be printed for each user added plus a summary when the default user group is updated. sLKerberos principal %s already exists. Use 'ipa user-mod' to set it manually.scUnable to determine if Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually.sTFailed to add user to the default group. Use 'ipa group-add-member' to add manually.s4Migration of LDAP search reference is not supported.s Malformed DNu RFC2307bisuRFC2307tcnsSchema Compatibilitytpluginstconfigc Ks8t|tƒst‚dddg}|j|jdgƒƒ|d} |d} |jddƒ} |d} |d } d |kr«tjd td ƒt d |ƒƒ‚nU|d d| krät j j d|d d|fƒn|d d| kryI| j d |d dddg| dƒ\}}| j|d dƒWqtjk rŽt j j d|d d|fƒ| j|d dƒqtjk rË}t j j d|d d||jfƒqtjk rü}t j j d|d dƒqXn|jdgƒ|djtƒd|d| D]6} | d| j d gƒkrº| j | dƒqºqºWt | ƒdkr]| j d gƒ}|j | ƒ|| d ƒded?ƒd4ed!eƒd$eƒe d@ddAdedBƒdedCƒd4ed!eƒd$eƒe dDddEdedFƒdedGƒd4ed!eƒd$eƒe dHddIdedJƒdedKƒd4ed!eƒd$eƒedLddMdedNƒdedOƒƒedPddQdedRƒdedSƒdTed!edUd$eƒedVdedWƒdedXƒd!eƒedYddZded[ƒded\ƒƒed]dd^ded_ƒded`ƒd!eƒfZejdadbededcƒƒejdddbededeƒƒejdfdbededgƒƒejdhdbedediƒƒfZedjƒZedkƒZedlƒZedmƒZ dn„Z!do„Z"dp„Z#dq„Z$dr„Z%ds„Z&RS({s(Migrate users and groups from DS to IPA.s(&(|%s)(uid=*))tfilter_templatetuserobjectclasst oc_optiontuserignoreobjectclasstoc_blacklist_optiontuserignoreattributetattr_blacklist_optiont pre_callbackt post_callbackt exc_callbackRs(&(|%s)(cn=*))tgroupobjectclasstgroupignoreobjectclasstgroupignoreattributeR!R§tcli_nameR¢tlabelsLDAP URItdocs%LDAP URI of DS server to migrate fromtbindpwtpasswordRtconfirms bind passwordsbinddn?tbind_dnsBind DNtdefaultRsdirectory managertautofillt usercontainertuser_containersUser containers3DN of container for users in DS relative to base DNtoutpeopletgroupcontainertgroup_containersGroup containers4DN of container for groups in DS relative to base DNtgroupssuserobjectclass+tuser_objectclasssUser object classs3Objectclasses used to search for user entries in DStcsvupersonsgroupobjectclass+tgroup_objectclasssGroup object classs4Objectclasses used to search for group entries in DSugroupOfUniqueNamesu groupOfNamessuserignoreobjectclass*tuser_ignore_objectclasssIgnore user object classs2Objectclasses to be ignored for user entries in DSsuserignoreattribute*tuser_ignore_attributesIgnore user attributes/Attributes to be ignored for user entries in DSsgroupignoreobjectclass*tgroup_ignore_objectclasssIgnore group object classs3Objectclasses to be ignored for group entries in DSsgroupignoreattribute*tgroup_ignore_attributesIgnore group attributes0Attributes to be ignored for group entries in DSR”tgroup_overwrite_gids Overwrite GIDscWhen migrating a group already existing in IPA domain overwrite the group GID and report as successsschema?Rs LDAP schemasjThe schema used on the LDAP server. Supported values are RFC2307 and RFC2307bis. The default is RFC2307bistvaluesis continue?tContinuesHContinuous operation mode. Errors are reported but the process continuessbasedn?tbase_dnsBase DNsBase DN on remote LDAP serverscompat?t with_compatsIgnore compat plugins3Allows migration despite the usage of compat pluginR}RLs/Lists of objects migrated; categorized by type.RXsALists of objects that could not be migrated; categorized by type.tenableds%False if migration mode was disabled.tcompatsFFalse if migration fails because the compatibility plug-in is enabled.s%s to exclude from migrationsssearch results for objects to be migrated have been truncated by the server; migration process might be incomplete s>Migration mode is disabled. Use 'ipa config-mod' to enable it.sùPasswords have been migrated in pre-hashed format. IPA is unable to generate Kerberos keys unless provided with clear text passwords. All migrated users need to login at https://your.domain/ipa/migration/ before they can use their Kerberos accounts.c csx"tt|ƒjƒD] }|VqWxq|jD]f}|jj|}dt|ƒ}|j|j}t d|d|d|dt dt ƒdt ƒVq/WdS( s} Call get_options of the baseclass and add "exclude" options for each type of object being migrated. s exclude_%sss%s*R¸RºRÉR¿RÀN( tsuperRªt get_optionstmigrate_objectsRRNR t exclude_doctobject_name_pluralRR’ttuple(tselftoptiont ldap_obj_nametldap_objRPRº((s6/home/mkosek/freeipa-clean/ipalib/plugins/migration.pyR×zs cCskxd|jƒD]V}|jr ||jrPtd„||jDƒƒ||j•sN(tparamsRÉRPRÛ(RÜR˜tp((s6/home/mkosek/freeipa-clean/ipalib/plugins/migration.pytnormalize_optionsŠs   $cCswtƒ}xg|D]_}|jdt|ƒƒ}|r_|j|ƒrM|}qet||ƒ}n|}||||j |dg|| |jdddd d tƒ\}}Wnstjk r|jd tƒs~tjd td ƒi| d6|| d6dj| ƒd6ƒ‚qŽt}g}nX|r·|jjd| j|jfƒni}xXd)D]P}|j | |d}|d*k r|j|tƒƒ||s> .$  [       $ } % W   ÿáfreeipa-3.3.4/ipalib/plugins/internal.pyc0000664000175000017500000006733212271707517020000 0ustar mkosekmkosekó †fçRc@s¼dZddlZddlmZddlmZddlmZddlmZddlm Z ddl m Z d efd „ƒYZ ej e ƒd efd „ƒYZej eƒdS( sK Plugins not accessible directly through the CLI, commands used internally iÿÿÿÿN(tapi(tCommand(tStr(tOutput(t_(tjson_serializet json_metadatacBséeZdZeZeddedƒƒeddedƒƒfZeddedƒƒeddedƒƒedded ƒƒfZe d e ded ƒƒe d e ded ƒƒe de dedƒƒfZ d„Z d„Z RS(s0 Export plugin meta-data for the webUI. sobjname?tdocsName of object to exports methodname?sName of method to exportsobject?smethod?scommand?sName of command to exporttobjectss Dict of JSON encoded IPA Objectstmethodss Dict of JSON encoded IPA Methodstcommandss!Dict of JSON encoded IPA Commandsc Kstƒ}tƒ}tƒ}t}yŽ|s7|d}n||jjkrz|jj|}t|jt|ƒfgƒ}n.|dkr¨td„|jjƒDƒƒ}nt}Wntk rÂnXyŽ|sÙ|d}n||jjkr|jj|} t| jt| ƒfgƒ}n.|dkrJtd„|jjƒDƒƒ}nt}Wntk rdnXy…|d} | |jj krµ|jj | } t| jt| ƒfgƒ}n.| dkrãtd„|jj ƒDƒƒ}nt}Wntk rýnX|rdtd„|jjƒDƒƒ}td „|jjƒDƒƒ}td „|jj ƒDƒƒ}ntd |fd |fd |fgƒ} | S(Ntobjecttallcss$|]}|jt|ƒfVqdS(N(tnameR(t.0to((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys Tstmethodcss$|]}|jt|ƒfVqdS(N(R R(Rtm((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys bstcommandcss$|]}|jt|ƒfVqdS(N(R R(Rtc((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys oscss$|]}|jt|ƒfVqdS(N(R R(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys wscss$|]}|jt|ƒfVqdS(N(R R(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys zscss$|]}|jt|ƒfVqdS(N(R R(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pys }sRR R ( tdicttTrueRtObjectR RtFalsetKeyErrortMethodR( tselftobjnamet methodnametoptionsRR R temptyRRtcmdnameRtretval((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pytexecuteEsf    !    !    !     cOstj|dtƒGHdS(Ntdefault(tjsontdumpsR(RttextuitresulttargsR((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pytoutput_for_cliˆs(t__name__t __module__t__doc__RtNO_CLIRRt takes_argst takes_optionsRRt has_outputR!R((((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pyR#s"         Ct i18n_messagescBsøeZeZiiiedƒd6d6d6iedƒd6edƒd6edƒd 6ed ƒd 6ed ƒd 6edƒd6d6i iedƒd6edƒd6edƒd6edƒd6edƒd6edƒd6edƒd6d6ed ƒd!6ed"ƒd#6ed$ƒd%6ed&ƒd'6ed(ƒd)6ied*ƒd6ed+ƒd6ed,ƒd6ed-ƒd6ed.ƒd6ed/ƒd6ed0ƒd6d16ed2ƒd36ed4ƒd56d66ied7ƒd6ed8ƒd96ed:ƒd;6ed<ƒd=6ed>ƒd?6ed@ƒdA6edBƒdC6edDƒdE6edFƒdG6edHƒdI6edJƒdK6edLƒdM6edNƒdO6edPƒdQ6edRƒdS6edTƒdU6edVƒd16edWƒdX6edYƒdZ6ed[ƒd\6ed]ƒd^6ed_ƒd`6edaƒdb6edcƒdd6edeƒdf6dg6iedhƒdi6edjƒdk6edlƒdm6ednƒdo6edpƒdq6edrƒds6edtƒdu6dv6iedwƒdx6edyƒdz6ed{ƒd|6ed}ƒd~6edƒd€6edƒd‚6edƒƒd„6ed…ƒd†6ed‡ƒdˆ6ed‰ƒdŠ6ed‹ƒdŒ6edƒdŽ6edƒd6ed‘ƒd’6ed“ƒd”6ed•ƒd–6ed—ƒd˜6d™6iedšƒd›6edœƒd6edžƒdU6edŸƒd 6ed¡ƒd¢6ed£ƒd6d¤6ied¥ƒd¦6ed§ƒd¨6ed©ƒdª6ed«ƒd¬6ed­ƒd®6ed¯ƒd°6ed±ƒd²6d³6ied´ƒd6edµƒd6ed¶ƒd6d·6ied¸ƒdv6ed¹ƒdº6d»6ed¼ƒd½6ied¾ƒd¿6edÀƒdÁ6edƒdÃ6edădÅ6dÆ6iedǃdÈ6edɃdÊ6ed˃dÌ6ed̓dÎ6edσdÐ6edуdÒ6edÓƒdÔ6edÕƒdÖ6dÎ6ied׃dØ6edÙƒdÙ6dÚ6i$iedÛƒdÜ6dÝ6i edÞƒdß6edàƒdá6edÛƒdÜ6edâƒdã6edäƒdå6edæƒdç6edèƒdé6edêƒdë6edìƒdí6edîƒdï6edðƒdñ6edòƒdó6dô6idõ6iedöƒdo6d÷6iedøƒdù6edúƒdû6edüƒdý6dþ6i8edÿƒd6edƒd6edƒd6edƒd6edƒd6ed ƒd 6ed ƒd 6ed ƒd6edƒd6edƒd6edƒd6edƒd6edƒd6edƒd6edƒd6edƒd6edƒd 6ed!ƒd"6ed#ƒd$6ed%ƒd&6ed'ƒd(6ed)ƒd*6ed+ƒd,6ed-ƒd.6ed/ƒd06ed1ƒd26ed3ƒd46ed5ƒd66ed7ƒd86ed9ƒd:6ed;ƒd<6ed=ƒd>6ed?ƒd@6edAƒdB6edCƒdD6edEƒdF6edGƒdH6edIƒdJ6edKƒdL6edMƒdN6edOƒdP6edQƒdR6edƒdS6edTƒdU6edVƒdW6edXƒdY6edZƒd[6ed\ƒd]6ed^ƒd_6ed`ƒda6edbƒdc6eddƒde6edfƒdg6edhƒdi6edjƒdk6edlƒdm6dn6iedoƒdp6edqƒdº6edrƒds6edtƒdu6edvƒdw6dx6idy6iedzƒd{6ed|ƒd}6ed~ƒd6ed€ƒd›6d6ied‚ƒdƒ6ed„ƒd…6ed†ƒd‡6edˆƒd‰6edŠƒd‹6edŒƒd6edŽƒd6edƒd‘6ed’ƒd“6ed”ƒd•6ed–ƒd—6ed˜ƒd™6edšƒd›6edœƒd6edžƒdŸ6ed ƒd¡6ed¢ƒd6ed£ƒd¤6d¥6ied¦ƒdo6ed§ƒd¨6ed©ƒdª6d«6ied¬ƒdv6ed­ƒd®6ed¯ƒd°6ed±ƒd²6ed³ƒd´6edµƒd¶6ed·ƒd¤6dp6i ed¸ƒd¹6edºƒd»6ed¼ƒd½6ed¾ƒd¿6edÀƒdÁ6edƒdu6edÃdÄ6edŃdÆ6edǃdÈ6edɃdw6dÊ6idË6ied̃dÍ6dÎ6i edσdÐ6edуdÒ6edÓƒdÔ6edÕƒdÖ6ed׃dØ6edÙƒdÚ6edÛƒdÜ6ed݃dÞ6ed߃dà6edáƒdâ6edãƒdä6edåƒdæ6dç6iedèƒd6edéƒdê6edëƒdì6edíƒdv6edîƒdï6edðƒdñ6edòƒdó6edôƒdõ6edöƒd÷6edøƒdù6edúƒdÔ6edûƒdü6edýƒdþ6edÿƒd6edƒd6edƒd6edƒd6edƒd6edbƒdc6ed ƒd 6ed ƒd 6ed ƒd6edƒd6d¿6iedƒdo6d6iedƒdo6d6i ed¸ƒd¹6ed¼ƒd½6ed­ƒd®6edƒd¿6edƒd6edƒd6edƒdo6edÃdÄ6edǃdÈ6edƒdw6edƒd6edƒd6d 6ied!ƒdo6ed"ƒd#6ed$ƒd%6ed&ƒd'6d(6ied)ƒdo6d*6ied+ƒdo6d,6i ed-ƒdv6ed.ƒd/6ed0ƒd16ed2ƒd36ed4ƒd56ed6ƒd76ed8ƒd¤6ed9ƒd:6ed;ƒd<6ed=ƒd>6ed?ƒd@6edAƒdB6edCƒdD6dE6iedFƒdo6edGƒdH6edIƒdJ6edKƒdL6dM6iedNƒdo6dO6idP6ied¸ƒd¹6ed¼ƒd½6edƒd¿6edÃdÄ6edǃdÈ6edƒdw6dQ6i edRƒd6edëƒdì6edSƒdv6edéƒd¿6edöƒd86edTƒdU6edVƒdu6edbƒdc6ed ƒd 6edWƒd 6ed ƒd6edXƒd6edYƒdi6du6iedZƒd[6ed\ƒd]6ed^ƒd_6ed`ƒda6edbƒdc6eddƒde6edfƒdg6edhƒdi6dj6iedkƒdl6dm6iednƒdo6dp6iedqƒdr6edsƒdt6eduƒdv6ed¸ƒd¹6ed¼ƒd½6edwƒdx6edyƒdz6ed­ƒd®6ed{ƒd¿6edÀƒdÁ6ed|ƒd}6ed~ƒd6ed€ƒd›6ed€ƒd6ed‚ƒdƒ6ed„ƒd…6edÃdÄ6edǃdÈ6edɃdw6d†6i ed‡ƒdˆ6ed‰ƒdŠ6ed‹ƒdŒ6edƒdv6edŽƒd6edƒd‘6ed’ƒd“6ed”ƒd•6ed–ƒd56ed—ƒd˜6ed™ƒdš6ed›ƒdœ6edƒdž6dŸ6ied€ƒd›6d 6i ed¡ƒdˆ6ed¢ƒd£6ed¤ƒd¥6ed¦ƒd§6ed¨ƒd©6edªƒd«6ed¬ƒd­6ed®ƒd¯6ed°ƒd±6ed²ƒd³6dw6d´6i edµƒd¶6ed·ƒd¸6ed¹ƒdº6ed»ƒd¼6ed½ƒd¾6ed¿ƒdÀ6edÓƒdÔ6edÁƒdÂ6edÃdÄ6edŃdÆ6edǃdÈ6edɃdÊ6ed˃dÌ6dÔ6i ed̓d 6ed΃dÏ6edЃd 6edуdÒ6edÓƒd 6edÔƒdÕ6edÖƒd×6ed؃dÙ6edÚƒdÛ6ed܃dÝ6edÞƒdß6dº6iedFƒdG6edàƒdÒ6edJƒdK6edáƒdÕ6edbƒdØ6dc6i edâƒdã6edäƒdô6edåƒdæ6edƒdn6edçƒdè6edéƒdê6ed!ƒdo6edëƒdì6edíƒdî6edïƒdO6edðƒdñ6edòƒdŸ6dó6edôƒdõ6iedöƒd÷6edøƒdù6edúƒdû6edüƒdü6edýƒdþ6i edÿƒd¦6edƒd6edƒd6edƒd6edƒd6edƒd 6ed ƒd 6ed ƒd 6edƒd6edƒd6edƒd6edƒd6d6d6ZedededƒƒfZd„Z d„Z RS(s*Your session has expired. Please re-login.tmessaget401tajaxtApplytapplys1Are you sure you want to proceed with the action.tconfirms)Are you sure you want to delete ${object}tdelete_confirms*Are you sure you want to disable ${object}tdisable_confirms)Are you sure you want to enable ${object}tenable_confirmtActionsttitletactionss7Add RunAs ${other_entity} into ${entity} ${primary_key}t ipasudorunass.Add RunAs Groups into ${entity} ${primary_key}tipasudorunasgroups5Add ${other_entity} Managing ${entity} ${primary_key}t managedbys1Add ${other_entity} into ${entity} ${primary_key}tmembers7Add Allow ${other_entity} into ${entity} ${primary_key}tmemberallowcmds6Add Deny ${other_entity} into ${entity} ${primary_key}t memberdenycmds1Add ${entity} ${primary_key} into ${other_entity}tmemberoftadds${count} item(s) addedtaddedsDirect Membershiptdirect_membershipsIndirect Membershiptindirect_memberships No entries.t no_entriess/Showing ${start} to ${end} of ${total} entries.tpagings:Remove RunAs ${other_entity} from ${entity} ${primary_key}s1Remove RunAs Groups from ${entity} ${primary_key}s8Remove ${other_entity} Managing ${entity} ${primary_key}s4Remove ${other_entity} from ${entity} ${primary_key}s:Remove Allow ${other_entity} from ${entity} ${primary_key}s9Remove Deny ${other_entity} from ${entity} ${primary_key}s4Remove ${entity} ${primary_key} from ${other_entity}tremoves${count} item(s) removedtremoveds Show Resultst show_resultst associationtAddsAdd and Add Anothertadd_and_add_anothers Add and Closet add_and_closes Add and Editt add_and_editsAdd Manytadd_manytBacktbacktCanceltcanceltClosetclosetDisabletdisabletEdittedittEnabletenabletFindtfindtGettgettIssuetissuetOKtoktRefreshtrefreshtDeletetResettresetsReset Password and Logintreset_password_and_logintRestoretrestoretRetrytretrytRevoketrevoketSettsettUpdatetupdatetViewtviewtbuttonss Collapse Allt collapse_alls Expand Allt expand_alltGeneraltgeneralsIdentity Settingstidentitys!${entity} ${primary_key} Settingstsettingss Back to Toptto_tops ${entity} ${primary_key} updatedtupdatedtdetailss${entity} successfully addedtadd_confirmations Add ${entity}t add_titlet Availablet availablesSome operations failed.tbatch_error_messagesOperations Errortbatch_error_titlet Confirmationt confirmations5This page has unsaved changes. Please save or revert.t dirty_messagesUnsaved Changest dirty_titlesEdit ${entity}t edit_titles Hide detailst hide_detailst Prospectivet prospectivet Redirectiont redirectionsSelect entries to be removed.t remove_emptysRemove ${entity}t remove_titles Show detailst show_detailssValidation errortvalidation_titles.Input form contains invalid or missing values.tvalidation_messagetdialogss!Please try the following options:Rs@If the problem persists please contact the system administrator.tproblem_persistssRefresh the page.sReload the browser.treloads/Return to the main page and retry the operationt main_pages An error has occurred (${error})t error_reporttErrorterrors HTTP Errort http_errorsInternal Errortinternal_errors IPA Errort ipa_errors No responset no_responses Unknown Errort unknown_errortURLturlterrorss${primary_key} is managed by:s${primary_key} members:s${primary_key} is a member of:t facet_groupstSettingstSearchtsearchtfacetsRtfalses#Inherited from server configurationt inheritedsMS-PACtmspacsOverride inherited settingstoverridetPADtpadt krbauthzdatasUTo login with username and password, enter them in the fields below then click Login.t form_auths Logged In AstheadersÈTo login with Kerberos, please make sure you have valid tickets (obtainable via kinit) and configured the browser correctly, then click Login.t krb_auth_msgtLogintlogintLogouttlogouts Logout errort logout_errortPasswordtpasswordtUsernametusernamesnumber of passwordstnumber_of_passwordstsecondstmeasurement_unitst Attributet attributetacisAdd Condition into ${pkey}t add_conditionsAdd Ruletadd_rulesDefault host grouptdefault_host_groupsDefault user grouptdefault_user_groupt Exclusivet exclusivet Expressiont expressionsHost group rulet hostgrouprulesHost group rulesthostgrouprulest Inclusivet inclusivesUser group rulet usergrouprulesUser group rulestusergrouprulest automembert automountkeysAutomount Location SettingstautomountlocationsMap Typetmap_typetDirecttdirecttIndirecttindirectt automountmaps AA Compromiset aa_compromisesAffiliation Changedtaffiliation_changeds CA Compromiset ca_compromiset Certificatet certificatet Certificatest certificatessCertificate Holdtcertificate_holdsCessation of Operationtcessation_of_operations Common Namet common_names Expires Ont expires_onsIssued on fromtfind_issuedon_froms Issued on totfind_issuedon_tosMaximum serial numbertfind_max_serial_numbersMinimum serial numbertfind_min_serial_numbersRevocation reasontfind_revocation_reasonsRevoked on fromtfind_revokedon_froms Revoked on totfind_revokedon_totSubjectt find_subjectsValid not after fromtfind_validnotafter_fromsValid not after totfind_validnotafter_tosValid not before fromtfind_validnotbefore_fromsValid not before totfind_validnotbefore_tot Fingerprintst fingerprintss2Issue New Certificate for ${entity} ${primary_key}tissue_certificates Issued Byt issued_bys Issued Ont issued_ons Issued Tot issued_tosKey Compromisetkey_compromisesMD5 Fingerprinttmd5_fingerprintsNo Valid CertificatetmissingsNew Certificatetnew_certificatetNotetnotet Organizationt organizationsOrganizational Unittorganizational_unitsPrivilege Withdrawntprivilege_withdrawnsReason for RevocationtreasonsRemove from CRLtremove_from_crls
  1. Create a certificate database or use an existing one. To create a new database:
    # certutil -N -d <database path>
  2. Create a CSR with subject CN=<hostname>,O=<realm>, for example:
    # certutil -R -d <database path> -a -g <key size> -s 'CN=${hostname},O=${realm}'
  3. Copy and paste the CSR (from -----BEGIN NEW CERTIFICATE REQUEST----- to -----END NEW CERTIFICATE REQUEST-----) into the text area below:
trequest_messagesCertificate requestedt requesteds0Restore Certificate for ${entity} ${primary_key}trestore_certificatesRestore Certificatetrestore_certificate_simplesRTo confirm your intention to restore this certificate, click the "Restore" button.trestore_confirmationsCertificate restoredtrestoredtrevocation_reasons/Revoke Certificate for ${entity} ${primary_key}trevoke_certificatesRevoke Certificatetrevoke_certificate_simples}To confirm your intention to revoke this certificate, select a reason from the pull-down list, and click the "Revoke" button.trevoke_confirmationsCertificate Revokedtrevokeds Serial Numbert serial_numbersSerial Number (hex)tserial_number_hexsSHA1 Fingerprinttsha1_fingerprinttStatuststatust Supersededt supersededt Unspecifiedt unspecifiedsValid Certificate PresenttvalidtValiditytvaliditys(Certificate for ${entity} ${primary_key}tview_certificatetcerts Group OptionstgroupsSearch OptionssSELinux OptionstselinuxsService Optionstservices User Optionstusertconfigt delegations Forward firstt forward_firstsForwarding disabledt forward_nones Forward onlyt forward_onlytOptionst dnsconfigtDatatdatas4DNS record was deleted because it contained no data.tdeleted_no_datasOther Record Typestothers!Address not valid, can't redirecttptr_redir_address_errsCreate dns recordtptr_redir_createsCreating record.tptr_redir_creatingsRecord creation failed.tptr_redir_creating_errsChecking if record exists.tptr_redir_recordsRecord not found.tptr_redir_record_errsRedirection to PTR recordtptr_redir_titlesZone found: ${zone}tptr_redir_zonesTarget reverse zone not found.tptr_redir_zone_errsFetching DNS zones.tptr_redir_zoness+An error occurred while fetching dns zones.tptr_redir_zones_errs#You will be redirected to DNS Zone.tredirection_dnszonesStandard Record TypeststandardsRecords for DNS Zones Record Typettypet dnsrecordsDNS Zone SettingssAdd Permissiontadd_permissionsRemove Permissiontremove_permissiontdnszonesGroup SettingstExternaltexternalsChange to external groupt make_externalsChange to POSIX groupt make_posixtNormaltnormaltPOSIXtposixs Group TypesAny Hosttany_hosts Any Servicet any_servicetAnyonetanyonet Accessingthosts Rule statustipaenabledflags Via ServicesSpecified Hosts and Groupstspecified_hostssSpecified Services and Groupstspecified_servicessSpecified Users and Groupstspecified_userstWhothbacrulethbacsvctServicestservicest hbacsvcgroups Access Deniedt access_deniedsAccess Grantedtaccess_grantedsInclude Disabledtinclude_disabledsInclude Enabledtinclude_enableds HBAC TesttlabeltMatchedtmatchedsMissing values: tmissing_valuessNew Testtnew_testtRulestrulessRun Testtrun_testsSpecify external ${entity}tspecify_externalt Unmatchedt unmatchedthbactestsHost Certificates Host NametcnsDelete Key, Unprovisiontdelete_key_unprovisions Host SettingstEnrolledtenrolledt Enrollmentt enrollmentsFully Qualified Host Nametfqdns Kerberos KeytkeytabsKerberos Key Not Presenttkeytab_missings&Kerberos Key Present, Host Provisionedtkeytab_presentsOne-Time-PasswordsOne-Time-Password Not Presenttpassword_missingsOne-Time-Password Presenttpassword_presents Reset OTPtpassword_reset_buttonsReset One-Time-Passwordtpassword_reset_titlesSet OTPtpassword_set_buttonsOTP settpassword_set_successsSet One-Time-Passwordtpassword_set_titlet Unprovisiont unprovisions/Are you sure you want to unprovision this host?tunprovision_confirmationsUnprovisioning ${entity}tunprovision_titlesHost unprovisionedt unprovisionedsHost Group Settingst hostgroupsKerberos Ticket Policyt krbtpolicytHosts Host Groupst hostgroupstHoststhostssNetgroup SettingstUsers User Groupst usergroupstUserstuserstnetgrouptIdentitys,Permission with invalid target specificationtinvalid_targettRightstrightstTargetttargett permissionsPrivilege Settingst privilegesPassword PolicytpwpolicysRange SettingssBase IDt ipabaseidsPrimary RID baset ipabaserids Range sizetipaidrangesizes Domain SIDtipanttrusteddomainsidsSecondary RID basetipasecondarybaserids Range typesActive Directory domainttype_ads-Active Directory domain with POSIX attributest type_ad_posixtDetectt type_detects Local domaint type_locals IPA trustttype_ipasActive Directory winsynct type_winsynctidranges Realm Domainss Check DNSt check_dnss&Do you also want to perform DNS check?tcheck_dns_confirmations Force Updatet force_updatet realmdomainss Role Settingstrolet selfservicetselinuxusermapsService CertificatesService Settingst Provisioningt provisioningtServices2Are you sure you want to unprovision this service?sService unprovisioneds)Kerberos Key Present, Service ProvisionedsSSH public keystkeyssSSH public key:tset_dialog_helps Set SSH keytset_dialog_titles Show/Set keyt show_set_keysModified: key not sett status_mod_nstModifiedt status_mod_ssNew: key not sett status_new_nss New: key sett status_new_st sshkeystoretGroupstgroupstsudocmdtCommandsR t sudocmdgrouptAllowtallows Any Commandt any_commands Any Groupt any_groups Run CommandsRtDenytdenysAccess this hosts Option addedt option_addeds${count} option(s) removedtoption_removedsAs WhomtrunassSpecified Commands and Groupstspecified_commandssSpecified Groupstspecified_groupstsudoruletAccounttaccountsAdministrative accountt admin_accountsSID blacklistst blacklistssTrust SettingstDomaintdomainsEstablish usingtestablish_usings Fetch domainst fetch_domainssDomain NetBIOS namet ipantflatnamesDomain Security IdentifiersPre-shared passwordtpreshared_passwordsTrust directionttrustdirections Trust statust truststatuss Trust typet trusttypettrustt trustconfigsAccount SettingssAccount Statustaccount_statussContact SettingstcontactsEmployee InformationtemployeesError changing account statusterror_changing_statussPassword expirationtkrbpasswordexpirationsMailing AddresstmailingsMisc. InformationtmiscsYAre you sure you want to ${action} the user?
The change will take effect immediately.tstatus_confirmationsClick to ${action}t status_linkRsCurrent Passwordtcurrent_passwordsCurrent password is requiredtcurrent_password_requireds&Your password expires in ${days} days.t expires_ins2The password or username you entered is incorrect.tinvalid_passwords New Passwordt new_passwordsNew password is requiredtnew_password_requiredsPassword change completetpassword_change_completesPasswords must matchtpassword_must_matchs"Password reset was not successful.t reset_failuresReset Passwordtreset_passwordsReset your password.treset_password_sentencesVerify Passwordtverify_passwords1Are you sure you want to delete selected entries?s${count} item(s) deletedtdeleteds2Are you sure you want to disable selected entries?s${count} item(s) disabledtdisableds1Are you sure you want to enable selected entries?s${count} item(s) enabledtenabledsSome entries were not deletedtpartial_deletes Quick Linkst quick_linkss Select Allt select_allsdQuery returned more results than the configured size limit. Displaying the first ${counter} results.t truncateds Unselect Allt unselect_alltDisabledtEnabledtAudittauditt Automembert Automountt automounttDNStdnssHost Based Access Controlthbacs IPA Servert ipaservertPolicytpolicysRole Based Access ControltSudotsudotTruststtabsRttruetNexttnexttPagetpagetPrevtprevtundosundo alltundo_alls!Text does not match field patternsMust be a decimal numbertdecimalsMust be an integertintegersNot a valid IP addresst ip_addresssNot a valid IPv4 addresst ip_v4_addresssNot a valid IPv6 addresst ip_v6_addresssMaximum value is ${value}t max_valuesMinimum value is ${value}t min_valuesNot a valid network addresst net_addresss'${port}' is not a valid porttportsRequired fieldtrequiredsUnsupported valuet unsupportedt validationtwidgetttextsRsDict of I18N messagescKstdt|jƒƒS(NR(RRtmessages(RR((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pyR!¾scOstj|dtƒGHdS(NR"(R#R$R(RR%R&R'R((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pyR(Ás( R)R*RR,RRRRR/R!R((((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pyR0sæ                                                                                                                                                                                                                                                                                                                                                                                                (R+R#tipalibRRRt ipalib.outputRt ipalib.textRt ipalib.utilRRtregisterR0(((s5/home/mkosek/freeipa-clean/ipalib/plugins/internal.pyts h ÿÿ:freeipa-3.3.4/ipalib/plugins/hbacsvc.pyc0000664000175000017500000000746112271707517017572 0ustar mkosekmkosekó ­8 Rc@sbddlmZddlmZddlmZmZmZddlmZmZm Z ddlm Z m Z e dƒZ de dƒfZ d efd „ƒYZejeƒd efd „ƒYZejeƒd efd„ƒYZejeƒdefd„ƒYZejeƒdefd„ƒYZejeƒde fd„ƒYZejeƒdS(iÿÿÿÿ(tapi(tStr(t LDAPObjectt LDAPCreatet LDAPDelete(t LDAPUpdatet LDAPSearcht LDAPRetrieve(t_tngettexts× HBAC Services The PAM services that HBAC can control access to. The name used here must match the service name that PAM is evaluating. EXAMPLES: Add a new HBAC service: ipa hbacsvc-add tftp Modify an existing HBAC service: ipa hbacsvc-mod --desc="TFTP service" tftp Search for HBAC services. This example will return two results, the FTP service and the newly-added tftp service: ipa hbacsvc-find ftp Delete an HBAC service: ipa hbacsvc-del tftp thbacs"Host based access control commandsthbacsvcc BsÞeZdZejjZedƒZedƒZ ddgZ dddgZ dZ id gd6Z ed ƒZed ƒZedd d dedƒdedƒdedd„ƒedd ddedƒdedƒƒfZRS(s HBAC Service object. s HBAC services HBAC servicest ipaobjecttipahbacservicetcnt descriptiontmemberoft ipauniqueidt hbacsvcgroups HBAC Servicess HBAC Servicetcli_nametservicetlabels Service nametdoct primary_keyt normalizercCs |jƒS(N(tlower(tvalue((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pytKss description?tdesct DescriptionsHBAC service description(t__name__t __module__t__doc__Rtenvtcontainer_hbacservicet container_dnRt object_nametobject_name_pluralt object_classtdefault_attributestuuid_attributetattribute_membersRtlabel_singularRtTruet takes_params(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR 4s*             t hbacsvc_addcBs eZedƒZedƒZRS(sAdd a new HBAC service.sAdded HBAC service "%(value)s"(RRRR t msg_summary(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR-Ws t hbacsvc_delcBs eZedƒZedƒZRS(s Delete an existing HBAC service.s Deleted HBAC service "%(value)s"(RRRR R.(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR/_s t hbacsvc_modcBs eZedƒZedƒZRS(sModify an HBAC service.s!Modified HBAC service "%(value)s"(RRRR R.(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR0gs t hbacsvc_findcBs&eZedƒZedddƒZRS(sSearch for HBAC services.s%(count)d HBAC service matcheds%(count)d HBAC services matchedi(RRRR R R.(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR1os t hbacsvc_showcBseZedƒZRS(s*Display information about an HBAC service.(RRRR (((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyR2ysN(tipalibRRtipalib.plugins.baseldapRRRRRRRR R ttopicR tregisterR-R/R0R1R2(((s4/home/mkosek/freeipa-clean/ipalib/plugins/hbacsvc.pyts&      freeipa-3.3.4/ipalib/plugins/internal.py0000664000175000017500000007534412271663206017633 0ustar mkosekmkosek# Authors: # Pavel Zuna # Adam Young # Endi S. Dewata # # Copyright (c) 2010 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 . """ Plugins not accessible directly through the CLI, commands used internally """ import json from ipalib import api from ipalib import Command from ipalib import Str from ipalib.output import Output from ipalib.text import _ from ipalib.util import json_serialize class json_metadata(Command): """ Export plugin meta-data for the webUI. """ NO_CLI = True takes_args = ( Str('objname?', doc=_('Name of object to export'), ), Str('methodname?', doc=_('Name of method to export'), ), ) takes_options = ( Str('object?', doc=_('Name of object to export'), ), Str('method?', doc=_('Name of method to export'), ), Str('command?', doc=_('Name of command to export'), ), ) has_output = ( Output('objects', dict, doc=_('Dict of JSON encoded IPA Objects')), Output('methods', dict, doc=_('Dict of JSON encoded IPA Methods')), Output('commands', dict, doc=_('Dict of JSON encoded IPA Commands')), ) def execute(self, objname, methodname, **options): objects = dict() methods = dict() commands = dict() empty = True try: if not objname: objname = options['object'] if objname in self.api.Object: o = self.api.Object[objname] objects = dict([(o.name, json_serialize(o))]) elif objname == "all": objects = dict( (o.name, json_serialize(o)) for o in self.api.Object() ) empty = False except KeyError: pass try: if not methodname: methodname = options['method'] if methodname in self.api.Method: m = self.api.Method[methodname] methods = dict([(m.name, json_serialize(m))]) elif methodname == "all": methods = dict( (m.name, json_serialize(m)) for m in self.api.Method() ) empty = False except KeyError: pass try: cmdname = options['command'] if cmdname in self.api.Command: c = self.api.Command[cmdname] commands = dict([(c.name, json_serialize(c))]) elif cmdname == "all": commands = dict( (c.name, json_serialize(c)) for c in self.api.Command() ) empty = False except KeyError: pass if empty: objects = dict( (o.name, json_serialize(o)) for o in self.api.Object() ) methods = dict( (m.name, json_serialize(m)) for m in self.api.Method() ) commands = dict( (c.name, json_serialize(c)) for c in self.api.Command() ) retval = dict([ ("objects", objects), ("methods", methods), ("commands", commands), ]) return retval def output_for_cli(self, textui, result, *args, **options): print json.dumps(result, default=json_serialize) api.register(json_metadata) class i18n_messages(Command): NO_CLI = True messages = { "ajax": { "401": { "message": _("Your session has expired. Please re-login."), }, }, "actions": { "apply": _("Apply"), "confirm": _("Are you sure you want to proceed with the action."), "delete_confirm": _("Are you sure you want to delete ${object}"), "disable_confirm": _("Are you sure you want to disable ${object}"), "enable_confirm": _("Are you sure you want to enable ${object}"), "title": _("Actions"), }, "association": { "add": { "ipasudorunas": _("Add RunAs ${other_entity} into ${entity} ${primary_key}"), "ipasudorunasgroup": _("Add RunAs Groups into ${entity} ${primary_key}"), "managedby": _("Add ${other_entity} Managing ${entity} ${primary_key}"), "member": _("Add ${other_entity} into ${entity} ${primary_key}"), "memberallowcmd": _("Add Allow ${other_entity} into ${entity} ${primary_key}"), "memberdenycmd": _("Add Deny ${other_entity} into ${entity} ${primary_key}"), "memberof": _("Add ${entity} ${primary_key} into ${other_entity}"), }, "added": _("${count} item(s) added"), "direct_membership": _("Direct Membership"), "indirect_membership": _("Indirect Membership"), "no_entries": _("No entries."), "paging": _("Showing ${start} to ${end} of ${total} entries."), "remove": { "ipasudorunas": _("Remove RunAs ${other_entity} from ${entity} ${primary_key}"), "ipasudorunasgroup": _("Remove RunAs Groups from ${entity} ${primary_key}"), "managedby": _("Remove ${other_entity} Managing ${entity} ${primary_key}"), "member": _("Remove ${other_entity} from ${entity} ${primary_key}"), "memberallowcmd": _("Remove Allow ${other_entity} from ${entity} ${primary_key}"), "memberdenycmd": _("Remove Deny ${other_entity} from ${entity} ${primary_key}"), "memberof": _("Remove ${entity} ${primary_key} from ${other_entity}"), }, "removed": _("${count} item(s) removed"), "show_results": _("Show Results"), }, "buttons": { "add": _("Add"), "add_and_add_another": _("Add and Add Another"), "add_and_close": _("Add and Close"), "add_and_edit": _("Add and Edit"), "add_many": _("Add Many"), "back": _("Back"), "cancel": _("Cancel"), "close": _("Close"), "disable": _("Disable"), "edit": _("Edit"), "enable": _("Enable"), "find": _("Find"), "get": _("Get"), "issue": _("Issue"), "ok": _("OK"), "refresh": _("Refresh"), "remove": _("Delete"), "reset": _("Reset"), "reset_password_and_login": _("Reset Password and Login"), "restore": _("Restore"), "retry": _("Retry"), "revoke": _("Revoke"), "set": _("Set"), "update": _("Update"), "view": _("View"), }, "details": { "collapse_all": _("Collapse All"), "expand_all": _("Expand All"), "general": _("General"), "identity": _("Identity Settings"), "settings": _("${entity} ${primary_key} Settings"), "to_top": _("Back to Top"), "updated": _("${entity} ${primary_key} updated"), }, "dialogs": { "add_confirmation": _("${entity} successfully added"), "add_title": _("Add ${entity}"), "available": _("Available"), "batch_error_message": _("Some operations failed."), "batch_error_title": _("Operations Error"), "confirmation": _("Confirmation"), "dirty_message": _("This page has unsaved changes. Please save or revert."), "dirty_title": _("Unsaved Changes"), "edit_title": _("Edit ${entity}"), "hide_details": _("Hide details"), "prospective": _("Prospective"), "redirection": _("Redirection"), "remove_empty": _("Select entries to be removed."), "remove_title": _("Remove ${entity}"), "show_details": _("Show details"), "validation_title": _("Validation error"), "validation_message": _("Input form contains invalid or missing values."), }, "error_report": { "options": _("Please try the following options:"), "problem_persists": _("If the problem persists please contact the system administrator."), "refresh": _("Refresh the page."), "reload": _("Reload the browser."), "main_page": _("Return to the main page and retry the operation"), "title": _("An error has occurred (${error})"), }, "errors": { "error": _("Error"), "http_error": _("HTTP Error"), "internal_error": _("Internal Error"), "ipa_error": _("IPA Error"), "no_response": _("No response"), "unknown_error": _("Unknown Error"), "url": _("URL"), }, "facet_groups": { "managedby": _("${primary_key} is managed by:"), "member": _("${primary_key} members:"), "memberof": _("${primary_key} is a member of:"), }, "facets": { "details": _("Settings"), "search": _("Search"), }, "false": _("False"), "krbauthzdata": { "inherited": _("Inherited from server configuration"), "mspac": _("MS-PAC"), "override": _("Override inherited settings"), "pad": _("PAD"), }, "login": { "form_auth": _("To login with username and password, enter them in the fields below then click Login."), "header": _("Logged In As"), "krb_auth_msg": _("To login with Kerberos, please make sure you have valid tickets (obtainable via kinit) and configured the browser correctly, then click Login."), "login": _("Login"), "logout": _("Logout"), "logout_error": _("Logout error"), "password": _("Password"), "username": _("Username"), }, "measurement_units": { "number_of_passwords": _("number of passwords"), "seconds": _("seconds"), }, "objects": { "aci": { "attribute": _("Attribute"), }, "automember": { "add_condition": _("Add Condition into ${pkey}"), "add_rule": _("Add Rule"), "attribute": _("Attribute"), "default_host_group": _("Default host group"), "default_user_group": _("Default user group"), "exclusive": _("Exclusive"), "expression": _("Expression"), "hostgrouprule": _("Host group rule"), "hostgrouprules": _("Host group rules"), "inclusive": _("Inclusive"), "usergrouprule": _("User group rule"), "usergrouprules": _("User group rules"), }, "automountkey": { }, "automountlocation": { "identity": _("Automount Location Settings") }, "automountmap": { "map_type": _("Map Type"), "direct": _("Direct"), "indirect": _("Indirect"), }, "cert": { "aa_compromise": _("AA Compromise"), "affiliation_changed": _("Affiliation Changed"), "ca_compromise": _("CA Compromise"), "certificate": _("Certificate"), "certificates": _("Certificates"), "certificate_hold": _("Certificate Hold"), "cessation_of_operation": _("Cessation of Operation"), "common_name": _("Common Name"), "expires_on": _("Expires On"), "find_issuedon_from": _("Issued on from"), "find_issuedon_to": _("Issued on to"), "find_max_serial_number": _("Maximum serial number"), "find_min_serial_number": _("Minimum serial number"), "find_revocation_reason": _("Revocation reason"), "find_revokedon_from": _("Revoked on from"), "find_revokedon_to": _("Revoked on to"), "find_subject": _("Subject"), "find_validnotafter_from": _("Valid not after from"), "find_validnotafter_to": _("Valid not after to"), "find_validnotbefore_from": _("Valid not before from"), "find_validnotbefore_to": _("Valid not before to"), "fingerprints": _("Fingerprints"), "issue_certificate": _("Issue New Certificate for ${entity} ${primary_key}"), "issued_by": _("Issued By"), "issued_on": _("Issued On"), "issued_to": _("Issued To"), "key_compromise": _("Key Compromise"), "md5_fingerprint": _("MD5 Fingerprint"), "missing": _("No Valid Certificate"), "new_certificate": _("New Certificate"), "note": _("Note"), "organization": _("Organization"), "organizational_unit": _("Organizational Unit"), "privilege_withdrawn": _("Privilege Withdrawn"), "reason": _("Reason for Revocation"), "remove_from_crl": _("Remove from CRL"), "request_message": _("
  1. Create a certificate database or use an existing one. To create a new database:
    # certutil -N -d <database path>
  2. Create a CSR with subject CN=<hostname>,O=<realm>, for example:
    # certutil -R -d <database path> -a -g <key size> -s 'CN=${hostname},O=${realm}'
  3. Copy and paste the CSR (from -----BEGIN NEW CERTIFICATE REQUEST----- to -----END NEW CERTIFICATE REQUEST-----) into the text area below:
"), "requested": _("Certificate requested"), "restore_certificate": _("Restore Certificate for ${entity} ${primary_key}"), "restore_certificate_simple": _("Restore Certificate"), "restore_confirmation": _("To confirm your intention to restore this certificate, click the \"Restore\" button."), "restored": _("Certificate restored"), "revocation_reason": _("Revocation reason"), "revoke_certificate": _("Revoke Certificate for ${entity} ${primary_key}"), "revoke_certificate_simple": _("Revoke Certificate"), "revoke_confirmation": _("To confirm your intention to revoke this certificate, select a reason from the pull-down list, and click the \"Revoke\" button."), "revoked": _("Certificate Revoked"), "serial_number": _("Serial Number"), "serial_number_hex": _("Serial Number (hex)"), "sha1_fingerprint": _("SHA1 Fingerprint"), "status": _("Status"), "superseded": _("Superseded"), "unspecified": _("Unspecified"), "valid": _("Valid Certificate Present"), "validity": _("Validity"), "view_certificate": _("Certificate for ${entity} ${primary_key}"), }, "config": { "group": _("Group Options"), "search": _("Search Options"), "selinux": _("SELinux Options"), "service": _("Service Options"), "user": _("User Options"), }, "delegation": { }, "dnsconfig": { "forward_first": _("Forward first"), "forward_none": _("Forwarding disabled"), "forward_only": _("Forward only"), "options": _("Options"), }, "dnsrecord": { "data": _("Data"), "deleted_no_data": _("DNS record was deleted because it contained no data."), "other": _("Other Record Types"), "ptr_redir_address_err": _("Address not valid, can't redirect"), "ptr_redir_create": _("Create dns record"), "ptr_redir_creating": _("Creating record."), "ptr_redir_creating_err": _("Record creation failed."), "ptr_redir_record": _("Checking if record exists."), "ptr_redir_record_err": _("Record not found."), "ptr_redir_title": _("Redirection to PTR record"), "ptr_redir_zone": _("Zone found: ${zone}"), "ptr_redir_zone_err": _("Target reverse zone not found."), "ptr_redir_zones": _("Fetching DNS zones."), "ptr_redir_zones_err": _("An error occurred while fetching dns zones."), "redirection_dnszone": _("You will be redirected to DNS Zone."), "standard": _("Standard Record Types"), "title": _("Records for DNS Zone"), "type": _("Record Type"), }, "dnszone": { "identity": _("DNS Zone Settings"), "add_permission":_("Add Permission"), "remove_permission": _("Remove Permission"), }, "group": { "details": _("Group Settings"), "external": _("External"), "make_external": _("Change to external group"), "make_posix": _("Change to POSIX group"), "normal": _("Normal"), "posix": _("POSIX"), "type": _("Group Type"), }, "hbacrule": { "any_host": _("Any Host"), "any_service": _("Any Service"), "anyone": _("Anyone"), "host": _("Accessing"), "ipaenabledflag": _("Rule status"), "service": _("Via Service"), "specified_hosts": _("Specified Hosts and Groups"), "specified_services": _("Specified Services and Groups"), "specified_users": _("Specified Users and Groups"), "user": _("Who"), }, "hbacsvc": { }, "hbacsvcgroup": { "services": _("Services"), }, "hbactest": { "access_denied": _("Access Denied"), "access_granted": _("Access Granted"), "include_disabled": _("Include Disabled"), "include_enabled": _("Include Enabled"), "label": _("HBAC Test"), "matched": _("Matched"), "missing_values": _("Missing values: "), "new_test": _("New Test"), "rules": _("Rules"), "run_test": _("Run Test"), "specify_external": _("Specify external ${entity}"), "unmatched": _("Unmatched"), }, "host": { "certificate": _("Host Certificate"), "cn": _("Host Name"), "delete_key_unprovision": _("Delete Key, Unprovision"), "details": _("Host Settings"), "enrolled": _("Enrolled"), "enrollment": _("Enrollment"), "fqdn": _("Fully Qualified Host Name"), "keytab": _("Kerberos Key"), "keytab_missing": _("Kerberos Key Not Present"), "keytab_present": _("Kerberos Key Present, Host Provisioned"), "password": _("One-Time-Password"), "password_missing": _("One-Time-Password Not Present"), "password_present": _("One-Time-Password Present"), "password_reset_button": _("Reset OTP"), "password_reset_title": _("Reset One-Time-Password"), "password_set_button": _("Set OTP"), "password_set_success": _("OTP set"), "password_set_title": _("Set One-Time-Password"), "status": _("Status"), "unprovision": _("Unprovision"), "unprovision_confirmation": _("Are you sure you want to unprovision this host?"), "unprovision_title": _("Unprovisioning ${entity}"), "unprovisioned": _("Host unprovisioned"), }, "hostgroup": { "identity": _("Host Group Settings"), }, "krbtpolicy": { "identity": _("Kerberos Ticket Policy"), }, "netgroup": { "any_host": _("Any Host"), "anyone": _("Anyone"), "external": _("External"), "host": _("Host"), "hostgroups": _("Host Groups"), "hosts": _("Hosts"), "identity": _("Netgroup Settings"), "specified_hosts": _("Specified Hosts and Groups"), "specified_users": _("Specified Users and Groups"), "user": _("User"), "usergroups": _("User Groups"), "users": _("Users"), }, "permission": { "identity": _("Identity"), "invalid_target": _("Permission with invalid target specification"), "rights": _("Rights"), "target": _("Target"), }, "privilege": { "identity": _("Privilege Settings"), }, "pwpolicy": { "identity": _("Password Policy"), }, "idrange": { "details": _("Range Settings"), "ipabaseid": _("Base ID"), "ipabaserid": _("Primary RID base"), "ipaidrangesize": _("Range size"), "ipanttrusteddomainsid": _("Domain SID"), "ipasecondarybaserid": _("Secondary RID base"), "type": _("Range type"), "type_ad": _("Active Directory domain"), "type_ad_posix": _("Active Directory domain with POSIX attributes"), "type_detect": _("Detect"), "type_local": _("Local domain"), "type_ipa": _("IPA trust"), "type_winsync": _("Active Directory winsync"), }, "realmdomains": { "identity": _("Realm Domains"), "check_dns": _("Check DNS"), "check_dns_confirmation": _("Do you also want to perform DNS check?"), "force_update": _("Force Update"), }, "role": { "identity": _("Role Settings"), }, "selfservice": { }, "selinuxusermap": { "any_host": _("Any Host"), "anyone": _("Anyone"), "host": _("Host"), "specified_hosts": _("Specified Hosts and Groups"), "specified_users": _("Specified Users and Groups"), "user": _("User"), }, "service": { "certificate": _("Service Certificate"), "delete_key_unprovision": _("Delete Key, Unprovision"), "details": _("Service Settings"), "host": _("Host Name"), "missing": _("Kerberos Key Not Present"), "provisioning": _("Provisioning"), "service": _("Service"), "status": _("Status"), "unprovision": _("Unprovision"), "unprovision_confirmation": _("Are you sure you want to unprovision this service?"), "unprovision_title": _("Unprovisioning ${entity}"), "unprovisioned": _("Service unprovisioned"), "valid": _("Kerberos Key Present, Service Provisioned"), }, "sshkeystore": { "keys": _("SSH public keys"), "set_dialog_help": _("SSH public key:"), "set_dialog_title": _("Set SSH key"), "show_set_key": _("Show/Set key"), "status_mod_ns": _("Modified: key not set"), "status_mod_s": _("Modified"), "status_new_ns": _("New: key not set"), "status_new_s": _("New: key set"), }, "sudocmd": { "groups": _("Groups"), }, "sudocmdgroup": { "commands": _("Commands"), }, "sudorule": { "allow": _("Allow"), "any_command": _("Any Command"), "any_group": _("Any Group"), "any_host": _("Any Host"), "anyone": _("Anyone"), "command": _("Run Commands"), "deny": _("Deny"), "external": _("External"), "host": _("Access this host"), "ipaenabledflag": _("Rule status"), "option_added": _("Option added"), "option_removed": _("${count} option(s) removed"), "options": _("Options"), "runas": _("As Whom"), "specified_commands": _("Specified Commands and Groups"), "specified_groups": _("Specified Groups"), "specified_hosts": _("Specified Hosts and Groups"), "specified_users": _("Specified Users and Groups"), "user": _("Who"), }, "trust": { "account": _("Account"), "admin_account": _("Administrative account"), "blacklists": _("SID blacklists"), "details": _("Trust Settings"), "domain": _("Domain"), "establish_using": _("Establish using"), "fetch_domains": _("Fetch domains"), "ipantflatname": _("Domain NetBIOS name"), "ipanttrusteddomainsid": _("Domain Security Identifier"), "preshared_password": _("Pre-shared password"), "trustdirection": _("Trust direction"), "truststatus": _("Trust status"), "trusttype": _("Trust type"), }, "trustconfig": { "options": _("Options"), }, "user": { "account": _("Account Settings"), "account_status": _("Account Status"), "contact": _("Contact Settings"), "employee": _("Employee Information"), "error_changing_status": _("Error changing account status"), "krbpasswordexpiration": _("Password expiration"), "mailing": _("Mailing Address"), "misc": _("Misc. Information"), "status_confirmation": _("Are you sure you want to ${action} the user?
The change will take effect immediately."), "status_link": _("Click to ${action}"), }, }, "password": { "current_password": _("Current Password"), "current_password_required": _("Current password is required"), "expires_in": _("Your password expires in ${days} days."), "invalid_password": _("The password or username you entered is incorrect."), "new_password": _("New Password"), "new_password_required": _("New password is required"), "password": _("Password"), "password_change_complete": _("Password change complete"), "password_must_match": _("Passwords must match"), "reset_failure": _("Password reset was not successful."), "reset_password": _("Reset Password"), "reset_password_sentence": _("Reset your password."), "verify_password": _("Verify Password"), }, "search": { "delete_confirm": _("Are you sure you want to delete selected entries?"), "deleted": _("${count} item(s) deleted"), "disable_confirm": _("Are you sure you want to disable selected entries?"), "disabled": _("${count} item(s) disabled"), "enable_confirm": _("Are you sure you want to enable selected entries?"), "enabled": _("${count} item(s) enabled"), "partial_delete": _("Some entries were not deleted"), "quick_links": _("Quick Links"), "select_all": _("Select All"), "truncated": _("Query returned more results than the configured size limit. Displaying the first ${counter} results."), "unselect_all": _("Unselect All"), }, "status": { "disable": _("Disable"), "disabled": _("Disabled"), "enable": _("Enable"), "enabled": _("Enabled"), "label": _("Status"), }, "tabs": { "audit": _("Audit"), "automember": _("Automember"), "automount": _("Automount"), "cert": _("Certificates"), "dns": _("DNS"), "hbac": _("Host Based Access Control"), "identity": _("Identity"), "ipaserver": _("IPA Server"), "policy": _("Policy"), "role": _("Role Based Access Control"), "sudo": _("Sudo"), "trust": _("Trusts"), }, "true": _("True"), "widget": { "next": _("Next"), "page": _("Page"), "prev": _("Prev"), "undo": _("undo"), "undo_all": _("undo all"), "validation": { "error": _("Text does not match field pattern"), "decimal": _("Must be a decimal number"), "integer": _("Must be an integer"), "ip_address": _('Not a valid IP address'), "ip_v4_address": _('Not a valid IPv4 address'), "ip_v6_address": _('Not a valid IPv6 address'), "max_value": _("Maximum value is ${value}"), "min_value": _("Minimum value is ${value}"), "net_address": _("Not a valid network address"), "port": _("'${port}' is not a valid port"), "required": _("Required field"), "unsupported": _("Unsupported value"), }, }, } has_output = ( Output('texts', dict, doc=_('Dict of I18N messages')), ) def execute(self, **options): return dict(texts=json_serialize(self.messages)) def output_for_cli(self, textui, result, *args, **options): print json.dumps(result, default=json_serialize) api.register(i18n_messages) freeipa-3.3.4/ipalib/plugins/idrange.pyc0000664000175000017500000005622512271707517017574 0ustar mkosekmkosekó †fçRc@sµddlmZmZmZmZmZmZddlmZm Z m Z m Z m Z m Z mZddlmZddlmZejjrÓejjdkrÓyddlZeZWqÓek rÏeZqÓXne dƒZd efd „ƒYZd efd „ƒYZd efd„ƒYZdefd„ƒYZdefd„ƒYZ defd„ƒYZ!ej"eƒej"eƒej"e!ƒej"eƒej"eƒej"e ƒdS(iÿÿÿÿ(t LDAPObjectt LDAPCreatet LDAPDeletet LDAPRetrievet LDAPSearcht LDAPUpdate(tapitInttStrtDeprecatedParamtStrEnumt_tngettext(terrors(tDNtlitetserverNsð ID ranges Manage ID ranges used to map Posix IDs to SIDs and back. There are two type of ID ranges which are both handled by this utility: - the ID ranges of the local domain - the ID ranges of trusted remote domains Both types have the following attributes in common: - base-id: the first ID of the Posix ID range - range-size: the size of the range With those two attributes a range object can reserve the Posix IDs starting with base-id up to but not including base-id+range-size exclusively. Additionally an ID range of the local domain may set - rid-base: the first RID(*) of the corresponding RID range - secondary-rid-base: first RID of the secondary RID range and an ID range of a trusted domain must set - rid-base: the first RID of the corresponding RID range - sid: domain SID of the trusted domain EXAMPLE: Add a new ID range for a trusted domain Since there might be more than one trusted domain the domain SID must be given while creating the ID range. ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \ --dom-sid=S-1-5-21-123-456-789 trusted_dom_range This ID range is then used by the IPA server and the SSSD IPA provider to assign Posix UIDs to users from the trusted domain. If e.g a range for a trusted domain is configured with the following values: base-id = 1200000 range-size = 200000 rid-base = 0 the RIDs 0 to 199999 are mapped to the Posix ID from 1200000 to 13999999. So RID 1000 <-> Posix ID 1201000 EXAMPLE: Add a new ID range for the local domain To create an ID range for the local domain it is not necessary to specify a domain SID. But since it is possible that a user and a group can have the same value as Posix ID a second RID interval is needed to handle conflicts. ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \ --secondary-rid-base=1000000 local_range The data from the ID ranges of the local domain are used by the IPA server internally to assign SIDs to IPA users and groups. The SID will then be stored in the user or group objects. If e.g. the ID range for the local domain is configured with the values from the example above then a new user with the UID 1200007 will get the RID 1007. If this RID is already used by a group the RID will be 1000007. This can only happen if a user or a group object was created with a fixed ID because the automatic assignment will not assign the same ID twice. Since there are only users and groups sharing the same ID namespace it is sufficient to have only one fallback range to handle conflicts. To find the Posix ID for a given RID from the local domain it has to be checked first if the RID falls in the primary or secondary RID range and the rid-base or the secondary-rid-base has to be subtracted, respectively, and the base-id has to be added to get the Posix ID. Typically the creation of ID ranges happens behind the scenes and this CLI must not be used at all. The ID range for the local domain will be created during installation or upgrade from an older version. The ID range for a trusted domain will be created together with the trust by 'ipa trust-add ...'. USE CASES: Add an ID range from a transitively trusted domain If the trusted domain (A) trusts another domain (B) as well and this trust is transitive 'ipa trust-add domain-A' will only create a range for domain A. The ID range for domain B must be added manually. Add an additional ID range for the local domain If the ID range of the local domain is exhausted, i.e. no new IDs can be assigned to Posix users or groups by the DNA plugin, a new range has to be created to allow new users and groups to be added. (Currently there is no connection between this range CLI and the DNA plugin, but a future version might be able to modify the configuration of the DNS plugin as well) In general it is not necessary to modify or delete ID ranges. If there is no other way to achieve a certain configuration than to modify or delete an ID range it should be done with great care. Because UIDs are stored in the file system and are used for access control it might be possible that users are allowed to access files of other users if an ID range got deleted and reused for a different domain. (*) The RID is typically the last integer of a user or group SID which follows the domain SID. E.g. if the domain SID is S-1-5-21-123-456-789 and a user from this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of the user. RIDs are unique in a domain, 32bit values and are used for users and groups. WARNING: DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands. Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range. tidrangecBsDeZdZdCZejjZdZdZ dgZ ddgZ d d d d d ddgZ e dƒZe dƒZiee dƒƒd6ee dƒƒd6ee dƒƒd6ee dƒƒd6ee dƒƒd6Zed ddde dƒd eƒed dd!de d"ƒƒed dd#de d$ƒƒed%dd&de d'ƒƒed(dd)de d*ƒƒed+dd,d-dDde d/ƒƒed0dd1d-dEde d4ƒƒed5de d6ƒdd7d8e d9jd:d;jejƒƒƒƒd<eejƒƒd-d.gƒfZed=„Zd>„Zd?„Zd@„ZdA„Z dB„Z!RS(Fs Range object. tdomaintadtipatrangetrangest ipaIDrangetipadomainidrangetipatrustedaddomainrangetcnt ipabaseidtipaidrangesizet ipabaseridtipasecondarybaseridtipanttrusteddomainsidt iparangetypes ID RangessID Rangeslocal domain rangeu ipa-localsActive Directory winsync rangeuipa-ad-winsyncsActive Directory domain rangeu ipa-ad-trusts2Active Directory trust range with POSIX attributesuipa-ad-trust-posixsIPA trust rangeu ipa-ipa-trusttcli_nametnametlabels Range namet primary_keytbase_idsFirst Posix ID of the ranget range_sizesNumber of IDs in the ranges ipabaserid?trid_bases(First RID of the corresponding RID rangesipasecondarybaserid?tsecondary_rid_bases$First RID of the secondary RID rangesipanttrusteddomainsid?tdom_sidtflagst no_updates Domain SID of the trusted domainsipanttrusteddomainname?tdom_namet no_searchtvirtual_attributesName of the trusted domains iparangetype?s Range typettypetdocsID range type, one of {vals}tvalss, tvaluescCsœt|jdtƒ|jdtƒfƒsW|dd}|jj|dƒg|d=%(low)d)(uidNumber<=%(high)d))tlowthighs,(&(gidNumber>=%(low)d)(gidNumber<=%(high)d))t|t&tfiltert attrs_listtuidRtbase_dnR"sipabaseid,ipaidrangesizeterrorsRrange modification leaving objects with ID out of the defined range is not allowed(R;tappendtmintmaxtbackendtdicttcombine_filterst find_entriesRRtenvtcontainer_accountstbasednR tNotFoundtValidationErrorR (R=told_basetold_sizetnew_basetnew_sizet old_intervalt new_intervaltchecked_intervalstlow_difft high_difftldaptid_filter_baset id_filter_idstid_lowtid_hight id_filtertobjectst truncated((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytcheck_ids_in_modified_rangeêsR      "       (cCsats!tjdtdƒƒ‚ntjj|jƒ}|jƒs]tjdtdƒƒ‚n|S(NtreasonsŽCannot perform SID validation without Samba 4 support installed. Make sure you have installed server-trust-ad sub-package of IPA on the serversiCross-realm trusts are not configured. Make sure you have run ipa-adtrust-install on the IPA server first( t_dcerpc_bindings_installedR RVR t ipaservertdcerpctDomainValidatorRt is_configured(R=tdomain_validator((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytget_domain_validators  cCs@|jƒ}|j|ƒs<tjdddtdƒƒ‚ndS(NR"s domain SIDRKs9SID is not recognized as a valid SID for a trusted domain(Rqtis_trusted_domain_sid_validR RWR (R=tsidRp((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytvalidate_trusted_domain_sid.s cCs:|jƒ}|j|ƒ}|dk r6t|ƒ}n|S(s Returns unicode string representation for given trusted domain name or None if SID forthe given trusted domain name could not be found.N(Rqtget_sid_from_domain_nameR;tunicode(R=R"RpRs((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyt get_trusted_domain_sid_from_name7s   cCs[td„|||fDƒƒr#tS||kr?||}}n|||krStStSdS(Ncss|]}|dkVqdS(N(R;(t.0tattr((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pys Hs(R7R9tTrue(R=R'R(tsize((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytare_rid_ranges_overlappingEs (sdomainsadsipa(s no_update(s no_searchsvirtual_attributes no_update("t__name__t __module__t__doc__RARRStcontainer_rangest container_dnt object_nametobject_name_pluralt object_classtpossible_objectclassestdefault_attributesR R#tlabel_singularRvR:RRzRR tformattjointkeysttuplet takes_paramsR9RBRiRqRtRwR|(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyRšsn                         5  t idrange_addcBs;eZedƒZedƒZd„Zd„Zd„ZRS(se Add new ID range. To add a new ID range you always have to specify --base-id --range-size Additionally --rid-base --secondary-rid-base may be given for a new ID range for the local domain while --rid-base --dom-sid must be given to add a new range for a trusted AD domain. WARNING: DNA plugin in 389-ds will allocate IDs based on the ranges configured for the local domain. Currently the DNA plugin *cannot* be reconfigured itself based on the local ranges set via this family of commands. Manual configuration change has to be done in the DNA plugin configuration for the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to be modified to match the new range. sAdded ID range "%(value)s"cst‡fd†d Dƒƒ}ˆjdd ƒ}ˆjdd ƒ}‡‡fd†}|rt|d kr |dƒq n™tjdƒd}|rÃ|d kr§|dƒn|d kr |dƒq nJ|d k rè|d krè|dƒn|d kr |d k r |dƒnd S( sn Ensure that rid-base is prompted for when dom-sid is specified. Also ensure that secondary-rid-base is prompted for when rid-base is specified and vice versa, in case that dom-sid was not specified. Also ensure that rid-base and secondary-rid-base is prompted for if ipa-adtrust-install has been run on the system. c3s|]}|ˆkVqdS(N((Rxtdom_id(tkw(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pys ŠstipanttrusteddomainnameRRRcs4ˆjˆj|ƒ}i||6}ˆj|ƒdS(N(t prompt_paramtparamstupdate(tparamtvalueR“(RR=(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytset_from_prompts tadtrust_is_enabledtresultN(Rsipanttrusteddomainsid(R7R8R;RtCommand(R=Rt dom_sid_setR'R(R–R—((RR=s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytinteractive_prompt_callbackzs$      c sÑt|tƒst‚‡fd†}d|kr­|dƒr]tjdddtdƒƒ‚n|jj|dƒ}|dk rŒ|ˆd(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pytºsRRR"sID Range setupRKs4Options dom-sid and dom-name cannot be used togetherssSID for the specified trusted domain name could not be found. Please specify the SID directly using dom-sid option.R6RR u ipa-ad-trustuipa-ad-trust-posixsmIPA Range type must be one of ipa-ad-trust or ipa-ad-trust-posix when SID of the trusted domain is specified.RsGOptions dom-sid/dom-name and secondary-rid-base cannot be used togetherRs;Options dom-sid/dom-name and rid-base must be used togetherRs ipa-localsuIPA Range type must not be one of ipa-ad-trust or ipa-ad-trust-posix when SID of the trusted domain is not specified.s=Options secondary-rid-base and rid-base must be used togetherRs8Primary RID range and secondary RID range cannot overlapR—R˜spYou must specify both rid-base and secondary-rid-base options, because ipa-adtrust-install has already been run.(u ipa-ad-trustuipa-ad-trust-posix(u ipa-ad-trustuipa-ad-trust-posix(t isinstanceRtAssertionErrorR RWR tobjRwR;RLRtR|RR™( R=RatdnR>RHRŠR?tis_setRsR—((R>s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyt pre_callback·sj                   cOs2t|tƒst‚|jj||dtƒ|S(NR@(RžRRŸR RBRz(R=RaR¡R>RŠR?((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyt post_callbacks(R}R~R Rt msg_summaryR›R£R¤(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyRWs    = et idrange_delcBs)eZedƒZedƒZd„ZRS(sDelete an ID range.sDeleted ID range "%(value)s"c Os*y%|j|dddgƒ\}}Wn$tjk rK|jj|ŒnXt|jddgƒdƒ}t|jddgƒdƒ}|jj||ddƒ|jdƒ} | dk r&| d} t j dd| ƒ} | ddkr&tj ddd |dd | d dd dƒ‚q&n|S( NRRRit trust_findtcountR#s Active Trusttkeyt dependentR˜R( t get_entryR RVR thandle_not_foundtintR8RiR;RR™tDependentEntry( R=RaR¡RŠR?told_dnt old_attrst old_base_idtold_range_sizet range_sidR˜((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR£(s(      (R}R~R RR¥R£(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR¦#s  t idrange_findcBs8eZedƒZedddƒZd„Zd„ZRS(sSearch for ranges.s%(count)d range matcheds%(count)d ranges matchedicOs2t|tƒst‚|jdƒ|||jfS(NR6(RžRRŸRLtSCOPE_ONELEVEL(R=RatfiltersRHRJtscopetargsR?((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR£Os cOs.x'|D]\}}|jj||ƒqW|S(N(R RB(R=RatentriesRhR¸R?R¡tentry((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR¤Us(R}R~R RR R¥R£R¤(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR´Fs   t idrange_showcBs&eZedƒZd„Zd„ZRS(s"Display information about a range.cOs&t|tƒst‚|jdƒ|S(NR6(RžRRŸRL(R=RaR¡RHRŠR?((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR£^s cOs,t|tƒst‚|jj||ƒ|S(N(RžRRŸR RB(R=RaR¡R>RŠR?((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR¤cs(R}R~R RR£R¤(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR»[s  t idrange_modcBsQeZedƒZedƒZejedƒedƒfZd„Zd„Z RS(sModify ID range.sModified ID range "%(value)s"sipanttrusteddomainsid?sipanttrusteddomainname?csct|tƒst‚|jdƒy|j|dgƒ\}‰Wn$tjk rg|jj|ŒnX‡fd†}‡‡fd†‰d|kr|dƒrÂtj ddd t d ƒƒ‚n|jj |dƒ} | dk rñ| ˆd(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR|scsB|ˆkrˆ|dk pA|ˆkoA|ˆkoAˆ|dk S(N(R;(Rœ(R>R°(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR}sRRR"sID Range setupRKs4Options dom-sid and dom-name cannot be used togetherssSID for the specified trusted domain name could not be found. Please specify the SID directly using dom-sid option.Rs>Options dom-sid and secondary-rid-base cannot be used togetherRs2Options dom-sid and rid-base must be used togetherRs=Options secondary-rid-base and rid-base must be used togetherc3s|]}ˆ|ƒVqdS(N((Rxtbase(tin_updated_attrs(s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pys µsRis8Primary RID range and secondary RID range cannot overlapR(s ipabaseridsipasecondarybaserid(s ipabaseridsipasecondarybaseridsipaidrangesize(RžRRŸRLR«R RVR R¬RWR RwR;RtR5RPR­R|R8Ri(R=RaR¡R>RHRŠR?R¯R¢Rstrid_range_attributestupdated_valuesRyR±R²t new_base_idtnew_range_size((R>R¿R°s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR£ssx                      cOs,t|tƒst‚|jj||ƒ|S(N(RžRRŸR RB(R=RaR¡R>RŠR?((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR¤Ýs( R}R~R RR¥Rt takes_optionsR R£R¤(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyR¼is    j(slitesserver(#tipalib.plugins.baseldapRRRRRRtipalibRRRR R R R R t ipapython.dnRRSt in_servertcontexttipaserver.dcerpcRlRzRkt ImportErrorR9RRRR¦R´R»R¼tregister(((s4/home/mkosek/freeipa-clean/ipalib/plugins/idrange.pyts..4    v ½Ì#z     freeipa-3.3.4/ipalib/plugins/pkinit.py0000664000175000017500000000533312202434255017276 0ustar mkosekmkosek# Authors: # Simo Sorce # # Copyright (C) 2010 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 . from ipalib import api, errors from ipalib import Int, Str from ipalib import Object, Command from ipalib import _ from ipapython.dn import DN __doc__ = _(""" Kerberos pkinit options Enable or disable anonymous pkinit using the principal WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with pkinit support. EXAMPLES: Enable anonymous pkinit: ipa pkinit-anonymous enable Disable anonymous pkinit: ipa pkinit-anonymous disable For more information on anonymous pkinit see: http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit """) class pkinit(Object): """ PKINIT Options """ object_name = _('pkinit') label=_('PKINIT') api.register(pkinit) def valid_arg(ugettext, action): """ Accepts only Enable/Disable. """ a = action.lower() if a != 'enable' and a != 'disable': raise errors.ValidationError( name='action', error=_('Unknown command %s') % action ) class pkinit_anonymous(Command): __doc__ = _('Enable or Disable Anonymous PKINIT.') princ_name = 'WELLKNOWN/ANONYMOUS@%s' % api.env.realm default_dn = DN(('krbprincipalname', princ_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn) takes_args = ( Str('action', valid_arg), ) def execute(self, action, **options): ldap = self.api.Backend.ldap2 set_lock = False lock = None (dn, entry_attrs) = ldap.get_entry(self.default_dn, ['nsaccountlock']) if 'nsaccountlock' in entry_attrs: lock = entry_attrs['nsaccountlock'][0].lower() if action.lower() == 'enable': if lock == 'true': set_lock = True lock = None elif action.lower() == 'disable': if lock != 'true': set_lock = True lock = 'TRUE' if set_lock: ldap.update_entry(dn, {'nsaccountlock':lock}) return dict(result=True) api.register(pkinit_anonymous) freeipa-3.3.4/ipalib/plugins/user.pyc0000664000175000017500000006716712271707517017150 0ustar mkosekmkosekó †fçRc @s¥ddlmZmZddlZddlZddlZddlmZmZddlm Z m Z m Z m Z m Z ddlTddlmZddlmZddlmZmZdd lmZdd lmZdd lmZdd lmZdd lmZmZmZej j!rEej jd=krEddl"m#Z#nedƒZ$dZ%e ddedƒƒe ddedƒƒfZ&e ddedƒƒe ddedƒƒe ddedƒƒe ddedƒƒe dded ƒƒfZ'ej(ej)d!Z*d"„Z+d#„Z,d$„Z-d%„Z.d&„Z/d'd(„Z0d)e1fd*„ƒYZ2ej3e2ƒd+e4fd,„ƒYZ5ej3e5ƒd-e6fd.„ƒYZ7ej3e7ƒd/e8fd0„ƒYZ9ej3e9ƒd1e:fd2„ƒYZ;ej3e;ƒd3e<fd4„ƒYZ=ej3e=ƒd5e>fd6„ƒYZ?ej3e?ƒd7e>fd8„ƒYZ@ej3e@ƒd9e>fd:„ƒYZAej3eAƒd;e>fd<„ƒYZBej3eBƒdS(>iÿÿÿÿ(tgmtimetstrftimeN(tapiterrors(tFlagtInttPasswordtStrtBool(t*(tbaseldap(tcontext(t_tngettext(toutput(tipa_generate_password(tEmail(tclient_has_capability(tnormalize_sshpubkeytvalidate_sshpubkeytconvert_sshpubkey_posttlitetserver(tldap2sô Users Manage user entries. All users are POSIX users. IPA supports a wide range of username formats, but you need to be aware of any restrictions that may apply to your particular environment. For example, usernames that start with a digit or usernames that exceed a certain length may cause problems for some UNIX systems. Use 'ipa config-mod' to change the username format allowed by IPA tools. Disabling a user account prevents that user from obtaining new Kerberos credentials. It does not invalidate any credentials that have already been issued. Password management is not a part of this module. For more information about this topic please see: ipa help passwd Account lockout on password failure happens per IPA master. The user-status command can be used to identify which master the user is locked out on. It is on that master the administrator must unlock the user. EXAMPLES: Add a new user: ipa user-add --first=Tim --last=User --password tuser1 Find all users whose entries include the string "Tim": ipa user-find Tim Find all users with "Tim" as the first name: ipa user-find --first=Tim Disable a user account: ipa user-disable tuser1 Enable a user account: ipa user-enable tuser1 Delete a user: ipa user-del tuser1 t __no_upg__t has_keytabtlabelsKerberos keys availables sshpubkeyfp*sSSH public key fingerprinttServertkrbloginfailedcounts Failed loginstkrblastsuccessfulauthsLast successful authenticationtkrblastfailedauthsLast failed authenticationtnowsTime nows_,.@+-=cCsŒd|krˆ|d}t|ttfƒsˆt|tƒsOtjddƒ‚n|jƒdkr…tjdddtdƒƒ‚q…qˆndS( Nt nsaccountlocktattrttruetfalsetnameterrorsmust be TRUE or FALSE(struesfalse( t isinstancetboolRt basestringRtOnlyOneValueAllowedtlowertValidationErrorR (t entry_attrsR ((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytvalidate_nsaccountlockus  cCsDd|krt|dR4(tugettextR3R=R:((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytvalidate_principalœscCs&t|ƒ\}}td||fƒS(s® Ensure that the name in the principal is lower-case. The realm is upper-case by convention but it isn't required. The principal is validated at this point. s%s@%s(R>tunicode(R3R=R:((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytnormalize_principal£suadminscCs„tjjd|ƒ}|d}g|D]}|ds&|dd^q&}||gkr€tjd|dtdƒd |ƒ‚nd S( s{ Ensure the last enabled member of a protected group cannot be deleted or disabled by raising LastMemberError. tin_grouptresultR tuiditkeyRugroupt containerN(RtCommandt user_findRtLastMemberErrorR (R=tprotected_group_nameRDtentryt enabled_users((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytcheck_protected_member®s  +R=c*BseZdZejjZedƒZedƒZ dgZ dZ dgZ dgZ dZdd d d d d ddddddddgZdd d d d ddddd ddg ZdZidddddgd6dddddgd6ZeZeZd’d“gZed!ƒZed"ƒZedd#d$d%d&d'd(d)d*d+ed,ƒd-ed.d/„d0d1„ƒed d)d2d+ed3ƒƒed d)d4d+ed5ƒƒed6d+ed7ƒd.d8„d9eƒed:d+ed;ƒd.d<„d9eƒed=d+ed>ƒd.d?„d9eƒed@d)dAd+edBƒƒedCd+edDƒd.dE„d9eƒedFd)dGd+edHƒƒedIed)dJd+edKƒd.dL„d9edMdNgd0dO„ƒedPd)dQd+edRƒƒedSd)dTd+edUƒdVedWƒdXdYƒedZdVed[ƒdMd”d^eƒed_d+ed`ƒdMd•ƒedbd)dd+edcƒdVeddƒdedfƒedgd+edhƒdVediƒdedfƒedjd)dkd+edlƒƒedmd)dnd+edoƒƒedpd)dqd+edrƒƒedsd+edtƒƒedud)dvd+edwƒƒedxd+edyƒƒedzd+ed{ƒƒed|d)d}d+ed~ƒƒedd)d€d+edƒƒed‚d+edƒƒƒed„d+ed…ƒƒed†d+ed‡ƒƒedˆd+ed‰ƒdMdŠgƒed‹e d)dŒd+edƒd0e!dŽedMd\gƒfZ"d–d„Z$d„Z%d‘„Z&RS(—s User object. R=tuserst posixaccounttipauserobjectclassestmeporiginentrytkrbticketpolicyauxtipausersearchfieldsREt givennametsnt homedirectoryt loginshellt uidnumbert gidnumbertmailtouttelephonenumberttitletmemberofR tmemberofindirectt sshpubkeyfpt ipauniqueidtgrouptnetgrouptrolethbacruletsudorulet userpasswordt has_passwordtkrbprincipalkeyRtUserstUsertpatterns4^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$tpattern_errmsgs0may only include letters, numbers, _, -, . and $t maxlengthiÿtcli_nametloginRs User logint primary_keyt default_fromcCs |d|S(Ni((RURV((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytìst normalizercCs |jƒS(N(R*(tvalue((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtístfirsts First nametlasts Last nametcns Full namecCsd||fS(Ns%s %s((RURV((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtùstautofills displayname?s Display namecCsd||fS(Ns%s %s((RURV((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtþss initials?tInitialscCsd|d|dfS(Ns%c%ci((RURV((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtsshomedirectory?thomedirsHome directorysgecos?tGECOScCsd||fS(Ns%s %s((RURV((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRt ss loginshell?tshells Login shellskrbprincipalname?R3sKerberos principalcCsd|jƒtjjfS(Ns%s@%s(R*RR9R:(RE((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtstflagst no_updatecCs t|ƒS(N(RB(Rv((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRtssmail*temails Email addresss userpassword?tpasswordRtdocsPrompt to set the user passwordtexcludetwebuisrandom?sGenerate a random user passwordt no_searchtvirtual_attributetdefaultsrandompassword?sRandom passwordt no_creates uidnumber?tUIDs7User ID Number (system will assign one if not provided)tminvalueis gidnumber?tGIDsGroup ID Numbersstreet?tstreetsStreet addresssl?tcitytCitysst?tstatesState/Provinces postalcode?tZIPstelephonenumber*tphonesTelephone Numbersmobile*sMobile Telephone Numberspager*s Pager Numbersfacsimiletelephonenumber*tfaxs Fax Numbersou?torgunits Org. Unitstitle?s Job Titlesmanager?tManagers carlicense?s Car Licensesnsaccountlock?sAccount disabledt no_options ipasshpubkey*t sshpubkeysSSH public keytcsvc Cs>|s|jjƒd}n|jddgƒd}|r:g}t|ttfƒsb|g}nxÑ|D]É}t|tƒrëd|kr¡|r¡|d|}nt|ƒsÛt j dddt d ƒt d|ƒƒ‚n|j |ƒqit|ƒs%t j dddt d ƒt d|ƒƒ‚n|j |ƒqiW|S|S( NitipadefaultemaildomainiR2u@R$RR%s invalid e-mail format: %(email)s(tbackendtget_ipa_configtgetR4R&tlistttupleR(RRR+R tdicttappend(tselfRtconfigt defaultdomaint norm_emailtm((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyt_normalize_and_validate_emailrs&   . .cCs |s dSt|tƒs%|g}ny£t|jtjjƒ}x„tt |ƒƒD]p}t||tƒr…||j |ƒr…qSn|j j |j j|||jdg|ƒ\}}|||dttdƒ||fS|||fS(NRs2(&(objectclass=posixaccount)(krbprincipalname=%s))R3(R&RªRÙRœRþR (R¡RêtfilterRëtbase_dntscopeRìR¶((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRõ¨s c Osz|jdtƒr|Sx]|D]U}|\}}|jj|||jj|||ƒt|ƒt|||ƒqW|S(Nt pkey_only(RœR/RÜR·RR1R( R¡Rêtentriest truncatedRR¶RLR²tattrs((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyR°s   s%(count)d user matcheds%(count)d users matchedi(R¸R¹R Rºtmember_attributest LDAPSearchRR R RRRõRR R(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRI”s        RÎcBs*eZedƒZejeZd„ZRS(s!Display information about a user.cOs\t|tƒst‚t|ƒ|jj|||jj|||ƒt|||ƒ|S(N(R&RªRÙR1RÜR·RR(R¡RêR²R,RìR¶((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRÇs  (R¸R¹R Rºt LDAPRetrieveRR R(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRÎÂs  t user_disablecBs2eZedƒZejZedƒZd„ZRS(sDisable a user account.s!Disabled user account "%(value)s"cOsS|jj}t|dƒ|jj||Ž}|j|ƒtdtd|dƒS(NiÿÿÿÿRDRvi(RÜRšRNRætdeactivate_entryRŸRÆ(R¡RìR¶RêR²((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRØs  ( R¸R¹R RºRtstandard_valuet has_outputRR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyR#Òs   t user_enablecBs?eZedƒZejZeje ZedƒZ d„Z RS(sEnable a user account.s Enabled user account "%(value)s"cOsE|jj}|jj||Ž}|j|ƒtdtd|dƒS(NRDRvi(RÜRšRætactivate_entryRŸRÆ(R¡RìR¶RêR²((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyRïs   ( R¸R¹R RºRR%R&t LDAPQueryRR RR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyR'ès     t user_unlockcBs2eZedƒZejZedƒZd„ZRS(s Unlock a user account An account may become locked if the password is entered incorrectly too many times within a specific time period as controlled by password policy. A locked account is a temporary condition and may be unlocked by an administrator.sUnlocked account "%(value)s"cOsb|jj||Ž}itdtƒƒd6dd6}|jjj||ƒtdtd|dƒS(Ns %Y%m%d%H%M%SZtkrbLastAdminUnlockt0tkrbLoginFailedCountRDRvi(RÜRæRRRšt update_entryRŸRÆ(R¡RìR¶R²R,((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyR s  ( R¸R¹R RºRR%R&RR(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pyR*ýs    t user_statuscBs3eZedƒZejZeje Zd„Z RS(sÏ Lockout status of a user account An account may become locked if the password is entered incorrectly too many times within a specific time period as controlled by password policy. A locked account is a temporary condition and may be unlocked by an administrator. This connects to each IPA master and displays the lockout status on each one. To determine whether an account is locked on a given server you need to compare the number of failed logins and the time of the last failure. For an account to be locked it must exceed the maxfail failures within the failinterval duration as specified in the password policy associated with the user. The failed login counter is modified only when a user attempts a log in so it is possible that an account may appear locked but the last failed login attempt is older than the lockouttime of the password policy. This means that the user may attempt a login again. cOs_|jj}|jj||Ž}ddddg}t}g}y=|jddgtd'd(d)tjj ƒ|j ƒ\}}Wn!t j k rŸ|j d ƒnXg} d } xx|D]p} | d dd } | tjjkrì|jj} nÈtd tdd| d|jjj ƒ} y| jdtjdƒWn‚tk r³}|j d| t|ƒfƒ|j|ƒ}tdƒtd| dt|ƒƒ|d<| j|ƒ| d 7} q³nXy·| j||ƒ}|j|ƒ}x1ddgD]#}|d j|dgƒ||tipalibRRRRRRRtipalib.plugins.baseldaptipalib.pluginsR tipalib.requestR R R Rtipapython.ipautilRtipapython.ipavalidateRtipalib.capabilitiesRt ipalib.utilRRRR9t in_servertipaserver.plugins.ldap2RRºRàR RPtdigitst ascii_lettersRèR-R1R>R@RBRNt LDAPObjectR=tregisterRRÌt LDAPDeleteR RRøR!RIR"RÎR)R#R'R*R/(((s1/home/mkosek/freeipa-clean/ipalib/plugins/user.pytsx   ( )                 î œ  4 +     mfreeipa-3.3.4/ipalib/plugins/delegation.py0000664000175000017500000001463412271663206020125 0ustar mkosekmkosek# Authors: # Rob Crittenden # Martin Kosek # # Copyright (C) 2010 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 . from ipalib import api, _, ngettext from ipalib import Flag, Str from ipalib.request import context from ipalib import api, crud, errors from ipalib import output from ipalib import Object, Command from ipalib.plugins.baseldap import gen_pkey_only_option __doc__ = _(""" Group to Group Delegation A permission enables fine-grained delegation of permissions. Access Control Rules, or instructions (ACIs), grant permission to permissions to perform given tasks such as adding a user, modifying a group, etc. Group to Group Delegations grants the members of one group to update a set of attributes of members of another group. EXAMPLES: Add a delegation rule to allow managers to edit employee's addresses: ipa delegation-add --attrs=street --group=managers --membergroup=employees "managers edit employees' street" When managing the list of attributes you need to include all attributes in the list, including existing ones. Add postalCode to the list: ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --membergroup=employees "managers edit employees' street" Display our updated rule: ipa delegation-show "managers edit employees' street" Delete a rule: ipa delegation-del "managers edit employees' street" """) ACI_PREFIX=u"delegation" output_params = ( Str('aci', label=_('ACI'), ), ) class delegation(Object): """ Delegation object. """ bindable = False object_name = _('delegation') object_name_plural = _('delegations') label = _('Delegations') label_singular = _('Delegation') takes_params = ( Str('aciname', cli_name='name', label=_('Delegation name'), doc=_('Delegation name'), primary_key=True, ), Str('permissions*', cli_name='permissions', label=_('Permissions'), doc=_('Permissions to grant (read, write). Default is write.'), csv=True, ), Str('attrs+', cli_name='attrs', label=_('Attributes'), doc=_('Attributes to which the delegation applies'), csv=True, normalizer=lambda value: value.lower(), ), Str('memberof', cli_name='membergroup', label=_('Member user group'), doc=_('User group to apply delegation to'), ), Str('group', cli_name='group', label=_('User group'), doc=_('User group ACI grants access to'), ), ) def __json__(self): json_friendly_attributes = ( 'label', 'label_singular', 'takes_params', 'bindable', 'name', 'object_name', 'object_name_plural', ) json_dict = dict( (a, getattr(self, a)) for a in json_friendly_attributes ) json_dict['primary_key'] = self.primary_key.name json_dict['methods'] = [m for m in self.methods] return json_dict def postprocess_result(self, result): try: # do not include prefix in result del result['aciprefix'] except KeyError: pass api.register(delegation) class delegation_add(crud.Create): __doc__ = _('Add a new delegation.') msg_summary = _('Added delegation "%(value)s"') has_output_params = output_params def execute(self, aciname, **kw): if not 'permissions' in kw: kw['permissions'] = (u'write',) kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_add'](aciname, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(delegation_add) class delegation_del(crud.Delete): __doc__ = _('Delete a delegation.') has_output = output.standard_boolean msg_summary = _('Deleted delegation "%(value)s"') def execute(self, aciname, **kw): kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_del'](aciname, **kw) self.obj.postprocess_result(result) return dict( result=True, value=aciname, ) api.register(delegation_del) class delegation_mod(crud.Update): __doc__ = _('Modify a delegation.') msg_summary = _('Modified delegation "%(value)s"') has_output_params = output_params def execute(self, aciname, **kw): kw['aciprefix'] = ACI_PREFIX result = api.Command['aci_mod'](aciname, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(delegation_mod) class delegation_find(crud.Search): __doc__ = _('Search for delegations.') msg_summary = ngettext( '%(count)d delegation matched', '%(count)d delegations matched', 0 ) takes_options = (gen_pkey_only_option("name"),) has_output_params = output_params def execute(self, term, **kw): kw['aciprefix'] = ACI_PREFIX results = api.Command['aci_find'](term, **kw)['result'] for aci in results: self.obj.postprocess_result(aci) return dict( result=results, count=len(results), truncated=False, ) api.register(delegation_find) class delegation_show(crud.Retrieve): __doc__ = _('Display information about a delegation.') has_output_params = output_params def execute(self, aciname, **kw): result = api.Command['aci_show'](aciname, aciprefix=ACI_PREFIX, **kw)['result'] self.obj.postprocess_result(result) return dict( result=result, value=aciname, ) api.register(delegation_show) freeipa-3.3.4/ipalib/frontend.py0000664000175000017500000015006712271663206016151 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Base classes for all front-end plugins. """ import re from distutils import version from ipapython.version import API_VERSION from ipapython.ipa_log_manager import root_logger from base import NameSpace from plugable import Plugin, is_production_mode from parameters import create_param, Param, Str, Flag, Password from output import Output, Entry, ListOfEntries from text import _ from errors import (ZeroArgumentError, MaxArgumentError, OverlapError, VersionError, OptionError, InvocationError, ValidationError, ConversionError) from ipalib import messages from textwrap import wrap RULE_FLAG = 'validation_rule' def rule(obj): assert not hasattr(obj, RULE_FLAG) setattr(obj, RULE_FLAG, True) return obj def is_rule(obj): return callable(obj) and getattr(obj, RULE_FLAG, False) is True def entry_count(entry): """ Return the number of entries in an entry. This is primarly for the failed output parameter so we don't print empty values. We also use this to determine if a non-zero return value is needed. """ num_entries = 0 for f in entry: if type(entry[f]) is dict: num_entries = num_entries + entry_count(entry[f]) else: num_entries = num_entries + len(entry[f]) return num_entries class HasParam(Plugin): """ Base class for plugins that have `Param` `NameSpace` attributes. Subclasses of `HasParam` will on one or more attributes store `NameSpace` instances containing zero or more `Param` instances. These parameters might describe, for example, the arguments and options a command takes, or the attributes an LDAP entry can include, or whatever else the subclass sees fit. Although the interface a subclass must implement is very simple, it must conform to a specific naming convention: if you want a namespace ``SubClass.foo``, you must define a ``Subclass.takes_foo`` attribute and a ``SubCLass.get_foo()`` method, and you may optionally define a ``SubClass.check_foo()`` method. A quick big-picture example =========================== Say you want the ``options`` instance attribute on your subclass to be a `Param` `NameSpace`... then according to the enforced naming convention, your subclass must define a ``takes_options`` attribute and a ``get_options()`` method. For example: >>> from ipalib import Str, Int >>> class Example(HasParam): ... ... options = None # This will be replaced with your namespace ... ... takes_options = (Str('one'), Int('two')) ... ... def get_options(self): ... return self._get_param_iterable('options') ... >>> eg = Example() The ``Example.takes_options`` attribute is a ``tuple`` defining the parameters you want your ``Example.options`` namespace to contain. Your ``Example.takes_options`` attribute will be accessed via `HasParam._get_param_iterable()`, which, among other things, enforces the ``('takes_' + name)`` naming convention. For example: >>> eg._get_param_iterable('options') (Str('one'), Int('two')) The ``Example.get_options()`` method simply returns ``Example.takes_options`` by calling `HasParam._get_param_iterable()`. Your ``Example.get_options()`` method will be called via `HasParam._filter_param_by_context()`, which, among other things, enforces the ``('get_' + name)`` naming convention. For example: >>> list(eg._filter_param_by_context('options')) [Str('one'), Int('two')] At this point, the ``eg.options`` instance attribute is still ``None``: >>> eg.options is None True `HasParam._create_param_namespace()` will create the ``eg.options`` namespace from the parameters yielded by `HasParam._filter_param_by_context()`. For example: >>> eg._create_param_namespace('options') >>> eg.options NameSpace(<2 members>, sort=False) >>> list(eg.options) # Like dict.__iter__() ['one', 'two'] Your subclass can optionally define a ``check_options()`` method to perform sanity checks. If it exists, the ``check_options()`` method is called by `HasParam._create_param_namespace()` with a single value, the `NameSpace` instance it created. For example: >>> class Example2(Example): ... ... def check_options(self, namespace): ... for param in namespace(): # Like dict.itervalues() ... if param.name == 'three': ... raise ValueError("I dislike the param 'three'") ... print ' ** Looks good! **' # Note output below ... >>> eg = Example2() >>> eg._create_param_namespace('options') ** Looks good! ** >>> eg.options NameSpace(<2 members>, sort=False) However, if we subclass again and add a `Param` named ``'three'``: >>> class Example3(Example2): ... ... takes_options = (Str('one'), Int('two'), Str('three')) ... >>> eg = Example3() >>> eg._create_param_namespace('options') Traceback (most recent call last): ... ValueError: I dislike the param 'three' >>> eg.options is None # eg.options was not set True The Devil and the details ========================= In the above example, ``takes_options`` is a ``tuple``, but it can also be a param spec (see `create_param()`), or a callable that returns an iterable containing one or more param spec. Regardless of how ``takes_options`` is defined, `HasParam._get_param_iterable()` will return a uniform iterable, conveniently hiding the details. The above example uses the simplest ``get_options()`` method possible, but you could instead implement a ``get_options()`` method that would, for example, produce (or withhold) certain parameters based on the whether certain plugins are loaded. Think of ``takes_options`` as declarative, a simple definition of *what* parameters should be included in the namespace. You should only implement a ``takes_options()`` method if a `Param` must reference attributes on your plugin instance (for example, for validation rules); you should not use a ``takes_options()`` method to filter the parameters or add any other procedural behaviour. On the other hand, think of the ``get_options()`` method as imperative, a procedure for *how* the parameters should be created and filtered. In the example above the *how* just returns the *what* unchanged, but arbitrary logic can be implemented in the ``get_options()`` method. For example, you might filter certain parameters from ``takes_options`` base on some criteria, or you might insert additional parameters provided by other plugins. The typical use case for using ``get_options()`` this way is to procedurally generate the arguments and options for all the CRUD commands operating on a specific LDAP object: the `Object` plugin defines the possible LDAP entry attributes (as `Param`), and then the CRUD commands intelligently build their ``args`` and ``options`` namespaces based on which attribute is the primary key. In this way new LDAP attributes (aka parameters) can be added to the single point of definition (the `Object` plugin), and all the corresponding CRUD commands pick up these new parameters without requiring modification. For an example of how this is done, see the `ipalib.crud.Create` base class. However, there is one type of filtering you should not implement in your ``get_options()`` method, because it's already provided at a higher level: you should not filter parameters based on the value of ``api.env.context`` nor (preferably) on any values in ``api.env``. `HasParam._filter_param_by_context()` already does this by calling `Param.use_in_context()` for each parameter. Although the base `Param.use_in_context()` implementation makes a decision solely on the value of ``api.env.context``, subclasses can override this with implementations that consider arbitrary ``api.env`` values. """ # HasParam is the base class for most frontend plugins, that make it to users # This flag indicates that the command should not be available in the cli NO_CLI = False def _get_param_iterable(self, name, verb='takes'): """ Return an iterable of params defined by the attribute named ``name``. A sequence of params can be defined one of three ways: as a ``tuple``; as a callable that returns an iterable; or as a param spec (a `Param` or ``str`` instance). This method returns a uniform iterable regardless of how the param sequence was defined. For example, when defined with a tuple: >>> class ByTuple(HasParam): ... takes_args = (Param('foo'), Param('bar')) ... >>> by_tuple = ByTuple() >>> list(by_tuple._get_param_iterable('args')) [Param('foo'), Param('bar')] Or you can define your param sequence with a callable when you need to reference attributes on your plugin instance (for validation rules, etc.). For example: >>> class ByCallable(HasParam): ... def takes_args(self): ... yield Param('foo', self.validate_foo) ... yield Param('bar', self.validate_bar) ... ... def validate_foo(self, _, value, **kw): ... if value != 'Foo': ... return _("must be 'Foo'") ... ... def validate_bar(self, _, value, **kw): ... if value != 'Bar': ... return _("must be 'Bar'") ... >>> by_callable = ByCallable() >>> list(by_callable._get_param_iterable('args')) [Param('foo', validate_foo), Param('bar', validate_bar)] Lastly, as a convenience for when a param sequence contains a single param, your defining attribute may a param spec (either a `Param` or an ``str`` instance). For example: >>> class BySpec(HasParam): ... takes_args = Param('foo') ... takes_options = 'bar?' ... >>> by_spec = BySpec() >>> list(by_spec._get_param_iterable('args')) [Param('foo')] >>> list(by_spec._get_param_iterable('options')) ['bar?'] For information on how an ``str`` param spec is interpreted, see the `create_param()` and `parse_param_spec()` functions in the `ipalib.parameters` module. Also see `HasParam._filter_param_by_context()`. """ src_name = verb + '_' + name src = getattr(self, src_name, None) if type(src) is tuple: return src if isinstance(src, (Param, str)): return (src,) if callable(src): return src() if src is None: return tuple() raise TypeError( '%s.%s must be a tuple, callable, or spec; got %r' % ( self.name, src_name, src ) ) def _filter_param_by_context(self, name, env=None): """ Filter params on attribute named ``name`` by environment ``env``. For example: >>> from ipalib.config import Env >>> class Example(HasParam): ... ... takes_args = ( ... Str('foo_only', include=['foo']), ... Str('not_bar', exclude=['bar']), ... 'both', ... ) ... ... def get_args(self): ... return self._get_param_iterable('args') ... ... >>> eg = Example() >>> foo = Env(context='foo') >>> bar = Env(context='bar') >>> another = Env(context='another') >>> (foo.context, bar.context, another.context) (u'foo', u'bar', u'another') >>> list(eg._filter_param_by_context('args', foo)) [Str('foo_only', include=['foo']), Str('not_bar', exclude=['bar']), Str('both')] >>> list(eg._filter_param_by_context('args', bar)) [Str('both')] >>> list(eg._filter_param_by_context('args', another)) [Str('not_bar', exclude=['bar']), Str('both')] """ env = getattr(self, 'env', env) get_name = 'get_' + name if not hasattr(self, get_name): raise NotImplementedError( '%s.%s()' % (self.name, get_name) ) get = getattr(self, get_name) if not callable(get): raise TypeError( '%s.%s must be a callable; got %r' % (self.name, get_name, get) ) for spec in get(): param = create_param(spec) if env is None or param.use_in_context(env): if env is not None and not hasattr(param, 'env'): # Force specified environment. The way it is done is violation of ReadOnly promise. # Unfortunately, all alternatives are worse from both performance and code complexity # points of view. See following threads on freeipa-devel@ for references: # https://www.redhat.com/archives/freeipa-devel/2011-August/msg00000.html # https://www.redhat.com/archives/freeipa-devel/2011-August/msg00011.html object.__setattr__(param, 'env', env) yield param def _create_param_namespace(self, name, env=None): namespace = NameSpace( self._filter_param_by_context(name, env), sort=False ) if not is_production_mode(self): check = getattr(self, 'check_' + name, None) if callable(check): check(namespace) setattr(self, name, namespace) class Command(HasParam): """ A public IPA atomic operation. All plugins that subclass from `Command` will be automatically available as a CLI command and as an XML-RPC method. Plugins that subclass from Command are registered in the ``api.Command`` namespace. For example: >>> from ipalib import create_api >>> api = create_api() >>> class my_command(Command): ... pass ... >>> api.register(my_command) >>> api.finalize() >>> list(api.Command) ['my_command'] >>> api.Command.my_command # doctest:+ELLIPSIS ipalib.frontend.my_command() """ finalize_early = False takes_options = tuple() takes_args = tuple() # Create stubs for attributes that are set in _on_finalize() args = Plugin.finalize_attr('args') options = Plugin.finalize_attr('options') params = Plugin.finalize_attr('params') params_by_default = Plugin.finalize_attr('params_by_default') obj = None use_output_validation = True output = Plugin.finalize_attr('output') has_output = ('result',) output_params = Plugin.finalize_attr('output_params') has_output_params = tuple() internal_options = tuple() msg_summary = None msg_truncated = _('Results are truncated, try a more specific search') def __call__(self, *args, **options): """ Perform validation and then execute the command. If not in a server context, the call will be forwarded over XML-RPC and the executed an the nearest IPA server. """ self.ensure_finalized() params = self.args_options_2_params(*args, **options) self.debug( 'raw: %s(%s)', self.name, ', '.join(self._repr_iter(**params)) ) params.update(self.get_default(**params)) params = self.normalize(**params) params = self.convert(**params) self.debug( '%s(%s)', self.name, ', '.join(self._repr_iter(**params)) ) if not self.api.env.in_server and 'version' not in params: params['version'] = API_VERSION self.validate(**params) (args, options) = self.params_2_args_options(**params) ret = self.run(*args, **options) if ( isinstance(ret, dict) and 'summary' in self.output and 'summary' not in ret ): if self.msg_summary: ret['summary'] = self.msg_summary % ret else: ret['summary'] = None if self.use_output_validation and (self.output or ret is not None): self.validate_output(ret) return ret def soft_validate(self, values): errors = dict() for p in self.params(): try: value = values.get(p.name) values[p.name] = p(value, **values) except InvocationError, e: errors[p.name] = str(e) return dict( values=values, errors=errors, ) def _repr_iter(self, **params): """ Iterate through ``repr()`` of *safe* values of args and options. This method uses `parameters.Param.safe_value()` to mask passwords when logging. Logging the exact call is extremely useful, but we obviously don't want to log the cleartext password. For example: >>> class my_cmd(Command): ... takes_args = ('login',) ... takes_options=(Password('passwd'),) ... >>> c = my_cmd() >>> c.finalize() >>> list(c._repr_iter(login=u'Okay.', passwd=u'Private!')) ["u'Okay.'", "passwd=u'********'"] """ for arg in self.args(): value = params.get(arg.name, None) yield repr(arg.safe_value(value)) for option in self.options(): if option.name not in params: continue value = params[option.name] yield '%s=%r' % (option.name, option.safe_value(value)) def args_options_2_params(self, *args, **options): """ Merge (args, options) into params. """ if self.max_args is not None and len(args) > self.max_args: if self.max_args == 0: raise ZeroArgumentError(name=self.name) raise MaxArgumentError(name=self.name, count=self.max_args) params = dict(self.__options_2_params(options)) if len(args) > 0: arg_kw = dict(self.__args_2_params(args)) intersection = set(arg_kw).intersection(params) if len(intersection) > 0: raise OverlapError(names=sorted(intersection)) params.update(arg_kw) return params def __args_2_params(self, values): multivalue = False for (i, arg) in enumerate(self.args()): assert not multivalue if len(values) > i: if arg.multivalue: multivalue = True if len(values) == i + 1 and type(values[i]) in (list, tuple): yield (arg.name, values[i]) else: yield (arg.name, values[i:]) else: yield (arg.name, values[i]) else: break def __options_2_params(self, options): for name in self.params: if name in options: yield (name, options.pop(name)) # If any options remain, they are either internal or unknown unused_keys = set(options).difference(self.internal_options) if unused_keys: raise OptionError(_('Unknown option: %(option)s'), option=unused_keys.pop()) def args_options_2_entry(self, *args, **options): """ Creates a LDAP entry from attributes in args and options. """ kw = self.args_options_2_params(*args, **options) return dict(self.__attributes_2_entry(kw)) def __attributes_2_entry(self, kw): for name in self.params: if self.params[name].attribute and name in kw: value = kw[name] if isinstance(value, tuple): yield (name, [v for v in value]) else: yield (name, kw[name]) def params_2_args_options(self, **params): """ Split params into (args, options). """ args = tuple(params.get(name, None) for name in self.args) options = dict(self.__params_2_options(params)) return (args, options) def __params_2_options(self, params): for name in self.options: if name in params: yield(name, params[name]) def prompt_param(self, param, default=None, optional=False, kw=dict(), label=None): """ Prompts the user for the value of given parameter. Returns the parameter instance. """ if label is None: label = param.label while True: raw = self.Backend.textui.prompt(label, default, optional=optional) # Backend.textui.prompt does not fill in the default value, # we have to do it ourselves if not raw.strip(): raw = default try: return param(raw, **kw) except (ValidationError, ConversionError), e: # Display error and prompt again self.Backend.textui.print_prompt_attribute_error(unicode(label), unicode(e.error)) def normalize(self, **kw): """ Return a dictionary of normalized values. For example: >>> class my_command(Command): ... takes_options = ( ... Param('first', normalizer=lambda value: value.lower()), ... Param('last'), ... ) ... >>> c = my_command() >>> c.finalize() >>> c.normalize(first=u'JOHN', last=u'DOE') {'last': u'DOE', 'first': u'john'} """ return dict( (k, self.params[k].normalize(v)) for (k, v) in kw.iteritems() ) def convert(self, **kw): """ Return a dictionary of values converted to correct type. >>> from ipalib import Int >>> class my_command(Command): ... takes_args = ( ... Int('one'), ... 'two', ... ) ... >>> c = my_command() >>> c.finalize() >>> c.convert(one=1, two=2) {'two': u'2', 'one': 1} """ return dict( (k, self.params[k].convert(v)) for (k, v) in kw.iteritems() ) def __convert_iter(self, kw): for param in self.params(): if kw.get(param.name, None) is None: continue def get_default(self, **kw): """ Return a dictionary of defaults for all missing required values. For example: >>> from ipalib import Str >>> class my_command(Command): ... takes_args = Str('color', default=u'Red') ... >>> c = my_command() >>> c.finalize() >>> c.get_default() {'color': u'Red'} >>> c.get_default(color=u'Yellow') {} """ params = [p.name for p in self.params() if p.name not in kw and (p.required or p.autofill)] return dict(self.__get_default_iter(params, kw)) def get_default_of(self, name, **kw): """ Return default value for parameter `name`. """ default = dict(self.__get_default_iter([name], kw)) return default.get(name) def __get_default_iter(self, params, kw): """ Generator method used by `Command.get_default` and `Command.get_default_of`. """ # Find out what additional parameters are needed to dynamically create # the default values with default_from. dep = set() for param in reversed(self.params_by_default): if param.name in params or param.name in dep: if param.default_from is None: continue for name in param.default_from.keys: dep.add(name) for param in self.params_by_default(): default = None hasdefault = False if param.name in dep: if param.name in kw: # Parameter is specified, convert and validate the value. kw[param.name] = param(kw[param.name], **kw) else: # Parameter is not specified, use default value. Convert # and validate the value, it might not be returned so # there's no guarantee it will be converted and validated # later. default = param(None, **kw) if default is not None: kw[param.name] = default hasdefault = True if param.name in params: if not hasdefault: # Default value is not available from the previous step, # get it now. At this point it is certain that the value # will be returned, so let the caller care about conversion # and validation. default = param.get_default(**kw) if default is not None: yield (param.name, default) def validate(self, **kw): """ Validate all values. If any value fails the validation, `ipalib.errors.ValidationError` (or a subclass thereof) will be raised. """ for param in self.params(): value = kw.get(param.name, None) param.validate(value, self.env.context, supplied=param.name in kw) def verify_client_version(self, client_version): """ Compare the version the client provided to the version of the server. If the client major version does not match then return an error. If the client minor version is less than or equal to the server then let the request proceed. """ server_ver = version.LooseVersion(API_VERSION) ver = version.LooseVersion(client_version) if len(ver.version) < 2: raise VersionError(cver=ver.version, sver=server_ver.version, server= self.env.xmlrpc_uri) client_major = ver.version[0] client_minor = ver.version[1] server_major = server_ver.version[0] server_minor = server_ver.version[1] if server_major != client_major: raise VersionError(cver=client_version, sver=API_VERSION, server=self.env.xmlrpc_uri) if client_minor > server_minor: raise VersionError(cver=client_version, sver=API_VERSION, server=self.env.xmlrpc_uri) def run(self, *args, **options): """ Dispatch to `Command.execute` or `Command.forward`. If running in a server context, `Command.execute` is called and the actually work this command performs is executed locally. If running in a non-server context, `Command.forward` is called, which forwards this call over XML-RPC to the exact same command on the nearest IPA server and the actual work this command performs is executed remotely. """ if self.api.env.in_server: version_provided = 'version' in options if version_provided: self.verify_client_version(options['version']) else: options['version'] = API_VERSION result = self.execute(*args, **options) if not version_provided: messages.add_message( API_VERSION, result, messages.VersionMissing(server_version=API_VERSION)) return result return self.forward(*args, **options) def execute(self, *args, **kw): """ Perform the actual work this command does. This method should be implemented only against functionality in self.api.Backend. For example, a hypothetical user_add.execute() might be implemented like this: >>> class user_add(Command): ... def execute(self, **kw): ... return self.api.Backend.ldap.add(**kw) ... """ raise NotImplementedError('%s.execute()' % self.name) def forward(self, *args, **kw): """ Forward call over XML-RPC to this same command on server. """ return self.Backend.xmlclient.forward(self.name, *args, **kw) def _on_finalize(self): """ Finalize plugin initialization. This method creates the ``args``, ``options``, and ``params`` namespaces. This is not done in `Command.__init__` because subclasses (like `crud.Add`) might need to access other plugins loaded in self.api to determine what their custom `Command.get_args` and `Command.get_options` methods should yield. """ self._create_param_namespace('args') if len(self.args) == 0 or not self.args[-1].multivalue: self.max_args = len(self.args) else: self.max_args = None self._create_param_namespace('options') params_nosort = tuple(self.args()) + tuple(self.options()) def get_key(p): if p.required: if p.sortorder < 0: return p.sortorder if p.default_from is None: return 0 return 1 return 2 self.params = NameSpace( sorted(params_nosort, key=get_key), sort=False ) # Sort params so that the ones with default_from come after the ones # that the default_from might depend on and save the result in # params_by_default namespace. params = [] for i in params_nosort: pos = len(params) for j in params_nosort: if j.default_from is None: continue if i.name not in j.default_from.keys: continue try: pos = min(pos, params.index(j)) except ValueError: pass params.insert(pos, i) self.params_by_default = NameSpace(params, sort=False) self.output = NameSpace(self._iter_output(), sort=False) self._create_param_namespace('output_params') super(Command, self)._on_finalize() def _iter_output(self): if type(self.has_output) is not tuple: raise TypeError('%s.has_output: need a %r; got a %r: %r' % ( self.name, tuple, type(self.has_output), self.has_output) ) for (i, o) in enumerate(self.has_output): if isinstance(o, str): o = Output(o) if not isinstance(o, Output): raise TypeError('%s.has_output[%d]: need a %r; got a %r: %r' % ( self.name, i, (str, Output), type(o), o) ) yield o def get_args(self): """ Iterate through parameters for ``Command.args`` namespace. This method gets called by `HasParam._create_param_namespace()`. Subclasses can override this to customize how the arguments are determined. For an example of why this can be useful, see the `ipalib.crud.Create` subclass. """ for arg in self._get_param_iterable('args'): yield arg def check_args(self, args): """ Sanity test for args namespace. This method gets called by `HasParam._create_param_namespace()`. """ optional = False multivalue = False for arg in args(): if optional and arg.required: raise ValueError( '%s: required argument after optional in %s arguments %s' % (arg.name, self.name, map(lambda x: x.param_spec, args())) ) if multivalue: raise ValueError( '%s: only final argument can be multivalue' % arg.name ) if not arg.required: optional = True if arg.multivalue: multivalue = True def get_options(self): """ Iterate through parameters for ``Command.options`` namespace. This method gets called by `HasParam._create_param_namespace()`. For commands that return entries two special options are generated: --all makes the command retrieve/display all attributes --raw makes the command display attributes as they are stored Subclasses can override this to customize how the arguments are determined. For an example of why this can be useful, see the `ipalib.crud.Create` subclass. """ for option in self._get_param_iterable('options'): yield option for o in self.has_output: if isinstance(o, (Entry, ListOfEntries)): yield Flag('all', cli_name='all', doc=_('Retrieve and print all attributes from the server. Affects command output.'), exclude='webui', flags=['no_output'], ) yield Flag('raw', cli_name='raw', doc=_('Print entries as stored on the server. Only affects output format.'), exclude='webui', flags=['no_output'], ) break yield Str('version?', doc=_('Client version. Used to determine if server will accept request.'), exclude='webui', flags=['no_option', 'no_output'], ) def validate_output(self, output): """ Validate the return value to make sure it meets the interface contract. """ nice = '%s.validate_output()' % self.name if not isinstance(output, dict): raise TypeError('%s: need a %r; got a %r: %r' % ( nice, dict, type(output), output) ) expected_set = set(self.output) actual_set = set(output) - set(['messages']) if expected_set != actual_set: missing = expected_set - actual_set if missing: raise ValueError('%s: missing keys %r in %r' % ( nice, sorted(missing), output) ) extra = actual_set - expected_set if extra: raise ValueError('%s: unexpected keys %r in %r' % ( nice, sorted(extra), output) ) for o in self.output(): value = output[o.name] if not (o.type is None or isinstance(value, o.type)): raise TypeError('%s:\n output[%r]: need %r; got %r: %r' % ( nice, o.name, o.type, type(value), value) ) if callable(o.validate): o.validate(self, value) def get_output_params(self): for param in self._get_param_iterable('output_params', verb='has'): yield param if self.params is None: return for param in self.params(): if 'no_output' in param.flags: continue yield param def log_messages(self, output, logger): logger_functions = dict( debug=logger.debug, info=logger.info, warning=logger.warning, error=logger.error, ) for message in output.get('messages', ()): try: function = logger_functions[message['type']] except KeyError: logger.error('Server sent a message with a wrong type') function = logger.error function(message.get('message')) def output_for_cli(self, textui, output, *args, **options): """ Generic output method. Prints values the output argument according to their type and self.output. Entry attributes are labeled and printed in the order specified in self.output_params. Attributes that aren't present in self.output_params are not printed unless the command was invokend with the --all option. Attribute labelling is disabled if the --raw option was given. Subclasses can override this method, if custom output is needed. """ if not isinstance(output, dict): return rv = 0 self.log_messages(output, root_logger) order = [p.name for p in self.output_params()] if options.get('all', False): order.insert(0, 'dn') print_all = True else: print_all = False if options.get('raw', False): labels = None else: labels = dict((p.name, unicode(p.label)) for p in self.output_params()) flags = dict((p.name, p.flags) for p in self.output_params()) for o in self.output: outp = self.output[o] if 'no_display' in outp.flags: continue result = output[o] if o.lower() == 'count' and result == 0: rv = 1 elif o.lower() == 'failed': if entry_count(result) == 0: # Don't display an empty failed list continue else: # Return an error to the shell rv = 1 if isinstance(outp, ListOfEntries): textui.print_entries(result, order, labels, flags, print_all) elif isinstance(result, (tuple, list)): textui.print_entries(result, order, labels, flags, print_all) elif isinstance(outp, Entry): textui.print_entry(result, order, labels, flags, print_all) elif isinstance(result, dict): textui.print_entry(result, order, labels, flags, print_all) elif isinstance(result, unicode): if o == 'summary': textui.print_summary(result) else: textui.print_indented(result) elif isinstance(result, bool): # the Delete commands return a boolean indicating # success or failure. Ignore these. pass elif isinstance(result, int): textui.print_count(result, '%s %%d' % unicode(self.output[o].doc)) return rv # list of attributes we want exported to JSON json_friendly_attributes = ( 'name', 'takes_args', ) # list of options we want only to mention their presence and not to write # their attributes json_only_presence_options = ( 'all', 'raw', 'attrs', 'addattr', 'delattr', 'setattr', 'version', ) def get_json_options(self): """ Get only options we want exported to JSON """ for option in self.get_options(): if option.name not in self.json_only_presence_options: yield option else: yield { 'name': option.name } def __json__(self): json_dict = dict( (a, getattr(self, a)) for a in self.json_friendly_attributes ) json_dict['takes_options'] = list(self.get_json_options()) return json_dict class LocalOrRemote(Command): """ A command that is explicitly executed locally or remotely. This is for commands that makes sense to execute either locally or remotely to return a perhaps different result. The best example of this is the `ipalib.plugins.f_misc.env` plugin which returns the key/value pairs describing the configuration state: it can be """ takes_options = ( Flag('server?', doc=_('Forward to server instead of running locally'), ), ) def run(self, *args, **options): """ Dispatch to forward() or execute() based on ``server`` option. When running in a client context, this command is executed remotely if ``options['server']`` is true; otherwise it is executed locally. When running in a server context, this command is always executed locally and the value of ``options['server']`` is ignored. """ if options['server'] and not self.env.in_server: return self.forward(*args, **options) return self.execute(*args, **options) class Local(Command): """ A command that is explicitly executed locally. This is for commands that makes sense to execute only locally such as the help command. """ def run(self, *args, **options): """ Dispatch to forward() onlly. """ return self.forward(*args, **options) class Object(HasParam): finalize_early = False # Create stubs for attributes that are set in _on_finalize() backend = Plugin.finalize_attr('backend') methods = Plugin.finalize_attr('methods') properties = Plugin.finalize_attr('properties') params = Plugin.finalize_attr('params') primary_key = Plugin.finalize_attr('primary_key') params_minus_pk = Plugin.finalize_attr('params_minus_pk') # Can override in subclasses: backend_name = None takes_params = tuple() def _on_finalize(self): self.methods = NameSpace( self.__get_attrs('Method'), sort=False, name_attr='attr_name' ) self.properties = NameSpace( self.__get_attrs('Property'), sort=False, name_attr='attr_name' ) self._create_param_namespace('params') pkeys = filter(lambda p: p.primary_key, self.params()) if len(pkeys) > 1: raise ValueError( '%s (Object) has multiple primary keys: %s' % ( self.name, ', '.join(p.name for p in pkeys), ) ) if len(pkeys) == 1: self.primary_key = pkeys[0] self.params_minus_pk = NameSpace( filter(lambda p: not p.primary_key, self.params()), sort=False ) else: self.primary_key = None self.params_minus_pk = self.params if 'Backend' in self.api and self.backend_name in self.api.Backend: self.backend = self.api.Backend[self.backend_name] super(Object, self)._on_finalize() def params_minus(self, *names): """ Yield all Param whose name is not in ``names``. """ if len(names) == 1 and not isinstance(names[0], (Param, str)): names = names[0] minus = frozenset(names) for param in self.params(): if param.name in minus or param in minus: continue yield param def get_dn(self, *args, **kwargs): """ Construct an LDAP DN. """ raise NotImplementedError('%s.get_dn()' % self.name) def __get_attrs(self, name): if name not in self.api: return namespace = self.api[name] assert type(namespace) is NameSpace for plugin in namespace(): # Equivalent to dict.itervalues() if plugin.obj_name == self.name: yield plugin def get_params(self): """ This method gets called by `HasParam._create_param_namespace()`. """ props = self.properties.__todict__() for spec in self._get_param_iterable('params'): if type(spec) is str: key = spec.rstrip('?*+') else: assert isinstance(spec, Param) key = spec.name if key in props: yield props.pop(key).param else: yield create_param(spec) def get_key(p): if p.param.required: if p.param.default_from is None: return 0 return 1 return 2 for prop in sorted(props.itervalues(), key=get_key): yield prop.param class Attribute(Plugin): """ Base class implementing the attribute-to-object association. `Attribute` plugins are associated with an `Object` plugin to group a common set of commands that operate on a common set of parameters. The association between attribute and object is done using a simple naming convention: the first part of the plugin class name (up to the first underscore) is the object name, and rest is the attribute name, as this table shows: =============== =========== ============== Class name Object name Attribute name =============== =========== ============== noun_verb noun verb user_add user add user_first_name user first_name =============== =========== ============== For example: >>> class user_add(Attribute): ... pass ... >>> instance = user_add() >>> instance.obj_name 'user' >>> instance.attr_name 'add' In practice the `Attribute` class is not used directly, but rather is only the base class for the `Method` and `Property` classes. Also see the `Object` class. """ finalize_early = False NAME_REGEX = re.compile( '^(?P[a-z][a-z0-9]+)_(?P[a-z][a-z0-9]+(?:_[a-z][a-z0-9]+)*)$' ) # Create stubs for attributes that are set in _on_finalize() __obj = Plugin.finalize_attr('_Attribute__obj') def __init__(self): m = self.NAME_REGEX.match(type(self).__name__) assert m self.__obj_name = m.group('obj') self.__attr_name = m.group('attr') super(Attribute, self).__init__() def __get_obj_name(self): return self.__obj_name obj_name = property(__get_obj_name) def __get_attr_name(self): return self.__attr_name attr_name = property(__get_attr_name) def __get_obj(self): """ Returns the obj instance this attribute is associated with, or None if no association has been set. """ return self.__obj obj = property(__get_obj) def _on_finalize(self): self.__obj = self.api.Object[self.obj_name] super(Attribute, self)._on_finalize() class Method(Attribute, Command): """ A command with an associated object. A `Method` plugin must have a corresponding `Object` plugin. The association between object and method is done through a simple naming convention: the first part of the method name (up to the first under score) is the object name, as the examples in this table show: ============= =========== ============== Method name Object name Attribute name ============= =========== ============== user_add user add noun_verb noun verb door_open_now door open_now ============= =========== ============== There are three different places a method can be accessed. For example, say you created a `Method` plugin and its corresponding `Object` plugin like this: >>> from ipalib import create_api >>> api = create_api() >>> class user_add(Method): ... def run(self, **options): ... return dict(result='Added the user!') ... >>> class user(Object): ... pass ... >>> api.register(user_add) >>> api.register(user) >>> api.finalize() First, the ``user_add`` plugin can be accessed through the ``api.Method`` namespace: >>> list(api.Method) ['user_add'] >>> api.Method.user_add() # Will call user_add.run() {'result': 'Added the user!'} Second, because `Method` is a subclass of `Command`, the ``user_add`` plugin can also be accessed through the ``api.Command`` namespace: >>> list(api.Command) ['user_add'] >>> api.Command.user_add() # Will call user_add.run() {'result': 'Added the user!'} And third, ``user_add`` can be accessed as an attribute on the ``user`` `Object`: >>> list(api.Object) ['user'] >>> list(api.Object.user.methods) ['add'] >>> api.Object.user.methods.add() # Will call user_add.run() {'result': 'Added the user!'} The `Attribute` base class implements the naming convention for the attribute-to-object association. Also see the `Object` and the `Property` classes. """ extra_options_first = False extra_args_first = False def __init__(self): super(Method, self).__init__() def get_output_params(self): for param in self.obj.params(): if 'no_output' in param.flags: continue yield param for param in self.params(): if param.name not in list(self.obj.params): if 'no_output' in param.flags: continue yield param for param in self._get_param_iterable('output_params', verb='has'): yield param class Property(Attribute): klass = Str default = None default_from = None normalizer = None def __init__(self): super(Property, self).__init__() # FIXME: This is a hack till Param.label is updated to require a # LazyText instance: self.label = None self.rules = tuple( sorted(self.__rules_iter(), key=lambda f: getattr(f, '__name__')) ) self.kwargs = tuple( sorted(self.__kw_iter(), key=lambda keyvalue: keyvalue[0]) ) kw = dict(self.kwargs) self.param = self.klass(self.attr_name, *self.rules, **kw) def __kw_iter(self): for (key, kind, default) in self.klass.kwargs: if getattr(self, key, None) is not None: yield (key, getattr(self, key)) def __rules_iter(self): """ Iterates through the attributes in this instance to retrieve the methods implementing validation rules. """ for name in dir(self.__class__): if name.startswith('_'): continue base_attr = getattr(self.__class__, name) if is_rule(base_attr): attr = getattr(self, name) if is_rule(attr): yield attr class Updater(Method): """ An LDAP update with an associated object (always update). All plugins that subclass from `Updater` will be automatically available as a server update function. Plugins that subclass from Updater are registered in the ``api.Updater`` namespace. For example: >>> from ipalib import create_api >>> api = create_api() >>> class my(Object): ... pass ... >>> api.register(my) >>> class my_update(Updater): ... pass ... >>> api.register(my_update) >>> api.finalize() >>> list(api.Updater) ['my_update'] >>> api.Updater.my_update # doctest:+ELLIPSIS ipalib.frontend.my_update() """ def __init__(self): super(Updater, self).__init__() def __call__(self, **options): self.debug( 'raw: %s', self.name ) return self.execute(**options) class _AdviceOutput(object): def __init__(self): self.content = [] self.prefix = '# ' self.options = None def comment(self, line, wrapped=True): if wrapped: for wrapped_line in wrap(line, 70): self.content.append(self.prefix + wrapped_line) else: self.content.append(self.prefix + line) def debug(self, line): if self.options.verbose: self.comment('DEBUG: ' + line) def command(self, line): self.content.append(line) class Advice(Plugin): """ Base class for advices, plugins for ipa-advise. """ options = None require_root = False description = '' def __init__(self): super(Advice, self).__init__() self.log = _AdviceOutput() def set_options(self, options): self.options = options self.log.options = options def get_info(self): """ This method should be overriden by child Advices. Returns a string with instructions. """ raise NotImplementedError freeipa-3.3.4/ipalib/messages.pyc0000664000175000017500000001270612271707517016305 0ustar mkosekmkosekó †fçRc@sdZddlmZddlmZddlmZddlmZm Z ddl m Z d„Z ddd„ZgZd „Zd efd „ƒYZd efd „ƒYZd„Zeeeeƒeƒdd„ƒƒZd„ZedkredeƒndS(s» Custom message (debug, info, wraning) classes passed through RPC. These are added to the "messages" entry in a RPC response, and printed to the user as log messages. Each message class has a unique numeric "errno" attribute from the 10000-10999 range, so that it does not clash with PublicError numbers. Messages also have the 'type' argument, set to one of 'debug', 'info', 'warning', 'error'. This determines the severity of themessage. iÿÿÿÿ(tisclass(t TYPE_ERROR(t_(tGettexttNGettext(tclient_has_capabilitycCs5t|dƒr1|jdgƒj|jƒƒndS(Ntmessages(Rt setdefaulttappendtto_dict(tversiontresulttmessage((s-/home/mkosek/freeipa-clean/ipalib/messages.pyt add_message)sc Ks||_|jj}|jdk rI|dk rItd||fƒ‚n|dkrD|jdkr|dkrƒtd|ƒ‚n||_nt|_|j||_t |jt ƒrÓt |jƒ||_ n|j||_ d|krºd„}dj ttdƒƒ||dƒfƒ}dj |j |fƒ|_ qºnvt |ttfƒrht|ƒ}n7t|ƒtk rŸttdt|t|ƒfƒ‚nt|_||_||_ xS|jƒD]E\}}t||ƒ sütd|||fƒ‚t|||ƒqÇWdS( Ns/non-generic %r needs format=None; got format=%rs/%s.format is None yet format=None, message=Nonet instructionscSs2t|tƒr.djtd„|ƒƒ}|S|S(Nu cSs t|ƒS(N(tunicode(tline((s-/home/mkosek/freeipa-clean/ipalib/messages.pytFs(t isinstancetlisttjointmap(tvalueR ((s-/home/mkosek/freeipa-clean/ipalib/messages.pytconvert_instructionsDsu sAdditional instructions:R sconflicting kwarg %s.%s = %r(tkwt __class__t__name__tformattNonet ValueErrortFalset forwardedtmsgRt basestringtugettexttstrerrorRRRRRttypet TypeErrorRtTruet iteritemsthasattrtAssertionErrortsetattr( tobjRR RtnameRRtkeyR((s-/home/mkosek/freeipa-clean/ipalib/messages.pytprocess_message_arguments.sD        !"   cCstj|ƒ|S(N(t_textsR(R ((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR_s t PublicMessagecBs2eZdZddd„ZdZdZd„ZRS(sU **10000** Base class for messages that can be forwarded in an RPC response. cKs0t||||tt|ƒj|jƒdS(N(R.tsuperR0t__init__R (tselfRR R((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR2hsi'c Cs=tdt|jƒdtt|ƒjƒd|jd|jƒS(s:Export this message to a dict that can be sent through RPCR$R,R tcode(tdictRR$RR#terrno(R3((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR os  N(Rt __module__t__doc__RR2R6RR (((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR0ds tVersionMissingcBs&eZdZdZdZedƒZRS(s **13001** Used when client did not send the API version. For example: >>> VersionMissing(server_version='2.123').strerror u"API Version number was not sent, forward compatibility not guaranteed. Assuming server's API version, 2.123" iÉ2twarningsxAPI Version number was not sent, forward compatibility not guaranteed. Assuming server's API version, %(server_version)s(RR7R8R6R$RR(((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR9ys ccsZxS|jƒD]E\}}|jdƒs t|ƒ r;q nt||ƒr |Vq q WdS(s'Return a tuple with all subclasses RN(titemst startswithRt issubclass(t variablestbaseR-R((s-/home/mkosek/freeipa-clean/ipalib/messages.pyt iter_messagesŠs R-cCs|jS(N(R6(tE((s-/home/mkosek/freeipa-clean/ipalib/messages.pyR•scCs?x#|D]}d|j|jfGHqWdt|ƒ|fGHdS(Ns%d %ss(%d %s)(R6Rtlen(tlabeltclassestcls((s-/home/mkosek/freeipa-clean/ipalib/messages.pyt print_report—s t__main__spublic messagesN(R8tinspectRtipalib.constantsRt ipalib.textRR"RRtipalib.capabilitiesRR RR.R/t UserWarningR0R9R@ttupletsortedtglobalstpublic_messagesRFR(((s-/home/mkosek/freeipa-clean/ipalib/messages.pyts" /  !  freeipa-3.3.4/ipalib/cli.pyc0000664000175000017500000012507412271707517015250 0ustar mkosekmkosekó †fçRc@s¼dZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z yddl Z Wne k r­nXddlZddlZddlZddlZddlmZmZmZmZmZmZmZmZmZmZddlmZddlm Z m!Z!m"Z"m#Z#m$Z$m%Z%ddl&m'Z'ddl(m)Z)d„Z*d „Z+d ej,fd „ƒYZ-d ej.fd „ƒYZ/dej0fd„ƒYZ1dej0fd„ƒYZ2dej0fd„ƒYZ3e/e2e3fZ4de5fd„ƒYZ6dej7fd„ƒYZ8dej9fd„ƒYZ:dej;fd„ƒYZ<dej7fd„ƒYZ=e<e-e2e/e1fZ>d„Z?dS(s+ Functionality for Command Line Interface. iÿÿÿÿN( t PublicErrort CommandErrort HelpErrort InternalErrortNoSuchNamespaceErrortValidationErrortNotFoundtNotConfiguredErrort PromptFailedtConversionError(tCLI_TAB(tPasswordtBytestFiletStrtStrEnumtAny(t_(t API_VERSIONcCs%t|tƒst‚|jddƒS(sl Takes a Python identifier and transforms it into form suitable for the Command Line Interface. Rt-(t isinstancetstrtAssertionErrortreplace(tname((s(/home/mkosek/freeipa-clean/ipalib/cli.pytto_cli:scCst|ƒjddƒS(sh Takes a string from the Command Line Interface and transforms it into a Python identifier. RR(RR(tcli_name((s(/home/mkosek/freeipa-clean/ipalib/cli.pytfrom_cliCsttextuicBsŽeZdZd„Zd$d„Zd„Zd„Zd„Zd$d„Z d„Z d„Z d$d „Z d$d „Z d d „Zd d „Zdd ed„Zd idged„Zd$d$d$edd d„Zd$d$d$edd d„Zeeddd„Zd„Zd„Zd„Zd„Zd„Zd$d„Zd„Zed„Zd„Zd$d$e d „Z!d$d!„Z"ed"„Z#ed#„Z$RS(%s; Backend plugin to nicely format output to stdout. c CsstjjƒroyHtjtjtjtjdddddƒƒ}tj d|ƒdSWqot k rkdSXndS(s„ Return the width (in characters) of output tty. If stdout is not a tty, this method will return ``None``. tHHHHiiN( tsyststdouttisattytfcntltioctlttermiost TIOCGWINSZtstructtpacktunpacktIOErrortNone(tselftwinsize((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt get_tty_widthPs cs„t|ƒttfkr4tdtt|fƒ‚nt|ƒdkrJdSˆdkrjtd„|DƒƒSt‡fd†|DƒƒS(s¸ Return the max width (in characters) of a specified column. For example: >>> ui = textui() >>> rows = [ ... ('a', 'package'), ... ('an', 'egg'), ... ] >>> ui.max_col_width(rows, col=0) # len('an') 2 >>> ui.max_col_width(rows, col=1) # len('package') 7 >>> ui.max_col_width(['a', 'cherry', 'py']) # len('cherry') 6 srows: need %r or %r; got %ricss|]}t|ƒVqdS(N(tlen(t.0trow((s(/home/mkosek/freeipa-clean/ipalib/cli.pys ysc3s|]}t|ˆƒVqdS(N(R-(R.R/(tcol(s(/home/mkosek/freeipa-clean/ipalib/cli.pys zsN(ttypetlistttuplet TypeErrorR-R)tmax(R*trowsR0((R0s(/home/mkosek/freeipa-clean/ipalib/cli.pyt max_col_width`s cCsA|tjtjfkst‚t|ddƒdkr:dS|jS(NtencodingsUTF-8(RtstdinRRtgetattrR)R8(R*tstream((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt__get_encoding|scsgt|ƒtkr1ˆjtjƒ}|j|ƒSt|ƒttfkrct‡fd†|DƒƒS|S(s) Decode text from stdin. c3s|]}ˆj|ƒVqdS(N(tdecode(R.tv(R*(s(/home/mkosek/freeipa-clean/ipalib/cli.pys Šs(R1Rt_textui__get_encodingRR9R=R2R3(R*tvalueR8((R*s(/home/mkosek/freeipa-clean/ipalib/cli.pyR=‚s  cCs7t|ƒtkst‚|jtjƒ}|j|ƒS(s3 Encode text for output to stdout. (R1tunicodeRR?RRtencode(R*t unicode_textR8((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRBscCs(|dks|dkr ||S||S(Ni(R)(R*tntsingulartplural((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt choose_number•scCs't|ƒtkrtj|ƒS|SdS(s‘ Convert a binary value to base64. We know a value is binary if it is a python str type, otherwise it is a plain string. N(R1Rtbase64t b64encode(R*R@((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt encode_binaryšs cCst|ƒGHdS(s? Print exactly like ``print`` statement would. N(RA(R*tstring((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_plain¤scCs]|dkr|jƒ}n|dk rN|t|ƒkrN||d d}nt|ƒGHdS(sä Force printing on a single line, using ellipsis if needed. For example: >>> ui = textui() >>> ui.print_line('This line can fit!', width=18) This line can fit! >>> ui.print_line('This line wont quite fit!', width=18) This line wont ... The above example aside, you normally should not specify the ``width``. When you don't, it is automatically determined by calling `textui.get_tty_width()`. is...N(R)R,R-RA(R*ttexttwidth((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_lineªs  cCsG|dkr|jƒ}nx%tj|jƒ|ƒD] }|GHq4WdS(s( Print a paragraph, automatically word-wrapping to tty width. For example: >>> text = ''' ... Python is a dynamic object-oriented programming language that can ... be used for many kinds of software development. ... ''' >>> ui = textui() >>> ui.print_paragraph(text, width=45) Python is a dynamic object-oriented programming language that can be used for many kinds of software development. The above example aside, you normally should not specify the ``width``. When you don't, it is automatically determined by calling `textui.get_tty_width()`. The word-wrapping is done using the Python ``textwrap`` module. See: http://docs.python.org/library/textwrap.html N(R)R,ttextwraptwraptstrip(R*RMRNtline((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_paragraphÀs icCst||GHdS(s{ Print at specified indentation level. For example: >>> ui = textui() >>> ui.print_indented('One indentation level.') One indentation level. >>> ui.print_indented('Two indentation levels.', indent=2) Two indentation levels. >>> ui.print_indented('No indentation.', indent=0) No indentation. N(R (R*RMtindent((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_indentedÝscCs>x7|D]/\}}|jd||j|ƒf|ƒqWdS(sÍ Print (key = value) pairs, one pair per line. For example: >>> items = [ ... ('in_server', True), ... ('mode', u'production'), ... ] >>> ui = textui() >>> ui.print_keyval(items) in_server = True mode = u'production' >>> ui.print_keyval(items, indent=0) in_server = True mode = u'production' Also see `textui.print_indented`. s%s = %rN(RVRJ(R*R6RUtkeyR@((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_keyvalíss%s: %sc s&t|tƒst‚t|ttfƒsPˆj||ˆj|ƒf|ƒnÒ|rxÉ|D])}ˆj||ˆj|ƒf|ƒq]Wn•t‡fd†|ƒ}t|ƒdkrt |dƒttfkrx@|D]8}dj |ƒ}ˆj||ˆj|ƒf|ƒqÚWdSt|ƒdkrHdj d„|Dƒƒ}ndSˆj ƒ} | rÏ|rÏdt |dt|ƒd f} | t| ƒ8} t j|| d tƒ}t|ƒdkrØd g}qØn |g}ˆj|||df|ƒx)|d D]} ˆjd| | fƒqWdS( så Print an ldap attribute. For example: >>> attr = 'dn' >>> ui = textui() >>> ui.print_attribute(attr, u'dc=example,dc=com') dn: dc=example,dc=com >>> attr = 'objectClass' >>> ui.print_attribute(attr, [u'top', u'someClass'], one_value_per_line=False) objectClass: top, someClass >>> ui.print_attribute(attr, [u'top', u'someClass']) objectClass: top objectClass: someClass cs ˆj|ƒS(N(RJ(R>(R*(s(/home/mkosek/freeipa-clean/ipalib/cli.pytsis: Ns, css|]}t|ƒVqdS(N(R(R.R>((s(/home/mkosek/freeipa-clean/ipalib/cli.pys (ss%s%st itbreak_long_wordsui(Rt basestringRR2R3RVRJtmapR-R1tjoinR,R RPRQtFalseRL( R*tattrR@tformatRUtone_value_per_lineR>tlRMtline_lents_indentRS((R*s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_attributes8& *. '   tdncs¹tˆtƒst‚tˆtƒs*t‚t|ttfƒsEt‚‡‡‡‡‡‡fd†}x.|D]&‰ˆˆkrj|ˆƒˆˆ=qjqjWxtˆƒD]‰|ˆƒq¡WdS(s+ Print an ldap entry dict. csWˆˆkr3ˆjˆˆˆˆdˆdˆƒn ˆjˆˆˆdˆdˆƒdS(NRURb(Rf(ta(R`tattr_maptentryRURbR*(s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_attrEs  !N(RtdictRR2R3tsorted(R*RjRURit attr_orderRbRk((R`RiRjRURbR*s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_entry1<s   c Csit|ttfƒst‚t}xA|D]9} |s<dGHnt}|j| ||||||ƒq(WdS(Nt(RR2R3RtTrueR_t print_entry( R*tentriestordertlabelstflagst print_allRaRUtfirstRj((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_entriesVs c Cs.t|ttfƒr$t|ƒ}nt|tƒs9t‚|dkrWtƒ}t}nt}|dk rÛxo|D]d} | |krˆqpn|j| | ƒ} |j| gƒ} || } d| krà| ddgdgkràqpnt| tƒrMt j | ƒdkr qpn|j || df|ƒ|j | |||||d|dƒn€t| ttfƒr´t d„| Dƒƒr´|j| d||ƒ|j| ||||||dƒn|j| | |||ƒ|| =qpWn|r*xFt|ƒD]5} |j| | ƒ} |j| || |||ƒqîWndS( s tsuppress_emptyuRpiRUicss|]}t|tƒVqdS(N(RRl(R.tval((s(/home/mkosek/freeipa-clean/ipalib/cli.pys }sN(RR2R3RlRR)RqR_tgettfrontendt entry_countRVRrtallRfRyRm( R*RjRtRuRvRwRaRURbRWtlabeltflagR@((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRr_sH       $iRcCsƒt|tƒst‚t|ƒdks-t‚|t|ƒ}|rV|j||ƒn|j||ƒ|r|j||ƒndS(sù Print a string with a dashed line above and/or below. For example: >>> ui = textui() >>> ui.print_dashed('Dashed above and below.') ----------------------- Dashed above and below. ----------------------- >>> ui.print_dashed('Only dashed below.', above=False) Only dashed below. ------------------ >>> ui.print_dashed('Only dashed above.', below=False) ------------------ Only dashed above. iN(RR\RR-RV(R*RKtabovetbelowRUtdashtdashes((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_dashedŽscCs|j|ddddƒdS(sè Print a primary header at indentation level 0. For example: >>> ui = textui() >>> ui.print_h1('A primary header') ================ A primary header ================ RUiR„t=N(R†(R*RM((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_h1©s cCs|j|ddddƒdS(sø Print a secondary header at indentation level 1. For example: >>> ui = textui() >>> ui.print_h2('A secondary header') ------------------ A secondary header ------------------ RUiR„RN(R†(R*RM((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_h2·s cCs|jdt|ƒƒdS(sb Print a command name. The typical use for this is to mark the start of output from a command. For example, a hypothetical ``show_status`` command would output something like this: >>> ui = textui() >>> ui.print_name('show_status') ------------ show-status: ------------ s%s:N(R†R(R*R((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_nameÅscCs|j||ƒdS(N(R†(R*tmsgtoutput((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_headerÕscCs|j|ƒdS(só Print a summary at the end of a comand's output. For example: >>> ui = textui() >>> ui.print_summary('Added user "jdoe"') ----------------- Added user "jdoe" ----------------- N(R†(R*R‹((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_summaryØs cCsbt|ƒtk rBt|ƒtttfks3t‚t|ƒ}n|j|j|||ƒƒdS(sÄ Print a summary count. The typical use for this is to print the number of items returned by a command, especially when this return count can vary. This preferably should be used as a summary and should be the final text a command outputs. For example: >>> ui = textui() >>> ui.print_count(1, '%d goose', '%d geese') ------- 1 goose ------- >>> ui.print_count(['Don', 'Sue'], 'Found %d user', 'Found %d users') ------------- Found 2 users ------------- If ``count`` is not an integer, it must be a list or tuple, and then ``len(count)`` is used as the count. N( R1tintR2R3RlRR-R†RG(R*tcountRERF((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_countæs !cCsdt|ƒGHdS(Ns ** %s **(RA(R*RM((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt print_errorscCsNy |j||j|ƒƒƒSWn'ttfk rIHtd|ƒ‚nXdS(s“Prompt user for input Handles encoding the prompt and decoding the input. On end of stream or ctrl+c, raise PromptFailed. RN(R=RBtKeyboardInterrupttEOFErrorR(R*tpromptR€t prompt_func((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt prompt_helpers  cCs|jd||fƒdS(Ns >>> %s: %s(RL(R*t attributeterror((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprint_prompt_attribute_errorscCsV|rd|}n d|}|dkr6d|}nd||f}|j||ƒS(s( Prompt user for input. u[%s]u%su%s: u %s [%s]: N(R)R—(R*R€tdefaultt get_valuestoptionalR•((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR•s    cCs²d }|d k r*|r!d}q*d}n|rCd||f}n d|}x^tr­|j||ƒjƒ}|d kr~tS|d krŽtS|d k rP|d krP|SqPWd S( sÖ Prompt user for yes/no input. This method returns True/False according to user response. Parameter "default" should be True, False or None If Default parameter is not None, user can enter an empty input instead of Yes/No answer. Value passed to Default is returned in that case. If Default parameter is None, user is asked for Yes/No answer until a correct answer is provided. Answer is then returned. tYestNou%s Yes/No (default %s): u %s Yes/No: uyesuyununouN(uyesuy(ununo(R)RqR—tlowerR_(R*R€R›tdefault_promptR•tdata((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt prompt_yesno&s        cCsÑtjjƒr±dt|ƒ}ttdƒtd|ƒƒ}xŒtr­|j||dtjƒ}|sl|S|j||dtjƒ}||kr—|S|j tdƒƒqAWn|j tjj ƒj ƒƒSdS(sx Prompt user for a password or read it in via stdin depending on whether there is a tty or not. u%s: s!Enter %(label)s again to verify: R€R–sPasswords do not match!N( RR9R RARRlRqR—tgetpassR’R=treadlineRR(R*R€tconfirmR•t repeat_prompttpw1tpw2((s(/home/mkosek/freeipa-clean/ipalib/cli.pytprompt_passwordJs  c Cs—|jj stjjƒ r!dSt|ƒ}|dkrQtdtdƒƒ‚nd}x`|D]X}i}x$|D]} |j| dƒ|| ñs(RÈt _builtinstCommandtNO_CLIRÇRÂR)tappendt_PLUGIN_BASE_MODULERARRRÄRºRRRÁR5R-RtrsplitRÌtkeyst_mtltsuperR¼t _on_finalize(R*tcR½RÉtmR¾RËRÊ((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR×ÀsB    (&+#!.9<c Ks´|dkrtj}n|j|ƒ}t|ƒ}d|j|f}|dkri|jjj|ƒdS|dkr†|j |ƒdS||j kr¨|j ||ƒn||j krþ|j |}|j rßtd|ƒ‚n|jjj|ƒj|ƒn²|tjkr |j ||ƒn|dkr¡td„|j Dƒƒ}xh|j D]K} |j | }|j rqqOn|dt|jƒj|ƒ|jfƒqOWntd|ƒ‚dS(Ns%s.%sttopicsR½tcommandscss|]}t|ƒVqdS(N(R-(R.RÍ((s(/home/mkosek/freeipa-clean/ipalib/cli.pys ss%s %s(R)RRt_writerRRÒtapitparsert print_helpt print_topicsRÈtprint_commandsRÏRÐRtBackendtclit build_parserRÄR5RRtljusttsummary( R*RWtoutfiletoptionstwriterRRÊtcmdRËtcname((s(/home/mkosek/freeipa-clean/ipalib/cli.pytrunös8           0csd‡fd†}|S(NRpcsˆt|ƒIJdS(N(RA(RK(Rç(s(/home/mkosek/freeipa-clean/ipalib/cli.pyRés((R*RçRé((Rçs(/home/mkosek/freeipa-clean/ipalib/cli.pyRÜscCsc|j|ƒ}xMt|jjƒƒD]6\}}|dt|ƒj|jƒ|dfƒq%WdS(Ns%s %si(RÜRmRÈtitemsRRåRÕ(R*RçRéttR½((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRàs"c Csl|j|ƒ}||jkr§t|j|dƒtkr§x*|j|dD]S}|j|d|d}|j|d}|dt|ƒj|ƒ|fƒqMWnÁ||jkrÛ|j|d}|j|d}ng}x„|jD]y}t|j|dƒtk rqën||j|dkr1qën|j|d|d}|j|d|d}PqëWd|j|f} ttt j | j ƒƒpšdj ƒ}||j krÖt|ƒdkrÖtd|ƒ‚n||ƒ|ra|ƒ|tdƒƒx7|D]/} |dt| jƒj|ƒ| jfƒqW|ƒ|td ƒƒ|td ƒƒn|ƒdS( Niiis %s %ss%s.%sRpR½sTopic commands:sTo get command help, use:s ipa --help(RÜRÈR1RlRRåRÒRARRRÄRºRRRÏR-RRRæ( R*R½RçRétsubtopicR¾RËRÛRîRÙRØ((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRá sB,*(!  *N(R¸R¹RºRRt takes_argsRt takes_optionsR3t has_outputRÒRÃRÇRÌR×R)RìRÜRàRá(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR¼–s   6   t show_mappingscBs;eZdZeddedƒƒfZeƒZd„ZRS(sA Show mapping of LDAP attributes to command-line option. t command_nameR€s Command namecKsùt|ƒ}||jkr-td|ƒ‚n|j|j}d d g}t|ddƒ}x`|ƒD]U}|jr‹d|jkr‹qgn|j|j|jfƒt |t|jƒƒ}qgWx2|D]*}t |dƒj |ƒd|d GHqÇWdS( NRt ParametersLDAP attributes =========s==============itwebuis : i(RõsLDAP attribute(s =========s==============( RRÏRRèR-texcludeRÑRt param_specR5RRå(R*RôRètparamstoutRËtparamtitem((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRìUs   ( R¸R¹RºRRRðR3RòRì(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRóJs   tconsolecBs eZdZeƒZd„ZRS(s)Start the IPA interactive Python console.cKs#tjddtd|jƒƒdS(Ns'(Custom IPA interactive Python console)tlocalRÝ(tcodetinteractRlRÝ(R*Rè((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRìks(R¸R¹RºR3RòRì(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRýfs tshow_apicBs2eZdZdZd„Zd„Zdd„ZRS(s%Show attributes on dynamic API objects namespaces*c Cs@|dkrt|jƒ}n8x/|D]'}||jkr%td|ƒ‚q%q%W|}|j|ƒ}td„|Dƒƒ}|jjjdƒt }xg|D]_}|ddkrÀ| rÀdGHn|rÏt }ndd|d|dj |ƒ|d fGHq›Wt |ƒdkrd }nd t |ƒ}|jjj |ƒdS( NRcss|]}t|dƒVqdS(iN(R-(R.Rc((s(/home/mkosek/freeipa-clean/ipalib/cli.pys €sRìiRps%s%s %rRZiis1 attribute shown.s%d attributes show.(R)R3RÝRt_show_api__traverseR5RâRRŠRqR_RåR-R†( R*t namespacestnamesRtlinestmlRxRSRÍ((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRìws.      cCs?g}x2|D]*}|j|}|jd|||ƒq W|S(Ns%s(RÝt_show_api__traverse_namespace(R*RRRt namespace((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt __traverse“s   ic CsÀ|j|||fƒx£|D]›}||}|j|d||fƒt|dƒs\qnxY|D]Q}||}t|tjƒrct|ƒdkrc|j||||dƒqcqcWqWdS(Nit__iter__ii(RÑthasattrRtplugablet NameSpaceR-R( R*RRRttabt member_nametmemberRDR`((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt__traverse_namespacešs    $(s namespaces*(R¸R¹RºRðRìRR(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRrs   t CollectorcBs#eZd„Zd„Zd„ZRS(cCstj|diƒdS(Nt_Collector__options(tobjectt __setattr__(R*((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt__init__¯scCsq||jkrM|j|}t|ƒtkr>||f}qM||f}n||j|((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR²s  cCs t|jƒS(N(RlR(R*((s(/home/mkosek/freeipa-clean/ipalib/cli.pyt __todict__¼s(R¸R¹RRR(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR®s  tCLIOptionParserFormattercBseZd„ZRS(cCsg}|j|jd}t|ƒ|krNd|jd|f}|j}nd|jd||f}d}|j|ƒ|rêtj||jƒ}|jd|d|dfƒ|jg|dD]}d|jd|f^qăn |ddkr |jdƒndj|ƒS( Nis%*s%s Rps %*s%-*s iiiÿÿÿÿs ( t help_positiontcurrent_indentR-RÑRPRQt help_widthtextendR^(R*Rt help_stringtresultt opt_widtht indent_firstt help_linesRS((s(/home/mkosek/freeipa-clean/ipalib/cli.pytformat_argumentÀs    .(R¸R¹R"(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR¿stCLIOptionParsercBs,eZdZd„Zdd„Zd„ZRS(sÍ This OptionParser subclass adds an ability to print positional arguments in CLI help. Custom formatter is used to format the argument list in the same way as OptionParser formats options. cOs?g|_d|kr%tƒ|dtexecutetcallabletoutput_for_cliRùtpasswordtparams_2_args_optionsRÝRâRtdestroy_context( R*R3RêRR;RRûR(Rètrv((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRì!s(   ! cCs^|j|ƒ}|j|tƒƒ\}}|jƒ}|j||Ž}t|j||ƒƒS(N(Rät parse_argsRRtargs_options_2_paramsRlt parse_iter(R*RêR3RÞt collectorR(RèR;((s(/home/mkosek/freeipa-clean/ipalib/cli.pyR?9s  ccs;x4|jƒD]&\}}||jjj|ƒfVq WdS(s5 Decode param values if appropriate. N(t iteritemsRâRR=(R*RêR;RWR@((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRKBsc Csxtddj|j|ƒƒdt|jƒdtƒƒ}i}xÆ|jƒD]¸}td|jdt|jƒƒ}d|j krˆqLn|j rª|j j rªd|d RìR?RKRäRqRdRWR7R:(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRã÷s     4  ,RXcBseZdZd„ZRS(s1Formatter suitable for printing IPA command help The default help formatter reflows text to fit the terminal, but it ignores line/paragraph breaks. IPA's descriptions already have correct line breaks. This formatter doesn't touch them (save for removing initial/trailing whitespace). cCs|r|jƒSdSdS(NRp(RR(R*RO((s(/home/mkosek/freeipa-clean/ipalib/cli.pytformat_descriptionós (R¸R¹RºRz(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRXëscCsTd}y…|jddƒ\}}xtD]}|j|ƒq(W|jƒ|jƒd|jkrntƒ‚ntj |j j j |ƒƒWn{t k r³dGH|jjdƒnVtk rË}|}n>tk r}|jjd|jjt|ƒƒtƒ}nX|dk rPt|tƒs*t‚|jj|jƒtj |jƒndS(NtcontextRãt config_loadedRpsoperation aborteds%s: %s(R)tbootstrap_with_global_optionst cli_pluginstregistert load_pluginstfinalizeR­RRR2RâRãRìR“tlogtinfoRt StandardErrort exceptionR\R¸RRRRR™tstrerrortrval(RÝR™RèR3tklassR³((s(/home/mkosek/freeipa-clean/ipalib/cli.pyRìs,       "  (@RºtreRPRR¤RÿR&tsocketR!R#R%RHtdefault_encoding_utf8t ImportErrorR}tbackendR tutilterrorsRRRRRRRRRR t constantsR t parametersR R R RRRRMRtipapython.versionRRRRâRR@R¼RÏRóRýRtcli_application_commandsRRtIndentedHelpFormatterRR'R#t ExecutionerRãRXR~Rì(((s(/home/mkosek/freeipa-clean/ipalib/cli.pyts^                F. ÿÿM´ 6 $ô freeipa-3.3.4/ipalib/krb_utils.py0000664000175000017500000003202612271663206016322 0ustar mkosekmkosek# Authors: John Dennis # # 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 . import krbV import time import re from ipapython.ipa_log_manager import * #------------------------------------------------------------------------------- # Kerberos constants, should be defined in krbV, but aren't KRB5_GC_CACHED = 0x2 # Kerberos error codes, should be defined in krbV, but aren't KRB5_CC_NOTFOUND = -1765328243 # Matching credential not found KRB5_FCC_NOFILE = -1765328189 # No credentials cache found KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN = -1765328377 # Server not found in Kerberos database KRB5KRB_AP_ERR_TKT_EXPIRED = -1765328352 # Ticket expired KRB5_FCC_PERM = -1765328190 # Credentials cache permissions incorrect KRB5_CC_FORMAT = -1765328185 # Bad format in credentials cache KRB5_REALM_CANT_RESOLVE = -1765328164 # Cannot resolve network address for KDC in requested realm krb_ticket_expiration_threshold = 60*5 # number of seconds to accmodate clock skew krb5_time_fmt = '%m/%d/%y %H:%M:%S' ccache_name_re = re.compile(r'^((\w+):)?(.+)') #------------------------------------------------------------------------------- def krb5_parse_ccache(ccache_name): ''' Given a Kerberos ccache name parse it into it's scheme and location components. Currently valid values for the scheme are: * FILE * MEMORY The scheme is always returned as upper case. If the scheme does not exist it defaults to FILE. :parameters: ccache_name The name of the Kerberos ccache. :returns: A two-tuple of (scheme, ccache) ''' match = ccache_name_re.search(ccache_name) if match: scheme = match.group(2) location = match.group(3) if scheme is None: scheme = 'FILE' else: scheme = scheme.upper() return scheme, location else: raise ValueError('Invalid ccache name = "%s"' % ccache_name) def krb5_unparse_ccache(scheme, name): return '%s:%s' % (scheme.upper(), name) def krb5_format_principal_name(user, realm): ''' Given a Kerberos user principal name and a Kerberos realm return the Kerberos V5 user principal name. :parameters: user User principal name. realm The Kerberos realm the user exists in. :returns: Kerberos V5 user principal name. ''' return '%s@%s' % (user, realm) def krb5_format_service_principal_name(service, host, realm): ''' Given a Kerberos service principal name, the host where the service is running and a Kerberos realm return the Kerberos V5 service principal name. :parameters: service Service principal name. host The DNS name of the host where the service is located. realm The Kerberos realm the service exists in. :returns: Kerberos V5 service principal name. ''' return '%s/%s@%s' % (service, host, realm) def krb5_format_tgt_principal_name(realm): ''' Given a Kerberos realm return the Kerberos V5 TGT name. :parameters: realm The Kerberos realm the TGT exists in. :returns: Kerberos V5 TGT name. ''' return krb5_format_service_principal_name('krbtgt', realm, realm) def krb5_format_time(timestamp): ''' Given a UNIX timestamp format it into a string in the same manner the MIT Kerberos library does. Kerberos timestamps are always in local time. :parameters: timestamp Unix timestamp :returns: formated string ''' return time.strftime(krb5_time_fmt, time.localtime(timestamp)) class KRB5_CCache(object): ''' Kerberos stores a TGT (Ticket Granting Ticket) and the service tickets bound to it in a ccache (credentials cache). ccaches are bound to a Kerberos user principal. This class opens a Kerberos ccache and allows one to manipulate it. Most useful is the extraction of ticket entries (cred's) in the ccache and the ability to examine their attributes. ''' def __init__(self, ccache): ''' :parameters: ccache The name of a Kerberos ccache used to hold Kerberos tickets. :returns: `KRB5_CCache` object encapsulting the ccache. ''' log_mgr.get_logger(self, True) self.context = None self.scheme = None self.name = None self.ccache = None self.principal = None try: self.context = krbV.default_context() self.scheme, self.name = krb5_parse_ccache(ccache) self.ccache = krbV.CCache(name=str(ccache), context=self.context) self.principal = self.ccache.principal() except krbV.Krb5Error, e: error_code = e.args[0] message = e.args[1] if error_code == KRB5_FCC_NOFILE: raise ValueError('"%s", ccache="%s"' % (message, ccache)) else: raise e def ccache_str(self): ''' A Kerberos ccache is identified by a name comprised of a scheme and location component. This function returns that canonical name. See `krb5_parse_ccache()` :returns: The name of ccache with it's scheme and location components. ''' return '%s:%s' % (self.scheme, self.name) def __str__(self): return 'cache="%s" principal="%s"' % (self.ccache_str(), self.principal.name) def get_credentials(self, principal): ''' Given a Kerberos principal return the krbV credentials tuple describing the credential. If the principal does not exist in the ccache a KeyError is raised. :parameters: principal The Kerberos principal whose ticket is being retrieved. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: A krbV credentials tuple. If the principal is not in the ccache a KeyError is raised. ''' if isinstance(principal, krbV.Principal): krbV_principal = principal else: try: krbV_principal = krbV.Principal(str(principal), self.context) except Exception, e: self.error('could not create krbV principal from "%s", %s', principal, e) raise e creds_tuple = (self.principal, krbV_principal, (0, None), # keyblock: (enctype, contents) (0, 0, 0, 0), # times: (authtime, starttime, endtime, renew_till) 0,0, # is_skey, ticket_flags None, # addrlist None, # ticket_data None, # second_ticket_data None) # adlist try: cred = self.ccache.get_credentials(creds_tuple, KRB5_GC_CACHED) except krbV.Krb5Error, e: error_code = e.args[0] if error_code == KRB5_CC_NOTFOUND: raise KeyError('"%s" credential not found in "%s" ccache' % \ (krbV_principal.name, self.ccache_str())) raise e except Exception, e: raise e return cred def get_credential_times(self, principal): ''' Given a Kerberos principal return the ticket timestamps if the principal's ticket in the ccache is valid. If the principal does not exist in the ccache a KeyError is raised. The return credential time values are Unix timestamps in localtime. The returned timestamps are: authtime The time when the ticket was issued. starttime The time when the ticket becomes valid. endtime The time when the ticket expires. renew_till The time when the ticket becomes no longer renewable (if renewable). :parameters: principal The Kerberos principal whose ticket is being validated. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: return authtime, starttime, endtime, renew_till ''' if isinstance(principal, krbV.Principal): krbV_principal = principal else: try: krbV_principal = krbV.Principal(str(principal), self.context) except Exception, e: self.error('could not create krbV principal from "%s", %s', principal, e) raise e try: cred = self.get_credentials(krbV_principal) authtime, starttime, endtime, renew_till = cred[3] self.debug('get_credential_times: principal=%s, authtime=%s, starttime=%s, endtime=%s, renew_till=%s', krbV_principal.name, krb5_format_time(authtime), krb5_format_time(starttime), krb5_format_time(endtime), krb5_format_time(renew_till)) return authtime, starttime, endtime, renew_till except KeyError, e: raise e except Exception, e: self.error('get_credential_times failed, principal="%s" error="%s"', krbV_principal.name, e) raise e def credential_is_valid(self, principal): ''' Given a Kerberos principal return a boolean indicating if the principal's ticket in the ccache is valid. If the ticket is not in the ccache False is returned. If the ticket exists in the ccache it's validity is checked and returned. :parameters: principal The Kerberos principal whose ticket is being validated. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: True if the principal's ticket exists and is valid. False if the ticket does not exist or if the ticket is not valid. ''' try: authtime, starttime, endtime, renew_till = self.get_credential_times(principal) except KeyError, e: return False except Exception, e: self.error('credential_is_valid failed, principal="%s" error="%s"', principal, e) raise e now = time.time() if starttime > now: return False if endtime < now: return False return True def valid(self, host, realm): ''' Test to see if ldap service ticket or the TGT is valid. :parameters: host ldap server realm kerberos realm :returns: True if either the ldap service ticket or the TGT is valid, False otherwise. ''' try: principal = krb5_format_service_principal_name('HTTP', host, realm) valid = self.credential_is_valid(principal) if valid: return True except KeyError: pass try: principal = krb5_format_tgt_principal_name(realm) valid = self.credential_is_valid(principal) return valid except KeyError: return False def endtime(self, host, realm): ''' Returns the minimum endtime for tickets of interest (ldap service or TGT). :parameters: host ldap server realm kerberos realm :returns: UNIX timestamp value. ''' result = 0 try: principal = krb5_format_service_principal_name('HTTP', host, realm) authtime, starttime, endtime, renew_till = self.get_credential_times(principal) if result: result = min(result, endtime) else: result = endtime except KeyError: pass try: principal = krb5_format_tgt_principal_name(realm) authtime, starttime, endtime, renew_till = self.get_credential_times(principal) if result: result = min(result, endtime) else: result = endtime except KeyError: pass self.debug('KRB5_CCache %s endtime=%s (%s)', self.ccache_str(), result, krb5_format_time(result)) return result freeipa-3.3.4/ipalib/base.py0000664000175000017500000003646512202434255015243 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Foundational classes and functions. """ import re from constants import NAME_REGEX, NAME_ERROR from constants import TYPE_ERROR, SET_ERROR, DEL_ERROR, OVERRIDE_ERROR class ReadOnly(object): """ Base class for classes that can be locked into a read-only state. Be forewarned that Python does not offer true read-only attributes for user-defined classes. Do *not* rely upon the read-only-ness of this class for security purposes! The point of this class is not to make it impossible to set or to delete attributes after an instance is locked, but to make it impossible to do so *accidentally*. Rather than constantly reminding our programmers of things like, for example, "Don't set any attributes on this ``FooBar`` instance because doing so wont be thread-safe", this class offers a real way to enforce read-only attribute usage. For example, before a `ReadOnly` instance is locked, you can set and delete its attributes as normal: >>> class Person(ReadOnly): ... pass ... >>> p = Person() >>> p.name = 'John Doe' >>> p.phone = '123-456-7890' >>> del p.phone But after an instance is locked, you cannot set its attributes: >>> p.__islocked__() # Is this instance locked? False >>> p.__lock__() # This will lock the instance >>> p.__islocked__() True >>> p.department = 'Engineering' Traceback (most recent call last): ... AttributeError: locked: cannot set Person.department to 'Engineering' Nor can you deleted its attributes: >>> del p.name Traceback (most recent call last): ... AttributeError: locked: cannot delete Person.name However, as noted at the start, there are still obscure ways in which attributes can be set or deleted on a locked `ReadOnly` instance. For example: >>> object.__setattr__(p, 'department', 'Engineering') >>> p.department 'Engineering' >>> object.__delattr__(p, 'name') >>> hasattr(p, 'name') False But again, the point is that a programmer would never employ the above techniques *accidentally*. Lastly, this example aside, you should use the `lock()` function rather than the `ReadOnly.__lock__()` method. And likewise, you should use the `islocked()` function rather than the `ReadOnly.__islocked__()` method. For example: >>> readonly = ReadOnly() >>> islocked(readonly) False >>> lock(readonly) is readonly # lock() returns the instance True >>> islocked(readonly) True """ __locked = False def __lock__(self): """ Put this instance into a read-only state. After the instance has been locked, attempting to set or delete an attribute will raise an AttributeError. """ assert self.__locked is False, '__lock__() can only be called once' self.__locked = True def __islocked__(self): """ Return True if instance is locked, otherwise False. """ return self.__locked def __setattr__(self, name, value): """ If unlocked, set attribute named ``name`` to ``value``. If this instance is locked, an AttributeError will be raised. :param name: Name of attribute to set. :param value: Value to assign to attribute. """ if self.__locked: raise AttributeError( SET_ERROR % (self.__class__.__name__, name, value) ) return object.__setattr__(self, name, value) def __delattr__(self, name): """ If unlocked, delete attribute named ``name``. If this instance is locked, an AttributeError will be raised. :param name: Name of attribute to delete. """ if self.__locked: raise AttributeError( DEL_ERROR % (self.__class__.__name__, name) ) return object.__delattr__(self, name) def lock(instance): """ Lock an instance of the `ReadOnly` class or similar. This function can be used to lock instances of any class that implements the same locking API as the `ReadOnly` class. For example, this function can lock instances of the `config.Env` class. So that this function can be easily used within an assignment, ``instance`` is returned after it is locked. For example: >>> readonly = ReadOnly() >>> readonly is lock(readonly) True >>> readonly.attr = 'This wont work' Traceback (most recent call last): ... AttributeError: locked: cannot set ReadOnly.attr to 'This wont work' Also see the `islocked()` function. :param instance: The instance of `ReadOnly` (or similar) to lock. """ assert instance.__islocked__() is False, 'already locked: %r' % instance instance.__lock__() assert instance.__islocked__() is True, 'failed to lock: %r' % instance return instance def islocked(instance): """ Return ``True`` if ``instance`` is locked. This function can be used on an instance of the `ReadOnly` class or an instance of any other class implemented the same locking API. For example: >>> readonly = ReadOnly() >>> islocked(readonly) False >>> readonly.__lock__() >>> islocked(readonly) True Also see the `lock()` function. :param instance: The instance of `ReadOnly` (or similar) to interrogate. """ assert ( hasattr(instance, '__lock__') and callable(instance.__lock__) ), 'no __lock__() method: %r' % instance return instance.__islocked__() def check_name(name): """ Verify that ``name`` is suitable for a `NameSpace` member name. In short, ``name`` must be a valid lower-case Python identifier that neither starts nor ends with an underscore. Otherwise an exception is raised. This function will raise a ``ValueError`` if ``name`` does not match the `constants.NAME_REGEX` regular expression. For example: >>> check_name('MyName') Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'MyName' Also, this function will raise a ``TypeError`` if ``name`` is not an ``str`` instance. For example: >>> check_name(u'my_name') Traceback (most recent call last): ... TypeError: name: need a ; got u'my_name' (a ) So that `check_name()` can be easily used within an assignment, ``name`` is returned unchanged if it passes the check. For example: >>> n = check_name('my_name') >>> n 'my_name' :param name: Identifier to test. """ if type(name) is not str: raise TypeError( TYPE_ERROR % ('name', str, name, type(name)) ) if re.match(NAME_REGEX, name) is None: raise ValueError( NAME_ERROR % (NAME_REGEX, name) ) return name class NameSpace(ReadOnly): """ A read-only name-space with handy container behaviours. A `NameSpace` instance is an ordered, immutable mapping object whose values can also be accessed as attributes. A `NameSpace` instance is constructed from an iterable providing its *members*, which are simply arbitrary objects with a ``name`` attribute whose value: 1. Is unique among the members 2. Passes the `check_name()` function Beyond that, no restrictions are placed on the members: they can be classes or instances, and of any type. The members can be accessed as attributes on the `NameSpace` instance or through a dictionary interface. For example, say we create a `NameSpace` instance from a list containing a single member, like this: >>> class my_member(object): ... name = 'my_name' ... >>> namespace = NameSpace([my_member]) >>> namespace NameSpace(<1 member>, sort=True) We can then access ``my_member`` both as an attribute and as a dictionary item: >>> my_member is namespace.my_name # As an attribute True >>> my_member is namespace['my_name'] # As dictionary item True For a more detailed example, say we create a `NameSpace` instance from a generator like this: >>> class Member(object): ... def __init__(self, i): ... self.i = i ... self.name = 'member%d' % i ... def __repr__(self): ... return 'Member(%d)' % self.i ... >>> ns = NameSpace(Member(i) for i in xrange(3)) >>> ns NameSpace(<3 members>, sort=True) As above, the members can be accessed as attributes and as dictionary items: >>> ns.member0 is ns['member0'] True >>> ns.member1 is ns['member1'] True >>> ns.member2 is ns['member2'] True Members can also be accessed by index and by slice. For example: >>> ns[0] Member(0) >>> ns[-1] Member(2) >>> ns[1:] (Member(1), Member(2)) (Note that slicing a `NameSpace` returns a ``tuple``.) `NameSpace` instances provide standard container emulation for membership testing, counting, and iteration. For example: >>> 'member3' in ns # Is there a member named 'member3'? False >>> 'member2' in ns # But there is a member named 'member2' True >>> len(ns) # The number of members 3 >>> list(ns) # Iterate through the member names ['member0', 'member1', 'member2'] Although not a standard container feature, the `NameSpace.__call__()` method provides a convenient (and efficient) way to iterate through the *members* (as opposed to the member names). Think of it like an ordered version of the ``dict.itervalues()`` method. For example: >>> list(ns[name] for name in ns) # One way to do it [Member(0), Member(1), Member(2)] >>> list(ns()) # A more efficient, simpler way to do it [Member(0), Member(1), Member(2)] Another convenience method is `NameSpace.__todict__()`, which will return a copy of the ``dict`` mapping the member names to the members. For example: >>> ns.__todict__() {'member1': Member(1), 'member0': Member(0), 'member2': Member(2)} As `NameSpace.__init__()` locks the instance, `NameSpace` instances are read-only from the get-go. An ``AttributeError`` is raised if you try to set *any* attribute on a `NameSpace` instance. For example: >>> ns.member3 = Member(3) # Lets add that missing 'member3' Traceback (most recent call last): ... AttributeError: locked: cannot set NameSpace.member3 to Member(3) (For information on the locking protocol, see the `ReadOnly` class, of which `NameSpace` is a subclass.) By default the members will be sorted alphabetically by the member name. For example: >>> sorted_ns = NameSpace([Member(7), Member(3), Member(5)]) >>> sorted_ns NameSpace(<3 members>, sort=True) >>> list(sorted_ns) ['member3', 'member5', 'member7'] >>> sorted_ns[0] Member(3) But if the instance is created with the ``sort=False`` keyword argument, the original order of the members is preserved. For example: >>> unsorted_ns = NameSpace([Member(7), Member(3), Member(5)], sort=False) >>> unsorted_ns NameSpace(<3 members>, sort=False) >>> list(unsorted_ns) ['member7', 'member3', 'member5'] >>> unsorted_ns[0] Member(7) The `NameSpace` class is used in many places throughout freeIPA. For a few examples, see the `plugable.API` and the `frontend.Command` classes. """ def __init__(self, members, sort=True, name_attr='name'): """ :param members: An iterable providing the members. :param sort: Whether to sort the members by member name. """ if type(sort) is not bool: raise TypeError( TYPE_ERROR % ('sort', bool, sort, type(sort)) ) self.__sort = sort if sort: self.__members = tuple( sorted(members, key=lambda m: getattr(m, name_attr)) ) else: self.__members = tuple(members) self.__names = tuple(getattr(m, name_attr) for m in self.__members) self.__map = dict() for member in self.__members: name = check_name(getattr(member, name_attr)) if name in self.__map: raise AttributeError(OVERRIDE_ERROR % (self.__class__.__name__, name, self.__map[name], member) ) assert not hasattr(self, name), 'Ouch! Has attribute %r' % name self.__map[name] = member setattr(self, name, member) lock(self) def __len__(self): """ Return the number of members. """ return len(self.__members) def __iter__(self): """ Iterate through the member names. If this instance was created with ``sort=False``, the names will be in the same order as the members were passed to the constructor; otherwise the names will be in alphabetical order (which is the default). This method is like an ordered version of ``dict.iterkeys()``. """ for name in self.__names: yield name def __call__(self): """ Iterate through the members. If this instance was created with ``sort=False``, the members will be in the same order as they were passed to the constructor; otherwise the members will be in alphabetical order by name (which is the default). This method is like an ordered version of ``dict.itervalues()``. """ for member in self.__members: yield member def __contains__(self, name): """ Return ``True`` if namespace has a member named ``name``. """ return name in self.__map def __getitem__(self, key): """ Return a member by name or index, or return a slice of members. :param key: The name or index of a member, or a slice object. """ if isinstance(key, basestring): return self.__map[key] if type(key) in (int, slice): return self.__members[key] raise TypeError( TYPE_ERROR % ('key', (str, int, slice), key, type(key)) ) def __repr__(self): """ Return a pseudo-valid expression that could create this instance. """ cnt = len(self) if cnt == 1: m = 'member' else: m = 'members' return '%s(<%d %s>, sort=%r)' % ( self.__class__.__name__, cnt, m, self.__sort, ) def __todict__(self): """ Return a copy of the private dict mapping member name to member. """ return dict(self.__map) freeipa-3.3.4/ipalib/frontend.pyc0000664000175000017500000015204312271707517016314 0ustar mkosekmkosekó †fçRc@s0dZddlZddlmZddlmZddlmZddlm Z ddl m Z m Z ddl mZmZmZmZmZdd lmZmZmZdd lmZdd lmZmZmZmZmZmZm Z m!Z!dd l"m#Z#dd l$m%Z%dZ&d„Z'd„Z(d„Z)de fd„ƒYZ*de*fd„ƒYZ+de+fd„ƒYZ,de+fd„ƒYZ-de*fd„ƒYZ.de fd„ƒYZ/de/e+fd„ƒYZ0d e/fd!„ƒYZ1d"e0fd#„ƒYZ2d$e3fd%„ƒYZ4d&e fd'„ƒYZ5dS((s) Base classes for all front-end plugins. iÿÿÿÿN(tversion(t API_VERSION(t root_logger(t NameSpace(tPlugintis_production_mode(t create_paramtParamtStrtFlagtPassword(tOutputtEntryt ListOfEntries(t_(tZeroArgumentErrortMaxArgumentErrort OverlapErrort VersionErrort OptionErrortInvocationErrortValidationErrortConversionError(tmessages(twraptvalidation_rulecCs*t|tƒ st‚t|ttƒ|S(N(thasattrt RULE_FLAGtAssertionErrortsetattrtTrue(tobj((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytrule+scCs"t|ƒo!t|ttƒtkS(N(tcallabletgetattrRtFalseR(R((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytis_rule0scCs\d}xO|D]G}t||ƒtkr@|t||ƒ}q |t||ƒ}q W|S(sÑ Return the number of entries in an entry. This is primarly for the failed output parameter so we don't print empty values. We also use this to determine if a non-zero return value is needed. i(ttypetdictt entry_counttlen(tentryt num_entriestf((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR'4s  tHasParamcBs8eZdZeZdd„Zdd„Zdd„ZRS(s¢ Base class for plugins that have `Param` `NameSpace` attributes. Subclasses of `HasParam` will on one or more attributes store `NameSpace` instances containing zero or more `Param` instances. These parameters might describe, for example, the arguments and options a command takes, or the attributes an LDAP entry can include, or whatever else the subclass sees fit. Although the interface a subclass must implement is very simple, it must conform to a specific naming convention: if you want a namespace ``SubClass.foo``, you must define a ``Subclass.takes_foo`` attribute and a ``SubCLass.get_foo()`` method, and you may optionally define a ``SubClass.check_foo()`` method. A quick big-picture example =========================== Say you want the ``options`` instance attribute on your subclass to be a `Param` `NameSpace`... then according to the enforced naming convention, your subclass must define a ``takes_options`` attribute and a ``get_options()`` method. For example: >>> from ipalib import Str, Int >>> class Example(HasParam): ... ... options = None # This will be replaced with your namespace ... ... takes_options = (Str('one'), Int('two')) ... ... def get_options(self): ... return self._get_param_iterable('options') ... >>> eg = Example() The ``Example.takes_options`` attribute is a ``tuple`` defining the parameters you want your ``Example.options`` namespace to contain. Your ``Example.takes_options`` attribute will be accessed via `HasParam._get_param_iterable()`, which, among other things, enforces the ``('takes_' + name)`` naming convention. For example: >>> eg._get_param_iterable('options') (Str('one'), Int('two')) The ``Example.get_options()`` method simply returns ``Example.takes_options`` by calling `HasParam._get_param_iterable()`. Your ``Example.get_options()`` method will be called via `HasParam._filter_param_by_context()`, which, among other things, enforces the ``('get_' + name)`` naming convention. For example: >>> list(eg._filter_param_by_context('options')) [Str('one'), Int('two')] At this point, the ``eg.options`` instance attribute is still ``None``: >>> eg.options is None True `HasParam._create_param_namespace()` will create the ``eg.options`` namespace from the parameters yielded by `HasParam._filter_param_by_context()`. For example: >>> eg._create_param_namespace('options') >>> eg.options NameSpace(<2 members>, sort=False) >>> list(eg.options) # Like dict.__iter__() ['one', 'two'] Your subclass can optionally define a ``check_options()`` method to perform sanity checks. If it exists, the ``check_options()`` method is called by `HasParam._create_param_namespace()` with a single value, the `NameSpace` instance it created. For example: >>> class Example2(Example): ... ... def check_options(self, namespace): ... for param in namespace(): # Like dict.itervalues() ... if param.name == 'three': ... raise ValueError("I dislike the param 'three'") ... print ' ** Looks good! **' # Note output below ... >>> eg = Example2() >>> eg._create_param_namespace('options') ** Looks good! ** >>> eg.options NameSpace(<2 members>, sort=False) However, if we subclass again and add a `Param` named ``'three'``: >>> class Example3(Example2): ... ... takes_options = (Str('one'), Int('two'), Str('three')) ... >>> eg = Example3() >>> eg._create_param_namespace('options') Traceback (most recent call last): ... ValueError: I dislike the param 'three' >>> eg.options is None # eg.options was not set True The Devil and the details ========================= In the above example, ``takes_options`` is a ``tuple``, but it can also be a param spec (see `create_param()`), or a callable that returns an iterable containing one or more param spec. Regardless of how ``takes_options`` is defined, `HasParam._get_param_iterable()` will return a uniform iterable, conveniently hiding the details. The above example uses the simplest ``get_options()`` method possible, but you could instead implement a ``get_options()`` method that would, for example, produce (or withhold) certain parameters based on the whether certain plugins are loaded. Think of ``takes_options`` as declarative, a simple definition of *what* parameters should be included in the namespace. You should only implement a ``takes_options()`` method if a `Param` must reference attributes on your plugin instance (for example, for validation rules); you should not use a ``takes_options()`` method to filter the parameters or add any other procedural behaviour. On the other hand, think of the ``get_options()`` method as imperative, a procedure for *how* the parameters should be created and filtered. In the example above the *how* just returns the *what* unchanged, but arbitrary logic can be implemented in the ``get_options()`` method. For example, you might filter certain parameters from ``takes_options`` base on some criteria, or you might insert additional parameters provided by other plugins. The typical use case for using ``get_options()`` this way is to procedurally generate the arguments and options for all the CRUD commands operating on a specific LDAP object: the `Object` plugin defines the possible LDAP entry attributes (as `Param`), and then the CRUD commands intelligently build their ``args`` and ``options`` namespaces based on which attribute is the primary key. In this way new LDAP attributes (aka parameters) can be added to the single point of definition (the `Object` plugin), and all the corresponding CRUD commands pick up these new parameters without requiring modification. For an example of how this is done, see the `ipalib.crud.Create` base class. However, there is one type of filtering you should not implement in your ``get_options()`` method, because it's already provided at a higher level: you should not filter parameters based on the value of ``api.env.context`` nor (preferably) on any values in ``api.env``. `HasParam._filter_param_by_context()` already does this by calling `Param.use_in_context()` for each parameter. Although the base `Param.use_in_context()` implementation makes a decision solely on the value of ``api.env.context``, subclasses can override this with implementations that consider arbitrary ``api.env`` values. ttakescCs˜|d|}t||dƒ}t|ƒtkr6|St|ttfƒrR|fSt|ƒre|ƒS|dkrxtƒStd|j ||fƒ‚dS(sà Return an iterable of params defined by the attribute named ``name``. A sequence of params can be defined one of three ways: as a ``tuple``; as a callable that returns an iterable; or as a param spec (a `Param` or ``str`` instance). This method returns a uniform iterable regardless of how the param sequence was defined. For example, when defined with a tuple: >>> class ByTuple(HasParam): ... takes_args = (Param('foo'), Param('bar')) ... >>> by_tuple = ByTuple() >>> list(by_tuple._get_param_iterable('args')) [Param('foo'), Param('bar')] Or you can define your param sequence with a callable when you need to reference attributes on your plugin instance (for validation rules, etc.). For example: >>> class ByCallable(HasParam): ... def takes_args(self): ... yield Param('foo', self.validate_foo) ... yield Param('bar', self.validate_bar) ... ... def validate_foo(self, _, value, **kw): ... if value != 'Foo': ... return _("must be 'Foo'") ... ... def validate_bar(self, _, value, **kw): ... if value != 'Bar': ... return _("must be 'Bar'") ... >>> by_callable = ByCallable() >>> list(by_callable._get_param_iterable('args')) [Param('foo', validate_foo), Param('bar', validate_bar)] Lastly, as a convenience for when a param sequence contains a single param, your defining attribute may a param spec (either a `Param` or an ``str`` instance). For example: >>> class BySpec(HasParam): ... takes_args = Param('foo') ... takes_options = 'bar?' ... >>> by_spec = BySpec() >>> list(by_spec._get_param_iterable('args')) [Param('foo')] >>> list(by_spec._get_param_iterable('options')) ['bar?'] For information on how an ``str`` param spec is interpreted, see the `create_param()` and `parse_param_spec()` functions in the `ipalib.parameters` module. Also see `HasParam._filter_param_by_context()`. Rs0%s.%s must be a tuple, callable, or spec; got %rN( R"tNoneR%ttuplet isinstanceRtstrR!t TypeErrortname(tselfR3tverbtsrc_nametsrc((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt_get_param_iterableãs;  ccsút|d|ƒ}d|}t||ƒsGtd|j|fƒ‚nt||ƒ}t|ƒstd|j||fƒ‚nxr|ƒD]g}t|ƒ}|dks¸|j|ƒr‹|dk rêt|dƒ rêt j |d|ƒn|Vq‹q‹WdS(sK Filter params on attribute named ``name`` by environment ``env``. For example: >>> from ipalib.config import Env >>> class Example(HasParam): ... ... takes_args = ( ... Str('foo_only', include=['foo']), ... Str('not_bar', exclude=['bar']), ... 'both', ... ) ... ... def get_args(self): ... return self._get_param_iterable('args') ... ... >>> eg = Example() >>> foo = Env(context='foo') >>> bar = Env(context='bar') >>> another = Env(context='another') >>> (foo.context, bar.context, another.context) (u'foo', u'bar', u'another') >>> list(eg._filter_param_by_context('args', foo)) [Str('foo_only', include=['foo']), Str('not_bar', exclude=['bar']), Str('both')] >>> list(eg._filter_param_by_context('args', bar)) [Str('both')] >>> list(eg._filter_param_by_context('args', another)) [Str('not_bar', exclude=['bar']), Str('both')] tenvtget_s%s.%s()s %s.%s must be a callable; got %rN( R"RtNotImplementedErrorR3R!R2RR.tuse_in_contexttobjectt __setattr__(R4R3R9tget_nametgettspectparam((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt_filter_param_by_context.s    cCspt|j||ƒdtƒ}t|ƒs\t|d|dƒ}t|ƒr\||ƒq\nt|||ƒdS(Ntsorttcheck_(RRCR#RR"R.R!R(R4R3R9t namespacetcheck((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt_create_param_namespacees   N( t__name__t __module__t__doc__R#tNO_CLIR8R.RCRH(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR,Es ™ K 7tCommandcBsúeZdZeZeƒZeƒZej dƒZ ej dƒZ ej dƒZ ej dƒZ d3ZeZej dƒZd4Zej dƒZeƒZeƒZd3ZedƒZd „Zd „Zd „Zd „Zd „Zd„Zd„Z d„Z!d„Z"d„Z#d3ee$ƒd3d„Z%d„Z&d„Z'd„Z(d„Z)d„Z*d„Z+d„Z,d„Z-d„Z.d„Z/d„Z0d„Z1d „Z2d!„Z3d"„Z4d#„Z5d$„Z6d%„Z7d&„Z8d'„Z9d5Z:d6Z;d1„Z<d2„Z=RS(7sF A public IPA atomic operation. All plugins that subclass from `Command` will be automatically available as a CLI command and as an XML-RPC method. Plugins that subclass from Command are registered in the ``api.Command`` namespace. For example: >>> from ipalib import create_api >>> api = create_api() >>> class my_command(Command): ... pass ... >>> api.register(my_command) >>> api.finalize() >>> list(api.Command) ['my_command'] >>> api.Command.my_command # doctest:+ELLIPSIS ipalib.frontend.my_command() targstoptionstparamstparams_by_defaulttoutputtresultt output_paramss1Results are truncated, try a more specific searchcOsƒ|jƒ|j||Ž}|jd|jdj|j|ƒƒ|j|j|ƒ|j|}|j |}|jd|jdj|j|ƒƒ|j j j rÉd|krÉt |d>> class my_cmd(Command): ... takes_args = ('login',) ... takes_options=(Password('passwd'),) ... >>> c = my_cmd() >>> c.finalize() >>> list(c._repr_iter(login=u'Okay.', passwd=u'Private!')) ["u'Okay.'", "passwd=u'********'"] s%s=%rN(RNR@R3R.treprt safe_valueRO(R4RPtargRltoption((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRZÏs cOsõ|jdk rft|ƒ|jkrf|jdkrHtd|jƒ‚ntd|jd|jƒ‚nt|j|ƒƒ}t|ƒdkrñt|j|ƒƒ}t |ƒj |ƒ}t|ƒdkrát dt |ƒƒ‚n|j |ƒn|S(s4 Merge (args, options) into params. iR3tcounttnamesN(tmax_argsR.R(RR3RR&t_Command__options_2_paramst_Command__args_2_paramstsett intersectionRtsortedR[(R4RNRORPtarg_kwRy((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRWës$ccsÍt}xÀt|jƒƒD]¬\}}| s2t‚t|ƒ|krÄ|jr¯t}t|ƒ|dkršt||ƒtt fkrš|j ||fVqÁ|j ||fVqÅ|j ||fVqPqWdS(Ni( R#t enumerateRNRR(t multivalueRR%tlistR/R3(R4RiR}tiRq((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__args_2_paramsüs  2ccszx4|jD])}||kr ||j|ƒfVq q Wt|ƒj|jƒ}|rvttdƒd|jƒƒ‚ndS(NsUnknown option: %(option)sRr(RPtpopRxt differencetinternal_optionsRR(R4ROR3t unused_keys((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__options_2_params s cOs%|j||Ž}t|j|ƒƒS(sK Creates a LDAP entry from attributes in args and options. (RWR&t_Command__attributes_2_entry(R4RNROtkw((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytargs_options_2_entrysccs€xy|jD]n}|j|jr ||kr ||}t|tƒrf|g|D] }|^qOfVqx|||fVq q WdS(N(RPt attributeR0R/(R4R‡R3Rltv((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__attributes_2_entrys  !c s>t‡fd†|jDƒƒ}t|jˆƒƒ}||fS(s4 Split params into (args, options). c3s!|]}ˆj|dƒVqdS(N(R@R.(t.0R3(RP(s-/home/mkosek/freeipa-clean/ipalib/frontend.pys *s(R/RNR&t_Command__params_2_options(R4RPRNRO((RPs-/home/mkosek/freeipa-clean/ipalib/frontend.pyRb&sccs6x/|jD]$}||kr |||fVq q WdS(N(RO(R4RPR3((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__params_2_options.s cCs®|dkr|j}nxtr©|jjj||d|ƒ}|jƒsT|}ny|||SWqttfk r¥}|jjj t |ƒt |j ƒƒqXqWdS(sm Prompts the user for the value of given parameter. Returns the parameter instance. toptionalN( R.tlabelRtBackendttextuitprompttstripRRtprint_prompt_attribute_errortunicodeterror(R4RBtdefaultRR‡RtrawRm((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt prompt_param3s     c s t‡fd†|jƒDƒƒS(s½ Return a dictionary of normalized values. For example: >>> class my_command(Command): ... takes_options = ( ... Param('first', normalizer=lambda value: value.lower()), ... Param('last'), ... ) ... >>> c = my_command() >>> c.finalize() >>> c.normalize(first=u'JOHN', last=u'DOE') {'last': u'DOE', 'first': u'john'} c3s1|]'\}}|ˆj|j|ƒfVqdS(N(RPR](RŒtkRŠ(R4(s-/home/mkosek/freeipa-clean/ipalib/frontend.pys _s(R&t iteritems(R4R‡((R4s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR]Msc s t‡fd†|jƒDƒƒS(s‡ Return a dictionary of values converted to correct type. >>> from ipalib import Int >>> class my_command(Command): ... takes_args = ( ... Int('one'), ... 'two', ... ) ... >>> c = my_command() >>> c.finalize() >>> c.convert(one=1, two=2) {'two': u'2', 'one': 1} c3s1|]'\}}|ˆj|j|ƒfVqdS(N(RPR^(RŒR›RŠ(R4(s-/home/mkosek/freeipa-clean/ipalib/frontend.pys ss(R&Rœ(R4R‡((R4s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR^bscCs<x5|jƒD]'}|j|jdƒdkr q q q WdS(N(RPR@R3R.(R4R‡RB((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__convert_itervscKsYg|jƒD]0}|j|kr |js4|jr |j^q }t|j||ƒƒS(s› Return a dictionary of defaults for all missing required values. For example: >>> from ipalib import Str >>> class my_command(Command): ... takes_args = Str('color', default=u'Red') ... >>> c = my_command() >>> c.finalize() >>> c.get_default() {'color': u'Red'} >>> c.get_default(color=u'Yellow') {} (RPR3trequiredtautofillR&t_Command__get_default_iter(R4R‡RkRP((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR\{sCcKs(t|j|g|ƒƒ}|j|ƒS(s< Return default value for parameter `name`. (R&R R@(R4R3R‡R˜((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_default_ofsccs]tƒ}xqt|jƒD]`}|j|ks=|j|kr|jdkrRqnx$|jjD]}|j|ƒq_WqqWxÙ|jƒD]Ë}d}t}|j|kr|j|krÚ|||j|||j>> class user_add(Command): ... def execute(self, **kw): ... return self.api.Backend.ldap.add(**kw) ... s %s.execute()N(R;R3(R4RNR‡((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR¹ûs cOs|jjj|j||ŽS(sK Forward call over XML-RPC to this same command on server. (R‘t xmlclientR¼R3(R4RNR‡((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR¼ scCs¢|jdƒt|jƒdks3|jdj rHt|jƒ|_n d |_|jdƒt|jƒƒt|jƒƒ}d„}tt |d|ƒdt ƒ|_ g}x›|D]“}t|ƒ}xn|D]f}|j d krëqÐn|j |j jkrqÐnyt||j|ƒƒ}WqÐtk r5qÐXqÐW|j||ƒq·Wt|dt ƒ|_t|jƒdt ƒ|_|jdƒtt|ƒjƒd S( s‰ Finalize plugin initialization. This method creates the ``args``, ``options``, and ``params`` namespaces. This is not done in `Command.__init__` because subclasses (like `crud.Add`) might need to access other plugins loaded in self.api to determine what their custom `Command.get_args` and `Command.get_options` methods should yield. RNiiÿÿÿÿROcSs:|jr6|jdkr|jS|jdkr2dSdSdS(Niii(Ržt sortorderR£R.(Rk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_key!s tkeyRDRTN(RHR(RNR}RuR.R/RORRzR#RPR£R3R¤tmintindext ValueErrortinsertRQt _iter_outputRRtsuperRMt _on_finalize(R4t params_nosortRÀRPRtpostj((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÈs6 &  "       ccsÊt|jƒtk rCtd|jtt|jƒ|jfƒ‚nx€t|jƒD]o\}}t|tƒr}t|ƒ}nt|tƒs½td|j|ttft|ƒ|fƒ‚n|VqSWdS(Ns&%s.has_output: need a %r; got a %r: %rs*%s.has_output[%d]: need a %r; got a %r: %r( R%t has_outputR/R2R3R|R0R1R (R4Rto((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÆBs(+ccs#x|jdƒD] }|VqWdS(sM Iterate through parameters for ``Command.args`` namespace. This method gets called by `HasParam._create_param_namespace()`. Subclasses can override this to customize how the arguments are determined. For an example of why this can be useful, see the `ipalib.crud.Create` subclass. RNN(R8(R4Rq((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_argsPs c Cs¤t}t}x‘|ƒD]†}|r\|jr\td|j|jtd„|ƒƒfƒ‚n|rxtd|jƒ‚n|jsŠt}n|jrt}qqWdS(s{ Sanity test for args namespace. This method gets called by `HasParam._create_param_namespace()`. s7%s: required argument after optional in %s arguments %scSs|jS(N(t param_spec(tx((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytiss)%s: only final argument can be multivalueN(R#RžRÄR3tmapRR}(R4RNRR}Rq((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt check_args]s %   c csÑx|jdƒD] }|VqWx‚|jD]w}t|ttfƒr)tddddtdƒdddd gƒVtd dd dtd ƒdddd gƒVPq)q)Wtd dtd ƒddddd gƒVdS(s' Iterate through parameters for ``Command.options`` namespace. This method gets called by `HasParam._create_param_namespace()`. For commands that return entries two special options are generated: --all makes the command retrieve/display all attributes --raw makes the command display attributes as they are stored Subclasses can override this to customize how the arguments are determined. For an example of why this can be useful, see the `ipalib.crud.Create` subclass. ROtalltcli_nametdocsJRetrieve and print all attributes from the server. Affects command output.texcludetwebuitflagst no_outputR™sBPrint entries as stored on the server. Only affects output format.sversion?s@Client version. Used to determine if server will accept request.t no_optionN(R8RÌR0R R R RR(R4RrRÍ((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt get_optionsts&         c Csud|j}t|tƒsAtd|tt|ƒ|fƒ‚nt|jƒ}t|ƒtdgƒ}||krÜ||}|r§td|t|ƒ|fƒ‚n||}|rÜtd|t|ƒ|fƒ‚qÜnx’|jƒD]„}||j}|jdkpt||jƒsKtd||j|jt|ƒ|fƒ‚nt |j ƒré|j ||ƒqéqéWdS(sY Validate the return value to make sure it meets the interface contract. s%s.validate_output()s%s: need a %r; got a %r: %rRs%s: missing keys %r in %rs%s: unexpected keys %r in %rs%%s: output[%r]: need %r; got %r: %rN( R3R0R&R2R%RxRRRÄRzR.R!Ra( R4RRtnicet expected_sett actual_settmissingtextraRÍRl((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRf™s,     !(ccsmx"|jdddƒD] }|VqW|jdkr8dSx.|jƒD] }d|jkr`qEn|VqEWdS(NRTR5thasRÚ(R8RPR.RÙ(R4RB((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_output_params¸s c Cstd|jd|jd|jd|jƒ}xi|jdd ƒD]U}y||d}Wn'tk r|jdƒ|j}nX||jdƒƒq@WdS( NRXtinfotwarningR—RR%s'Server sent a message with a wrong typetmessage((R&RXRäRåR—R@tKeyError(R4RRtloggertlogger_functionsRætfunction((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt log_messagesÂs       cOs¢t|tƒsdSd}|j|tƒg|jƒD]}|j^q6}|jdtƒrv|jddƒt }nt}|jdtƒr—d} ntd„|jƒDƒƒ} td„|jƒDƒƒ} xÌ|j D]Á} |j | } d| j krqÙn|| } | j ƒd kr2| dkr2d }n3| j ƒd kret| ƒdkr\qÙqed }nt| tƒr|j| || | |ƒqÙt| ttfƒrÁ|j| || | |ƒqÙt| tƒrì|j| || | |ƒqÙt| tƒr|j| || | |ƒqÙt| tƒrR| d krB|j| ƒqš|j| ƒqÙt| tƒrdqÙt| tƒrÙ|j| d t|j | jƒƒqÙqÙW|S(s Generic output method. Prints values the output argument according to their type and self.output. Entry attributes are labeled and printed in the order specified in self.output_params. Attributes that aren't present in self.output_params are not printed unless the command was invokend with the --all option. Attribute labelling is disabled if the --raw option was given. Subclasses can override this method, if custom output is needed. NiRÔtdnR™css'|]}|jt|jƒfVqdS(N(R3R–R(RŒRk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pys ïscss!|]}|j|jfVqdS(N(R3RÙ(RŒRk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pys ðst no_displayRsitfailedRUs%s %%d(R0R&RëRRTR3R@R#RÅRR.RRRÙtlowerR'R t print_entriesR/R~R t print_entryR–t print_summarytprint_indentedtbooltintt print_countRÖ(R4R’RRRNROtrvRktordert print_alltlabelsRÙRÍtoutpRS((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytoutput_for_cliÑsR "       +R3t takes_argsRÔR™tattrstaddattrtdelattrRRccsDx=|jƒD]/}|j|jkr-|Vq i|jd6Vq WdS(s; Get only options we want exported to JSON R3N(RÜR3tjson_only_presence_options(R4Rr((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_json_options"scs9t‡fd†ˆjDƒƒ}tˆjƒƒ|d<|S(Nc3s$|]}|tˆ|ƒfVqdS(N(R"(RŒta(R4(s-/home/mkosek/freeipa-clean/ipalib/frontend.pys .st takes_options(R&tjson_friendly_attributesR~R(R4t json_dict((R4s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__json__,sN(sresult(snames takes_args(sallsrawsattrsRÿsdelattrssetattrsversion(>RIRJRKR#tfinalize_earlyR/RRýRt finalize_attrRNRORPRQR.RRReRRRÌRTthas_output_paramsRƒRdRt msg_truncatedRhRnRZRWRwRvRˆR†RbRR&RšR]R^t_Command__convert_iterR\R¡R RaR·RcR¹R¼RÈRÆRÎRÓRÜRfRãRëRüRRRR(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRMqsj      $              (     2   %   H t LocalOrRemotecBs2eZdZeddedƒƒfZd„ZRS(s[ A command that is explicitly executed locally or remotely. This is for commands that makes sense to execute either locally or remotely to return a perhaps different result. The best example of this is the `ipalib.plugins.f_misc.env` plugin which returns the key/value pairs describing the configuration state: it can be sserver?RÖs,Forward to server instead of running locallycOs7|dr'|jj r'|j||ŽS|j||ŽS(sw Dispatch to forward() or execute() based on ``server`` option. When running in a client context, this command is executed remotely if ``options['server']`` is true; otherwise it is executed locally. When running in a server context, this command is always executed locally and the value of ``options['server']`` is ignored. R­(R9R`R¼R¹(R4RNRO((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRcEs (RIRJRKR RRRc(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR 5s tLocalcBseZdZd„ZRS(s™ A command that is explicitly executed locally. This is for commands that makes sense to execute only locally such as the help command. cOs|j||ŽS(s. Dispatch to forward() onlly. (R¼(R4RNRO((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRc\s(RIRJRKRc(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRTstObjectcBs¤eZeZejdƒZejdƒZejdƒZejdƒZ ejdƒZ ejdƒZ d Z eƒZd„Zd„Zd„Zd „Zd „ZRS( tbackendtmethodst propertiesRPt primary_keytparams_minus_pkcCs`t|jdƒdtddƒ|_t|jdƒdtddƒ|_|jdƒtd„|jƒƒ}t|ƒdkr®t d |j d j d „|Dƒƒfƒ‚nt|ƒdkr÷|d |_ ttd „|jƒƒdtƒ|_ nd|_ |j|_ d|jkrI|j|jjkrI|jj|j|_ntt|ƒjƒdS(NtMethodRDt name_attrt attr_nametPropertyRPcSs|jS(N(R(Rk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÑzsis)%s (Object) has multiple primary keys: %ss, css|]}|jVqdS(N(R3(RŒRk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pys sicSs|j S(N(R(Rk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÑ…sR‘(Rt_Object__get_attrsR#RRRHtfilterRPR(RÄR3RYRRR.R_t backend_nameR‘RRÇRRÈ(R4tpkeys((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÈrs(!! # '  $cgs†t|ƒdkr9t|dttfƒ r9|d}nt|ƒ}x:|jƒD],}|j|ksR||kryqRn|VqRWdS(sA Yield all Param whose name is not in ``names``. iiN(R(R0RR1t frozensetRPR3(R4RttminusRB((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt params_minuss,  cOstd|jƒ‚dS(s' Construct an LDAP DN. s %s.get_dn()N(R;R3(R4RNtkwargs((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_dnœsccsj||jkrdS|j|}t|ƒtks8t‚x+|ƒD] }|j|jkrB|VqBqBWdS(N(R_R%RRtobj_nameR3(R4R3RFtplugin((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt __get_attrs¢s ccsÎ|jjƒ}x„|jdƒD]s}t|ƒtkrI|jdƒ}nt|tƒs^t‚|j }||kr‡|j |ƒj Vqt |ƒVqWd„}x(t |jƒd|ƒD]}|j Vq¸WdS(sR This method gets called by `HasParam._create_param_namespace()`. RPs?*+cSs*|jjr&|jjdkr"dSdSdS(Niii(RBRžR£R.(Rk((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÀºs  RÁN(Rt __todict__R8R%R1trstripR0RRR3RRBRRzt itervalues(R4tpropsRARÁRÀtprop((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt get_params«s   N(RIRJR#RRR RRRRPRRR.RR/t takes_paramsRÈRR!RR*(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRcs    t AttributecBsƒeZdZeZejdƒZej dƒZ d„Z d„Z e e ƒZd„Ze eƒZd„Ze eƒZd„ZRS(sr Base class implementing the attribute-to-object association. `Attribute` plugins are associated with an `Object` plugin to group a common set of commands that operate on a common set of parameters. The association between attribute and object is done using a simple naming convention: the first part of the plugin class name (up to the first underscore) is the object name, and rest is the attribute name, as this table shows: =============== =========== ============== Class name Object name Attribute name =============== =========== ============== noun_verb noun verb user_add user add user_first_name user first_name =============== =========== ============== For example: >>> class user_add(Attribute): ... pass ... >>> instance = user_add() >>> instance.obj_name 'user' >>> instance.attr_name 'add' In practice the `Attribute` class is not used directly, but rather is only the base class for the `Method` and `Property` classes. Also see the `Object` class. sF^(?P[a-z][a-z0-9]+)_(?P[a-z][a-z0-9]+(?:_[a-z][a-z0-9]+)*)$t_Attribute__objcCsb|jjt|ƒjƒ}|s't‚|jdƒ|_|jdƒ|_tt |ƒj ƒdS(NRtattr( t NAME_REGEXtmatchR%RIRtgroupt_Attribute__obj_namet_Attribute__attr_nameRÇR,t__init__(R4tm((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4ðs  cCs|jS(N(R2(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__get_obj_name÷scCs|jS(N(R3(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt__get_attr_nameûscCs|jS(s} Returns the obj instance this attribute is associated with, or None if no association has been set. (R-(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt __get_objÿscCs-|jj|j|_tt|ƒjƒdS(N(R_RR"R-RÇR,RÈ(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÈs(RIRJRKR#RtretcompileR/RR R-R4t_Attribute__get_obj_nametpropertyR"t_Attribute__get_attr_nameRt_Attribute__get_objRRÈ(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR,Äs"        RcBs,eZdZeZeZd„Zd„ZRS(s- A command with an associated object. A `Method` plugin must have a corresponding `Object` plugin. The association between object and method is done through a simple naming convention: the first part of the method name (up to the first under score) is the object name, as the examples in this table show: ============= =========== ============== Method name Object name Attribute name ============= =========== ============== user_add user add noun_verb noun verb door_open_now door open_now ============= =========== ============== There are three different places a method can be accessed. For example, say you created a `Method` plugin and its corresponding `Object` plugin like this: >>> from ipalib import create_api >>> api = create_api() >>> class user_add(Method): ... def run(self, **options): ... return dict(result='Added the user!') ... >>> class user(Object): ... pass ... >>> api.register(user_add) >>> api.register(user) >>> api.finalize() First, the ``user_add`` plugin can be accessed through the ``api.Method`` namespace: >>> list(api.Method) ['user_add'] >>> api.Method.user_add() # Will call user_add.run() {'result': 'Added the user!'} Second, because `Method` is a subclass of `Command`, the ``user_add`` plugin can also be accessed through the ``api.Command`` namespace: >>> list(api.Command) ['user_add'] >>> api.Command.user_add() # Will call user_add.run() {'result': 'Added the user!'} And third, ``user_add`` can be accessed as an attribute on the ``user`` `Object`: >>> list(api.Object) ['user'] >>> list(api.Object.user.methods) ['add'] >>> api.Object.user.methods.add() # Will call user_add.run() {'result': 'Added the user!'} The `Attribute` base class implements the naming convention for the attribute-to-object association. Also see the `Object` and the `Property` classes. cCstt|ƒjƒdS(N(RÇRR4(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4Osccs¬x1|jjƒD] }d|jkr+qn|VqWxL|jƒD]>}|jt|jjƒkrAd|jkrwqAn|VqAqAWx"|jdddƒD] }|Vq™WdS(NRÚRTR5Râ(RRPRÙR3R~R8(R4RB((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRãRs  (RIRJRKR#textra_options_firsttextra_args_firstR4Rã(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR s ? RcBs;eZeZdZdZdZd„Zd„Z d„Z RS(cCs•tt|ƒjƒd|_tt|jƒdd„ƒƒ|_tt|j ƒdd„ƒƒ|_ t |j ƒ}|j |j |j|Ž|_dS(NRÁcSs t|dƒS(NRI(R"(R+((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÑlscSs|dS(Ni((tkeyvalue((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRÑos(RÇRR4R.RR/Rzt_Property__rules_itertrulest_Property__kw_iterR R&tklassRRB(R4R‡((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4fs !!ccsSxL|jjD]>\}}}t||dƒdk r |t||ƒfVq q WdS(N(RER R"R.(R4RÁtkindR˜((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt __kw_itertsccswxpt|jƒD]_}|jdƒr+qnt|j|ƒ}t|ƒrt||ƒ}t|ƒro|VqoqqWdS(s Iterates through the attributes in this instance to retrieve the methods implementing validation rules. RN(tdirt __class__t startswithR"R$(R4R3t base_attrR.((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt __rules_iterys  N( RIRJRRER.R˜R£t normalizerR4RDRB(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR`s  tUpdatercBs eZdZd„Zd„ZRS(sš An LDAP update with an associated object (always update). All plugins that subclass from `Updater` will be automatically available as a server update function. Plugins that subclass from Updater are registered in the ``api.Updater`` namespace. For example: >>> from ipalib import create_api >>> api = create_api() >>> class my(Object): ... pass ... >>> api.register(my) >>> class my_update(Updater): ... pass ... >>> api.register(my_update) >>> api.finalize() >>> list(api.Updater) ['my_update'] >>> api.Updater.my_update # doctest:+ELLIPSIS ipalib.frontend.my_update() cCstt|ƒjƒdS(N(RÇRNR4(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4¡scKs |jd|jƒ|j|S(Nsraw: %s(RXR3R¹(R4RO((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRh¤s (RIRJRKR4Rh(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRN‡s t _AdviceOutputcBs/eZd„Zed„Zd„Zd„ZRS(cCsg|_d|_d|_dS(Ns# (tcontenttprefixR.RO(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4®s  cCsU|r:xHt|dƒD]}|jj|j|ƒqWn|jj|j|ƒdS(NiF(RRPtappendRQ(R4tlinetwrappedt wrapped_line((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytcomment³scCs$|jjr |jd|ƒndS(NsDEBUG: (ROtverboseRV(R4RS((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRXºs cCs|jj|ƒdS(N(RPRR(R4RS((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytcommand¾s(RIRJR4RRVRXRX(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRO¬s   tAdvicecBs;eZdZdZeZdZd„Zd„Z d„Z RS(s9 Base class for advices, plugins for ipa-advise. tcCs#tt|ƒjƒtƒ|_dS(N(RÇRYR4ROtlog(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyR4ËscCs||_||j_dS(N(ROR[(R4RO((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyt set_optionsÏs cCs t‚dS(sp This method should be overriden by child Advices. Returns a string with instructions. N(R;(R4((s-/home/mkosek/freeipa-clean/ipalib/frontend.pytget_infoÓsN( RIRJRKR.ROR#t require_roott descriptionR4R\R](((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyRYÂs  (6RKR9t distutilsRtipapython.versionRtipapython.ipa_log_managerRtbaseRtplugableRRt parametersRRRR R RRR R R ttextRRjRRRRRRRRtipalibRttextwrapRRR R$R'R,RMR RRR,RRRNR=RORY(((s-/home/mkosek/freeipa-clean/ipalib/frontend.pyts< (:   ÿ-ÿÿÆaHT'%freeipa-3.3.4/ipalib/plugable.pyc0000664000175000017500000006533512271707517016277 0ustar mkosekmkosekó †fçRc@s¬dZddlZddlZddlZddlZddlZddlmZddlZddlZddl Z ddl Z ddl m Z ddl Z ddlZddlmZddlmZmZmZmZmZddlmZddlTd Zd „Zd efd „ƒYZd efd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZdefd„ƒYZ dej!fd„ƒYZ"dS(sÀ Plugin framework. The classes in this module make heavy use of Python container emulation. If you are unfamiliar with this Python feature, see http://docs.python.org/ref/sequence-types.html iÿÿÿÿN(tpath(tEnv(t_(tReadOnlyt NameSpacetlocktislockedt check_name(tDEFAULT_CONFIG(t*s%s: need a %r; got a %r: %rcCsKt|ddƒdkrtSt|jddƒdkr;tS|jjdkS(sv If the object has self.env.mode defined and that mode is production return True, otherwise return False. tenvtmodet productionN(tgetattrtNonetFalseR R (tobj((s-/home/mkosek/freeipa-clean/ipalib/plugable.pytis_production_mode2s tSetProxycBs2eZdZd„Zd„Zd„Zd„ZRS(sc A read-only container with set/sequence behaviour. This container acts as a proxy to an actual set-like object (a set, frozenset, or dict) that is passed to the constructor. To the extent possible in Python, this underlying set-like object cannot be modified through the SetProxy... which just means you wont do it accidentally. cCsftttf}t|ƒ|kr@tdt|ƒ|fƒ‚n||_t|ƒsbt|ƒndS(sR :param s: The target set-like object (a set, frozenset, or dict) s %r not in %rN(tsett frozensettdictttypet TypeErrort _SetProxy__sRR(tselftstallowed((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__init__Gs   cCs t|jƒS(s? Return the number of items in this container. (tlenR(R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__len__Rsccs#xt|jƒD] }|VqWdS(s< Iterate (in ascending order) through keys. N(tsortedR(Rtkey((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__iter__XscCs ||jkS(sv Return True if this container contains ``key``. :param key: The key to test for membership. (R(RR ((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __contains___s(t__name__t __module__t__doc__RRR!R"(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR>s   t DictProxycBs)eZdZd„Zd„Zd„ZRS(sd A read-only container with mapping behaviour. This container acts as a proxy to an actual mapping object (a dict) that is passed to the constructor. To the extent possible in Python, this underlying mapping object cannot be modified through the DictProxy... which just means you wont do it accidentally. Also see `SetProxy`. cCsTt|ƒtk r1tdt|ƒtfƒ‚n||_tt|ƒj|ƒdS(s> :param d: The target mapping object (a dict) s %r is not %rN(RRRt _DictProxy__dtsuperR&R(Rtd((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRss cCs |j|S(s| Return the value corresponding to ``key``. :param key: The key of the value you wish to retrieve. (R'(RR ((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __getitem__|sccs!x|D]}|j|VqWdS(sE Iterate (in ascending order by key) through values. N(R'(RR ((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__call__„s (R#R$R%RR*R+(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR&hs  t MagicDictcBseZdZd„ZRS(s A mapping container whose values can be accessed as attributes. For example: >>> magic = MagicDict({'the_key': 'the value'}) >>> magic['the_key'] 'the value' >>> magic.the_key 'the value' This container acts as a proxy to an actual mapping object (a dict) that is passed to the constructor. To the extent possible in Python, this underlying mapping object cannot be modified through the MagicDict... which just means you wont do it accidentally. Also see `DictProxy` and `SetProxy`. cCs4y ||SWn!tk r/td|ƒ‚nXdS(sƒ Return the value corresponding to ``name``. :param name: The name of the attribute you wish to retrieve. sno magic attribute %rN(tKeyErrortAttributeError(Rtname((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __getattr__ s  (R#R$R%R0(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR,ŒstPlugincBs„eZdZeZd Zd„Zd„Ze eƒZ d„Z d„Z d„Z defd„ƒYZd„Zd „Zd „ZRS( s% Base class for all plugins. cCsbd|_t|_t|_tjƒ|_|j}|j |_ |j |_ d|j |j f|_ td„|jDƒƒ|_t|jƒ|_|jjs±d|j |_n(t|jƒjddƒdjƒ|_tj|tƒ|jdkrtj|j dƒ|_nt|jtj ƒs^t!t"|j dtj t#|jƒ|jfƒ‚ndS(Ns%s.%scss%|]}d|j|jfVqdS(s%s.%sN(R$R#(t.0tb((s-/home/mkosek/freeipa-clean/ipalib/plugable.pys ¿ss<%s>s iis.label($Rt _Plugin__apiRt_Plugin__finalize_calledt_Plugin__finalizedt threadingtRLockt_Plugin__finalize_lockt __class__R#R/R$tmoduletfullnamettuplet __bases__tbasesRR%tdoctmsgtsummarytunicodetsplittstriptlog_mgrt get_loggertTruetlabelttexttFixMet isinstancetLazyTextRt TYPE_ERRORR(Rtcls((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRµs0       (  cCs|jS(s Return `API` instance passed to `set_api()`. If `set_api()` has not yet been called, None is returned. (R4(R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __get_apiÓscCsk|j\|jtkst‚|jr,dSt|_|jƒt|_t|ƒsat|ƒnWdQXdS(sè Finalize plugin initialization. This method calls `_on_finalize()` and locks the plugin object. Subclasses should not override this method. Custom finalization is done in `_on_finalize()`. N( R9R6RtAssertionErrorR5RHt _on_finalizeRR(R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pytfinalizeÜs      cCsdS(s¬ Do custom finalization. This method is called from `finalize()`. Subclasses can override this method in order to add custom finalization. N((R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRRðscCs*|j|js |jƒnWdQXdS(sR Finalize plugin initialization if it has not yet been finalized. N(R9R6RS(R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pytensure_finalizedùs  t finalize_attrcBs)eZdZdZdd„Zd„ZRS(s/ Create a stub object for plugin attribute that isn't set until the finalization of the plugin initialization. When the stub object is accessed, it calls `ensure_finalized()` to make sure the plugin initialization is finalized. The stub object is expected to be replaced with the actual attribute value during the finalization (preferably in `_on_finalize()`), otherwise an `AttributeError` is raised. This is used to implement on-demand finalization of plugin initialization. R/tvaluecCs||_||_dS(N(R/RV(RR/RV((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRs cCst|dks|jdkr"|jS|jƒyt||jƒSWn-tk rotd|j|jfƒ‚nXdS(Ns7attribute '%s' of plugin '%s' was not set in finalize()(RtapiRVRTR R/t RuntimeErrorR.(RRRO((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__get__s  (snamesvalueN(R#R$R%t __slots__RRRY(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRUs  cCsà|jdkstdƒ‚|dk s3tdƒ‚||_t|tƒsOdSx8|D]0}t||ƒ srt‚t||||ƒqVWxOdD]G}t||ƒr‘t||ƒ s¼t‚t||t||ƒƒq‘q‘WdS(s2 Set reference to `API` instance. s!set_api() can only be called onces!set_api() argument cannot be NoneNR tcontext(senvscontext(R4RRQRLtAPIthasattrtsetattrR (RRWR/((s-/home/mkosek/freeipa-clean/ipalib/plugable.pytset_api%s   cGsW|f|}|jd|ƒtj|ƒ}|dkrStjd|d|ƒ‚ndS(s— Call ``executable`` with ``args`` using subprocess.call(). If the call exits with a non-zero exit status, `ipalib.errors.SubprocessError` is raised, from which you can retrieve the exit code by checking the SubprocessError.returncode attribute. This method does *not* return what ``executable`` sent to stdout... for that, use `Plugin.callread()`. s Calling %rit returncodetargvN(tdebugt subprocesstcallterrorstSubprocessError(Rt executabletargsRatcode((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRd6s  cCsd|jj|jjfS(s½ Return 'module_name.class_name()' representation. This representation could be used to instantiate this Plugin instance given the appropriate environment. s%s.%s()(R:R$R#(R((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt__repr__Gs N(R#R$R%RHtfinalize_earlyRRIRt_Plugin__get_apitpropertyRWRSRRRTtobjectRUR_RdRj(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR1¬s     $  t RegistrarcBs5eZdZd„Zd„Zd„Zed„ZRS(s Collects plugin classes as they are registered. The Registrar does not instantiate plugins... it only implements the override logic and stores the plugins in a namespace per allowed base class. The plugins are instantiated when `API.finalize()` is called. cGsKtd„|Dƒƒ|_tƒ|_tt|ƒjt|jƒƒƒdS(sw :param allowed: Base classes from which plugins accepted by this Registrar must subclass. css|]}|ifVqdS(N((R2tbase((s-/home/mkosek/freeipa-clean/ipalib/plugable.pys csN(Rt_Registrar__allowedRt_Registrar__registeredR(RoRt_Registrar__base_iter(RR((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR^s ccs—x|jjƒD]\}}t|ƒs@tj|ƒs@t‚n|j}t|ƒsnt||ƒ snt‚nt||t |ƒƒ||fVqWdS(N( Rqt iteritemsRtinspecttisclassRQR#R]R^R,(RRptsub_dR/((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __base_iteris   ccs›t|ƒs$tj|ƒs$t‚nt}x@|jjƒD]/\}}t||ƒr:t}||fVq:q:W|s—t j d|d|jj ƒƒ‚ndS(sõ Iterates through allowed bases that ``klass`` is a subclass of. Raises `errors.PluginSubclassError` if ``klass`` is not a subclass of any allowed base. :param klass: The plugin class to find bases for. tpluginR?N( RRuRvRQRRqRtt issubclassRHRetPluginSubclassErrortkeys(RtklasstfoundRpRw((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyt __findbasesss  cCsótj|ƒs"td|ƒ‚n||jkrFtjd|ƒ‚nx–|j|ƒD]…\}}|j|kr¡|sÎtjd|jd|jd|ƒ‚qÎn-|rÎtj d|jd|jd|ƒ‚n|||j" for more information on a specific topic.s6See "ipa help commands" for the full list of commands.sFSee "ipa --help" for more information on a specific command.s-hs--helptactionthelpsShow this help message and exits-etdestR tmetavarsKEY=VALtappends#Set environment variable KEY to VALs-ctconftFILEsLoad configuration from FILEs-ds--debugt store_truesProduce full debuging outputs --delegates"Delegate the TGT to the IPA servers-vs --verbosetcountsEProduce more verbose output. A second -v displays the XML-RPC requestR’s-as --prompt-alls(Prompt for ALL values (even if optional)s-ns --no-promptt store_falset interactives'Prompt for NO values (even if required)s-fs --no-fallbacktfallbacks7Only use the server configured in /etc/ipa/default.confN(Rtoptparset OptionParserRtIPAHelpFormattertjointdisable_interspersed_argst add_option(RR˜R[((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR­ sD       c CsE|j||ƒ}|jƒ\}}i}|jdk r·t|jƒtksTt‚x`|jD]R}y|jddƒ\}}Wntk r“nX|j ƒ|t |j ƒƒ¿s(RLRQRR}R#R/RØR$R;RyR=R?RR(Rtp(Rÿ(s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR¹s  (R#R$R((Rÿ(s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR¸sc3sµx®|D]¦}t||ƒs"t‚|ˆkrAˆ|ƒˆ|×st_API__finalizedc3s|]}ˆ|ƒVqdS(N((R2R(R(s-/home/mkosek/freeipa-clean/ipalib/plugable.pys êsRçc3s|]}ˆ|ƒVqdS(N((R2R(R(s-/home/mkosek/freeipa-clean/ipalib/plugable.pys ìsN(RRäRnRRRRˆR RR†R]RQR t itervaluesRR_RWRTRRHR=(RR tproduction_modeR/Rpt namespaceR((RRÿR RçRR s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRSœs:      "(   "  N(R#R$R%RRRäRŒRRR­RÛRÜRåRS(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyR\±s     @4  .RÌcBseZd„ZRS(csS|j|j‰d|j‰|jƒ}dj‡‡fd†|Dƒƒ}d|S(Nt s c3s-|]#}tj|ˆdˆdˆƒVqdS(tinitial_indenttsubsequent_indentN(ttextwraptfill(R2tline(tindentt text_width(s-/home/mkosek/freeipa-clean/ipalib/plugable.pys öss %s (twidthtcurrent_indentt splitlinesRÍ(RRJtlinestresult((RRs-/home/mkosek/freeipa-clean/ipalib/plugable.pyt format_epilogñs   (R#R$R(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyRÌðs(#R%treRªRuR7R°RRcRÊReRtconfigRRðRJRRpRRRRRt constantsRtipapython.ipa_log_managerRNRRR&R,R1RoR\tIndentedHelpFormatterRÌ(((s-/home/mkosek/freeipa-clean/ipalib/plugable.pyts6           (  *$ ¨]ÿ@freeipa-3.3.4/ipalib/config.py0000664000175000017500000004737712270466515015613 0ustar mkosekmkosek# Authors: # Martin Nagy # Jason Gerard DeRose # # 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 . """ Process-wide static configuration and environment. The standard run-time instance of the `Env` class is initialized early in the `ipalib` process and is then locked into a read-only state, after which no further changes can be made to the environment throughout the remaining life of the process. For the per-request thread-local information, see `ipalib.request`. """ from ConfigParser import RawConfigParser, ParsingError from types import NoneType import os from os import path import sys from socket import getfqdn from ipapython.dn import DN from base import check_name from constants import CONFIG_SECTION from constants import TYPE_ERROR, OVERRIDE_ERROR, SET_ERROR, DEL_ERROR class Env(object): """ Store and retrieve environment variables. First an foremost, the `Env` class provides a handy container for environment variables. These variables can be both set *and* retrieved either as attributes *or* as dictionary items. For example, you can set a variable as an attribute: >>> env = Env() >>> env.attr = 'I was set as an attribute.' >>> env.attr u'I was set as an attribute.' >>> env['attr'] # Also retrieve as a dictionary item u'I was set as an attribute.' Or you can set a variable as a dictionary item: >>> env['item'] = 'I was set as a dictionary item.' >>> env['item'] u'I was set as a dictionary item.' >>> env.item # Also retrieve as an attribute u'I was set as a dictionary item.' The variable names must be valid lower-case Python identifiers that neither start nor end with an underscore. If your variable name doesn't meet these criteria, a ``ValueError`` will be raised when you try to set the variable (compliments of the `base.check_name()` function). For example: >>> env.BadName = 'Wont work as an attribute' Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'BadName' >>> env['BadName'] = 'Also wont work as a dictionary item' Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'BadName' The variable values can be ``str``, ``int``, or ``float`` instances, or the ``True``, ``False``, or ``None`` constants. When the value provided is an ``str`` instance, some limited automatic type conversion is performed, which allows values of specific types to be set easily from configuration files or command-line options. So in addition to their actual values, the ``True``, ``False``, and ``None`` constants can be specified with an ``str`` equal to what ``repr()`` would return. For example: >>> env.true = True >>> env.also_true = 'True' # Equal to repr(True) >>> env.true True >>> env.also_true True Note that the automatic type conversion is case sensitive. For example: >>> env.not_false = 'false' # Not equal to repr(False)! >>> env.not_false u'false' If an ``str`` value looks like an integer, it's automatically converted to the ``int`` type. Likewise, if an ``str`` value looks like a floating-point number, it's automatically converted to the ``float`` type. For example: >>> env.lucky = '7' >>> env.lucky 7 >>> env.three_halves = '1.5' >>> env.three_halves 1.5 Leading and trailing white-space is automatically stripped from ``str`` values. For example: >>> env.message = ' Hello! ' # Surrounded by double spaces >>> env.message u'Hello!' >>> env.number = ' 42 ' # Still converted to an int >>> env.number 42 >>> env.false = ' False ' # Still equal to repr(False) >>> env.false False Also, empty ``str`` instances are converted to ``None``. For example: >>> env.empty = '' >>> env.empty is None True `Env` variables are all set-once (first-one-wins). Once a variable has been set, trying to override it will raise an ``AttributeError``. For example: >>> env.date = 'First' >>> env.date = 'Second' Traceback (most recent call last): ... AttributeError: cannot override Env.date value u'First' with 'Second' An `Env` instance can be *locked*, after which no further variables can be set. Trying to set variables on a locked `Env` instance will also raise an ``AttributeError``. For example: >>> env = Env() >>> env.okay = 'This will work.' >>> env.__lock__() >>> env.nope = 'This wont work!' Traceback (most recent call last): ... AttributeError: locked: cannot set Env.nope to 'This wont work!' `Env` instances also provide standard container emulation for membership testing, counting, and iteration. For example: >>> env = Env() >>> 'key1' in env # Has key1 been set? False >>> env.key1 = 'value 1' >>> 'key1' in env True >>> env.key2 = 'value 2' >>> len(env) # How many variables have been set? 2 >>> list(env) # What variables have been set? ['key1', 'key2'] Lastly, in addition to all the handy container functionality, the `Env` class provides high-level methods for bootstraping a fresh `Env` instance into one containing all the run-time and configuration information needed by the built-in freeIPA plugins. These are the `Env` bootstraping methods, in the order they must be called: 1. `Env._bootstrap()` - initialize the run-time variables and then merge-in variables specified on the command-line. 2. `Env._finalize_core()` - merge-in variables from the configuration files and then merge-in variables from the internal defaults, after which at least all the standard variables will be set. After this method is called, the plugins will be loaded, during which third-party plugins can merge-in defaults for additional variables they use (likely using the `Env._merge()` method). 3. `Env._finalize()` - one last chance to merge-in variables and then the instance is locked. After this method is called, no more environment variables can be set during the remaining life of the process. However, normally none of these three bootstraping methods are called directly and instead only `plugable.API.bootstrap()` is called, which itself takes care of correctly calling the `Env` bootstrapping methods. """ __locked = False def __init__(self, **initialize): object.__setattr__(self, '_Env__d', {}) object.__setattr__(self, '_Env__done', set()) if initialize: self._merge(**initialize) def __lock__(self): """ Prevent further changes to environment. """ if self.__locked is True: raise StandardError( '%s.__lock__() already called' % self.__class__.__name__ ) object.__setattr__(self, '_Env__locked', True) def __islocked__(self): """ Return ``True`` if locked. """ return self.__locked def __setattr__(self, name, value): """ Set the attribute named ``name`` to ``value``. This just calls `Env.__setitem__()`. """ self[name] = value def __setitem__(self, key, value): """ Set ``key`` to ``value``. """ if self.__locked: raise AttributeError( SET_ERROR % (self.__class__.__name__, key, value) ) check_name(key) if key in self.__d: raise AttributeError(OVERRIDE_ERROR % (self.__class__.__name__, key, self.__d[key], value) ) assert not hasattr(self, key) if isinstance(value, basestring): value = value.strip() if isinstance(value, str): value = value.decode('utf-8') m = { 'True': True, 'False': False, 'None': None, '': None, } if value in m: value = m[value] elif value.isdigit(): value = int(value) elif key in ('basedn'): value = DN(value) else: try: value = float(value) except (TypeError, ValueError): pass assert type(value) in (unicode, int, float, bool, NoneType, DN) object.__setattr__(self, key, value) self.__d[key] = value def __getitem__(self, key): """ Return the value corresponding to ``key``. """ return self.__d[key] def __delattr__(self, name): """ Raise an ``AttributeError`` (deletion is never allowed). For example: >>> env = Env() >>> env.name = 'A value' >>> del env.name Traceback (most recent call last): ... AttributeError: locked: cannot delete Env.name """ raise AttributeError( DEL_ERROR % (self.__class__.__name__, name) ) def __contains__(self, key): """ Return True if instance contains ``key``; otherwise return False. """ return key in self.__d def __len__(self): """ Return number of variables currently set. """ return len(self.__d) def __iter__(self): """ Iterate through keys in ascending order. """ for key in sorted(self.__d): yield key def _merge(self, **kw): """ Merge variables from ``kw`` into the environment. Any variables in ``kw`` that have already been set will be ignored (meaning this method will *not* try to override them, which would raise an exception). This method returns a ``(num_set, num_total)`` tuple containing first the number of variables that were actually set, and second the total number of variables that were provided. For example: >>> env = Env() >>> env._merge(one=1, two=2) (2, 2) >>> env._merge(one=1, three=3) (1, 2) >>> env._merge(one=1, two=2, three=3) (0, 3) Also see `Env._merge_from_file()`. :param kw: Variables provides as keyword arguments. """ i = 0 for (key, value) in kw.iteritems(): if key not in self: self[key] = value i += 1 return (i, len(kw)) def _merge_from_file(self, config_file): """ Merge variables from ``config_file`` into the environment. Any variables in ``config_file`` that have already been set will be ignored (meaning this method will *not* try to override them, which would raise an exception). If ``config_file`` does not exist or is not a regular file, or if there is an error parsing ``config_file``, ``None`` is returned. Otherwise this method returns a ``(num_set, num_total)`` tuple containing first the number of variables that were actually set, and second the total number of variables found in ``config_file``. This method will raise a ``ValueError`` if ``config_file`` is not an absolute path. For example: >>> env = Env() >>> env._merge_from_file('my/config.conf') Traceback (most recent call last): ... ValueError: config_file must be an absolute path; got 'my/config.conf' Also see `Env._merge()`. :param config_file: Absolute path of the configuration file to load. """ if path.abspath(config_file) != config_file: raise ValueError( 'config_file must be an absolute path; got %r' % config_file ) if not path.isfile(config_file): return parser = RawConfigParser() try: parser.read(config_file) except ParsingError: return if not parser.has_section(CONFIG_SECTION): parser.add_section(CONFIG_SECTION) items = parser.items(CONFIG_SECTION) if len(items) == 0: return (0, 0) i = 0 for (key, value) in items: if key not in self: self[key] = value i += 1 if 'config_loaded' not in self: # we loaded at least 1 file self['config_loaded'] = True return (i, len(items)) def _join(self, key, *parts): """ Append path components in ``parts`` to base path ``self[key]``. For example: >>> env = Env() >>> env.home = '/people/joe' >>> env._join('home', 'Music', 'favourites') u'/people/joe/Music/favourites' """ if key in self and self[key] is not None: return path.join(self[key], *parts) def __doing(self, name): if name in self.__done: raise StandardError( '%s.%s() already called' % (self.__class__.__name__, name) ) self.__done.add(name) def __do_if_not_done(self, name): if name not in self.__done: getattr(self, name)() def _isdone(self, name): return name in self.__done def _bootstrap(self, **overrides): """ Initialize basic environment. This method will perform the following steps: 1. Initialize certain run-time variables. These run-time variables are strictly determined by the external environment the process is running in; they cannot be specified on the command-line nor in the configuration files. 2. Merge-in the variables in ``overrides`` by calling `Env._merge()`. The intended use of ``overrides`` is to merge-in variables specified on the command-line. 3. Intelligently fill-in the *in_tree*, *context*, *conf*, and *conf_default* variables if they haven't been set already. Also see `Env._finalize_core()`, the next method in the bootstrap sequence. :param overrides: Variables specified via command-line options. """ self.__doing('_bootstrap') # Set run-time variables (cannot be overridden): self.ipalib = path.dirname(path.abspath(__file__)) self.site_packages = path.dirname(self.ipalib) self.script = path.abspath(sys.argv[0]) self.bin = path.dirname(self.script) self.home = os.environ.get('HOME', None) # Merge in overrides: self._merge(**overrides) # Determine if running in source tree: if 'in_tree' not in self: if ( self.bin == self.site_packages and path.isfile(path.join(self.bin, 'setup.py')) ): self.in_tree = True else: self.in_tree = False if self.in_tree and 'mode' not in self: self.mode = 'developer' # Set dot_ipa: if 'dot_ipa' not in self: self.dot_ipa = self._join('home', '.ipa') # Set context if 'context' not in self: self.context = 'default' # Set confdir: if 'confdir' not in self: if self.in_tree: self.confdir = self.dot_ipa else: self.confdir = path.join('/', 'etc', 'ipa') # Set conf (config file for this context): if 'conf' not in self: self.conf = self._join('confdir', '%s.conf' % self.context) # Set conf_default (default base config used in all contexts): if 'conf_default' not in self: self.conf_default = self._join('confdir', 'default.conf') # Set plugins_on_demand: if 'plugins_on_demand' not in self: self.plugins_on_demand = (self.context == 'cli') def _finalize_core(self, **defaults): """ Complete initialization of standard IPA environment. This method will perform the following steps: 1. Call `Env._bootstrap()` if it hasn't already been called. 2. Merge-in variables from the configuration file ``self.conf`` (if it exists) by calling `Env._merge_from_file()`. 3. Merge-in variables from the defaults configuration file ``self.conf_default`` (if it exists) by calling `Env._merge_from_file()`. 4. Intelligently fill-in the *in_server* , *logdir*, and *log* variables if they haven't already been set. 5. Merge-in the variables in ``defaults`` by calling `Env._merge()`. In normal circumstances ``defaults`` will simply be those specified in `constants.DEFAULT_CONFIG`. After this method is called, all the environment variables used by all the built-in plugins will be available. As such, this method should be called *before* any plugins are loaded. After this method has finished, the `Env` instance is still writable so that 3rd-party plugins can set variables they may require as the plugins are registered. Also see `Env._finalize()`, the final method in the bootstrap sequence. :param defaults: Internal defaults for all built-in variables. """ self.__doing('_finalize_core') self.__do_if_not_done('_bootstrap') # Merge in context config file and then default config file: if self.__d.get('mode', None) != 'dummy': self._merge_from_file(self.conf) self._merge_from_file(self.conf_default) # Determine if in_server: if 'in_server' not in self: self.in_server = (self.context == 'server') # Set logdir: if 'logdir' not in self: if self.in_tree or not self.in_server: self.logdir = self._join('dot_ipa', 'log') else: self.logdir = path.join('/', 'var', 'log', 'ipa') # Set log file: if 'log' not in self: self.log = self._join('logdir', '%s.log' % self.context) self._merge(**defaults) def _finalize(self, **lastchance): """ Finalize and lock environment. This method will perform the following steps: 1. Call `Env._finalize_core()` if it hasn't already been called. 2. Merge-in the variables in ``lastchance`` by calling `Env._merge()`. 3. Lock this `Env` instance, after which no more environment variables can be set on this instance. Aside from unit-tests and example code, normally only one `Env` instance is created, which means that after this step, no more variables can be set during the remaining life of the process. This method should be called after all plugins have been loaded and after `plugable.API.finalize()` has been called. :param lastchance: Any final variables to merge-in before locking. """ self.__doing('_finalize') self.__do_if_not_done('_finalize_core') self._merge(**lastchance) self.__lock__() freeipa-3.3.4/ipalib/constants.py0000664000175000017500000002032212271663206016334 0ustar mkosekmkosek# Authors: # Martin Nagy # Jason Gerard DeRose # # 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 . """ All constants centralised in one file. """ import socket from ipapython.dn import DN from ipapython.version import VERSION try: FQDN = socket.getfqdn() except: try: FQDN = socket.gethostname() except: FQDN = None # The parameter system treats all these values as None: NULLS = (None, '', u'', tuple(), []) # regular expression NameSpace member names must match: NAME_REGEX = r'^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$' # Format for ValueError raised when name does not match above regex: NAME_ERROR = "name must match '%s'; got '%s'" # Standard format for TypeError message: TYPE_ERROR = '%s: need a %r; got %r (a %r)' # Stardard format for TypeError message when a callable is expected: CALLABLE_ERROR = '%s: need a callable; got %r (which is a %r)' # Standard format for StandardError message when overriding an attribute: OVERRIDE_ERROR = 'cannot override %s.%s value %r with %r' # Standard format for AttributeError message when a read-only attribute is # already locked: SET_ERROR = 'locked: cannot set %s.%s to %r' DEL_ERROR = 'locked: cannot delete %s.%s' # Used for a tab (or indentation level) when formatting for CLI: CLI_TAB = ' ' # Two spaces # The section to read in the config files, i.e. [global] CONFIG_SECTION = 'global' # The default configuration for api.env # This is a tuple instead of a dict so that it is immutable. # To create a dict with this config, just "d = dict(DEFAULT_CONFIG)". DEFAULT_CONFIG = ( ('version', VERSION), # Domain, realm, basedn: ('domain', 'example.com'), ('realm', 'EXAMPLE.COM'), ('basedn', DN(('dc', 'example'), ('dc', 'com'))), # LDAP containers: ('container_accounts', DN(('cn', 'accounts'))), ('container_user', DN(('cn', 'users'), ('cn', 'accounts'))), ('container_group', DN(('cn', 'groups'), ('cn', 'accounts'))), ('container_service', DN(('cn', 'services'), ('cn', 'accounts'))), ('container_host', DN(('cn', 'computers'), ('cn', 'accounts'))), ('container_hostgroup', DN(('cn', 'hostgroups'), ('cn', 'accounts'))), ('container_rolegroup', DN(('cn', 'roles'), ('cn', 'accounts'))), ('container_permission', DN(('cn', 'permissions'), ('cn', 'pbac'))), ('container_privilege', DN(('cn', 'privileges'), ('cn', 'pbac'))), ('container_automount', DN(('cn', 'automount'))), ('container_policies', DN(('cn', 'policies'))), ('container_configs', DN(('cn', 'configs'), ('cn', 'policies'))), ('container_roles', DN(('cn', 'roles'), ('cn', 'policies'))), ('container_applications', DN(('cn', 'applications'), ('cn', 'configs'), ('cn', 'policies'))), ('container_policygroups', DN(('cn', 'policygroups'), ('cn', 'configs'), ('cn', 'policies'))), ('container_policylinks', DN(('cn', 'policylinks'), ('cn', 'configs'), ('cn', 'policies'))), ('container_netgroup', DN(('cn', 'ng'), ('cn', 'alt'))), ('container_hbac', DN(('cn', 'hbac'))), ('container_hbacservice', DN(('cn', 'hbacservices'), ('cn', 'hbac'))), ('container_hbacservicegroup', DN(('cn', 'hbacservicegroups'), ('cn', 'hbac'))), ('container_dns', DN(('cn', 'dns'))), ('container_virtual', DN(('cn', 'virtual operations'), ('cn', 'etc'))), ('container_sudorule', DN(('cn', 'sudorules'), ('cn', 'sudo'))), ('container_sudocmd', DN(('cn', 'sudocmds'), ('cn', 'sudo'))), ('container_sudocmdgroup', DN(('cn', 'sudocmdgroups'), ('cn', 'sudo'))), ('container_automember', DN(('cn', 'automember'), ('cn', 'etc'))), ('container_selinux', DN(('cn', 'usermap'), ('cn', 'selinux'))), ('container_s4u2proxy', DN(('cn', 's4u2proxy'), ('cn', 'etc'))), ('container_cifsdomains', DN(('cn', 'ad'), ('cn', 'etc'))), ('container_trusts', DN(('cn', 'trusts'))), ('container_adtrusts', DN(('cn', 'ad'), ('cn', 'trusts'))), ('container_ranges', DN(('cn', 'ranges'), ('cn', 'etc'))), ('container_dna', DN(('cn', 'dna'), ('cn', 'ipa'), ('cn', 'etc'))), ('container_dna_posix_ids', DN(('cn', 'posix-ids'), ('cn', 'dna'), ('cn', 'ipa'), ('cn', 'etc'))), ('container_realm_domains', DN(('cn', 'Realm Domains'), ('cn', 'ipa'), ('cn', 'etc'))), ('container_otp', DN(('cn', 'otp'))), # Ports, hosts, and URIs: # FIXME: let's renamed xmlrpc_uri to rpc_xml_uri ('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', 300), # Web Application mount points ('mount_ipa', '/ipa/'), # WebUI stuff: ('webui_prod', True), # Session stuff: # Maximum time before a session expires forcing credentials to be reacquired. ('session_auth_duration', '20 minutes'), # How a session expiration is computed, see SessionManager.set_session_expiration_time() ('session_duration_type', 'inactivity_timeout'), # Debugging: ('verbose', 0), ('debug', False), ('startup_traceback', False), ('mode', 'production'), # CA plugin: ('ca_host', FQDN), # Set in Env._finalize_core() ('ca_port', 80), ('ca_agent_port', 443), ('ca_ee_port', 443), # For the following ports, None means a default specific to the installed # Dogtag version. ('ca_install_port', None), ('ca_agent_install_port', None), ('ca_ee_install_port', None), # Special CLI: ('prompt_all', False), ('interactive', True), ('fallback', True), ('delegate', False), # Enable certain optional plugins: ('enable_ra', False), ('ra_plugin', 'selfsign'), ('dogtag_version', 9), # Used when verifying that the API hasn't changed. Not for production. ('validate_api', False), # ******************************************************** # The remaining keys are never set from the values here! # ******************************************************** # # Env._bootstrap() or Env._finalize_core() will have filled in all the keys # below by the time DEFAULT_CONFIG is merged in, so the values below are # never actually used. They are listed both to provide a big picture and # also so DEFAULT_CONFIG contains at least all the keys that should be # present after Env._finalize_core() is called. # # Each environment variable below is sent to ``object``, which just happens # to be an invalid value for an environment variable, so if for some reason # any of these keys were set from the values here, an exception will be # raised. # Non-overridable vars set in Env._bootstrap(): ('host', FQDN), ('ipalib', object), # The directory containing ipalib/__init__.py ('site_packages', object), # The directory contaning ipalib ('script', object), # sys.argv[0] ('bin', object), # The directory containing the script ('home', object), # $HOME # Vars set in Env._bootstrap(): ('in_tree', object), # Whether or not running in-tree (bool) ('dot_ipa', object), # ~/.ipa directory ('context', object), # Name of context, default is 'default' ('confdir', object), # Directory containing config files ('conf', object), # File containing context specific config ('conf_default', object), # File containing context independent config ('plugins_on_demand', object), # Whether to finalize plugins on-demand (bool) # Set in Env._finalize_core(): ('in_server', object), # Whether or not running in-server (bool) ('logdir', object), # Directory containing log files ('log', object), # Path to context specific log file ) freeipa-3.3.4/ipalib/text.pyc0000664000175000017500000004435612271707517015470 0ustar mkosekmkosekó MmâRc@sãdZddlZddlZddlZddlmZd„Zdefd„ƒYZdefd„ƒYZ d e fd „ƒYZ d efd „ƒYZ d efd„ƒYZ de fd„ƒYZ e ƒZe ƒZeZdS(s` Defers gettext translation till request time. IPA presents some tricky gettext challenges. On the one hand, most translatable message are defined as class attributes on the plugins, which means these get evaluated at module-load time. But on the other hand, each request to the server can be in a different locale, so the actual translation must not occur till request time. The `text` module provides a mechanism for for deferred gettext translation. It was designed to: 1. Allow translatable strings to be marked with the usual ``_()`` and ``ngettext()`` functions so that standard tools like xgettext can still be used 2. Allow programmers to mark strings in a natural way without burdening them with details of the deferred translation mechanism A typical plugin will use the deferred translation like this: >>> from ipalib import Command, _, ngettext >>> class my_plugin(Command): ... my_string = _('Hello, %(name)s.') ... my_plural = ngettext('%(count)d goose', '%(count)d geese', 0) ... With normal gettext usage, the *my_string* and *my_plural* message would be translated at module-load-time when your ``my_plugin`` class is defined. This would mean that all message are translated in the locale of the server rather than the locale of the request. However, the ``_()`` function above is actually a `GettextFactory` instance, which when called returns a `Gettext` instance. A `Gettext` instance stores the message to be translated, and the gettext domain and localedir, but it doesn't perform the translation till `Gettext.__unicode__()` is called. For example: >>> my_plugin.my_string Gettext('Hello, %(name)s.', domain='ipa', localedir=None) >>> unicode(my_plugin.my_string) u'Hello, %(name)s.' Translation can also be performed via the `Gettext.__mod__()` convenience method. For example, these two are equivalent: >>> my_plugin.my_string % dict(name='Joe') u'Hello, Joe.' >>> unicode(my_plugin.my_string) % dict(name='Joe') # Long form u'Hello, Joe.' Similar to ``_()``, the ``ngettext()`` function above is actually an `NGettextFactory` instance, which when called returns an `NGettext` instance. An `NGettext` instance stores the singular and plural messages, and the gettext domain and localedir, but it doesn't perform the translation till `NGettext.__call__()` is called. For example: >>> my_plugin.my_plural NGettext('%(count)d goose', '%(count)d geese', domain='ipa', localedir=None) >>> my_plugin.my_plural(1) u'%(count)d goose' >>> my_plugin.my_plural(2) u'%(count)d geese' Translation can also be performed via the `NGettext.__mod__()` convenience method. For example, these two are equivalent: >>> my_plugin.my_plural % dict(count=1) u'1 goose' >>> my_plugin.my_plural(1) % dict(count=1) # Long form u'1 goose' Lastly, 3rd-party plugins can create factories bound to a different gettext domain. The default domain is ``'ipa'``, which is also the domain of the standard ``ipalib._()`` and ``ipalib.ngettext()`` factories. But 3rd-party plugins can create their own factories like this: >>> from ipalib import GettextFactory, NGettextFactory >>> _ = GettextFactory(domain='ipa_foo') >>> ngettext = NGettextFactory(domain='ipa_foo') >>> class foo(Command): ... msg1 = _('Foo!') ... msg2 = ngettext('%(count)d bar', '%(count)d bars', 0) ... Notice that these messages are bound to the ``'ipa_foo'`` domain: >>> foo.msg1 Gettext('Foo!', domain='ipa_foo', localedir=None) >>> foo.msg2 NGettext('%(count)d bar', '%(count)d bars', domain='ipa_foo', localedir=None) For additional details, see `GettextFactory` and `Gettext`, and for plural forms, see `NGettextFactory` and `NGettext`. iÿÿÿÿN(tcontextc Cs_|tjkst‚|\}}tj|d|dttddƒdtƒ}|tj|<|S(Nt localedirt languagestfallback(Rt__dict__tAssertionErrortgettextt translationtgetattrtNonetTrue(tkeytdomainRR((s)/home/mkosek/freeipa-clean/ipalib/text.pytcreate_translationys    tLazyTextcBs5eZdZdZd d d„Zd„Zd„ZRS( s† Base class for deferred translation. This class is not used directly. See the `Gettext` and `NGettext` subclasses. R RR targscCs.||_||_||f|_d|_dS(s¢ Initialize. :param domain: The gettext domain in which this message will be translated, e.g. ``'ipa'`` or ``'ipa_3rd_party'``; default is ``None`` :param localedir: The directory containing the gettext translations, e.g. ``'/usr/share/locale/'``; default is ``None``, in which case gettext will use the default system locale directory. N(R RR R R(tselfR R((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__init__s  cCs)t|ƒ|jk rtS|j|jkS(sÚ Return ``True`` if this instances is equal to *other*. Note that this method cannot be used on the `LazyText` base class itself as subclasses must define an *args* instance attribute. (ttypet __class__tFalseR(Rtother((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__eq__ŸscCs|j|ƒ S(sÞ Return ``True`` if this instances is not equal to *other*. Note that this method cannot be used on the `LazyText` base class itself as subclasses must define an *args* instance attribute. (R(RR((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__ne__ªs(sdomains localedirskeysargsN(t__name__t __module__t__doc__t __slots__R RRR(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR…s  tGettextcBsGeZdZdZddd„Zd„Zd„Zd„Zd„Z RS(sí Deferred translation using ``gettext.ugettext()``. Normally the `Gettext` class isn't used directly and instead is created via a `GettextFactory` instance. However, for illustration, we can create one like this: >>> msg = Gettext('Hello, %(name)s.') When you create a `Gettext` instance, the message is stored on the *msg* attribute: >>> msg.msg 'Hello, %(name)s.' No translation is performed till `Gettext.__unicode__()` is called. This will translate *msg* using ``gettext.ugettext()``, which will return the translated string as a Python ``unicode`` instance. For example: >>> unicode(msg) u'Hello, %(name)s.' `Gettext.__unicode__()` should be called at request time, which in a nutshell means it should be called from within your plugin's ``Command.execute()`` method. `Gettext.__unicode__()` will perform the translation based on the locale of the current request. `Gettext.__mod__()` is a convenience method for Python "percent" string formatting. It will translate your message using `Gettext.__unicode__()` and then perform the string substitution on the translated message. For example, these two are equivalent: >>> msg % dict(name='Joe') u'Hello, Joe.' >>> unicode(msg) % dict(name='Joe') # Long form u'Hello, Joe.' See `GettextFactory` for additional details. If you need to pick between singular and plural form, use `NGettext` instances via the `NGettextFactory`. tmsgcCs8tt|ƒj||ƒ||_|||f|_dS(N(tsuperRRRR(RRR R((s)/home/mkosek/freeipa-clean/ipalib/text.pyRás cCs#d|jj|j|j|jfS(Ns%s(%r, domain=%r, localedir=%r)(RRRR R(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__repr__æs cCsG|jtjkr(tj|jj}nt|jƒj}||jƒS(sN Translate this message and return as a ``unicode`` instance. (R RRtugettextR R(Rtg((s)/home/mkosek/freeipa-clean/ipalib/text.pyt __unicode__êscCs |jƒS(N(R"(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__json__ôscCs|jƒ|S(N(R"(Rtkw((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__mod__÷sN( RRRRR RRR"R#R%(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR´s)  tFixMecBs)eZdZeƒZd„Zd„ZRS(sH Non-translated place-holder for UI labels. `FixMe` is a subclass of `Gettext` and is used for automatically created place-holder labels. It generally behaves exactly like `Gettext` except no translation is ever performed. `FixMe` allows programmers to get plugins working without first filling in all the labels that will ultimately be required, while at the same time it creates conspicuous looking UI labels that remind the programmer to "fix-me!". For example, the typical usage would be something like this: >>> class Plugin(object): ... label = None ... def __init__(self): ... self.name = self.__class__.__name__ ... if self.label is None: ... self.label = FixMe(self.name + '.label') ... assert isinstance(self.label, Gettext) ... >>> class user(Plugin): ... pass # Oops, we didn't set user.label yet ... >>> u = user() >>> u.label FixMe('user.label') Note that as `FixMe` is a subclass of `Gettext`, is passes the above type check using ``isinstance()``. Calling `FixMe.__unicode__()` performs no translation, but instead returns said conspicuous looking label: >>> unicode(u.label) u'' For more examples of how `FixMe` is used, see `ipalib.parameters`. cCsd|jj|jfS(Ns%s(%r)(RRR(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyR%scCs d|jS(Nu<%s>(R(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyR"(s(RRRttupleRRR"(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR&ûs&  tNGettextcBs>eZdZdZddd„Zd„Zd„Zd„ZRS( sÖ Deferred translation for plural forms using ``gettext.ungettext()``. Normally the `NGettext` class isn't used directly and instead is created via a `NGettextFactory` instance. However, for illustration, we can create one like this: >>> msg = NGettext('%(count)d goose', '%(count)d geese') When you create an `NGettext` instance, the singular and plural forms of your message are stored on the *singular* and *plural* instance attributes: >>> msg.singular '%(count)d goose' >>> msg.plural '%(count)d geese' The translation and number selection isn't performed till `NGettext.__call__()` is called. This will translate and pick the correct number using ``gettext.ungettext()``. As a callable, an `NGettext` instance takes a single argument, an integer specifying the count. For example: >>> msg(0) u'%(count)d geese' >>> msg(1) u'%(count)d goose' >>> msg(2) u'%(count)d geese' `NGettext.__mod__()` is a convenience method for Python "percent" string formatting. It can only be used if your substitution ``dict`` contains the count in a ``'count'`` item. For example: >>> msg % dict(count=0) u'0 geese' >>> msg % dict(count=1) u'1 goose' >>> msg % dict(count=2) u'2 geese' Alternatively, these longer forms have the same effect as the three examples above: >>> msg(0) % dict(count=0) u'0 geese' >>> msg(1) % dict(count=1) u'1 goose' >>> msg(2) % dict(count=2) u'2 geese' A ``KeyError`` is raised if your substitution ``dict`` doesn't have a ``'count'`` item. For example: >>> msg2 = NGettext('%(num)d goose', '%(num)d geese') >>> msg2 % dict(num=0) Traceback (most recent call last): ... KeyError: 'count' However, in this case you can still use the longer, explicit form for string substitution: >>> msg2(0) % dict(num=0) u'0 geese' See `NGettextFactory` for additional details. tsingulartpluralcCsDtt|ƒj||ƒ||_||_||||f|_dS(N(RR(RR)R*R(RR)R*R R((s)/home/mkosek/freeipa-clean/ipalib/text.pyRss  cCs)d|jj|j|j|j|jfS(Ns#%s(%r, %r, domain=%r, localedir=%r)(RRR)R*R R(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyRys cCs|d}||ƒ|S(Ntcount((RR$R+((s)/home/mkosek/freeipa-clean/ipalib/text.pyR%}s cCsP|jtjkr(tj|jj}nt|jƒj}||j|j|ƒS(N(R RRt ungettextR R)R*(RR+tng((s)/home/mkosek/freeipa-clean/ipalib/text.pyt__call__s(ssingularspluralN( RRRRR RRR%R.(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR(,s C  tGettextFactorycBs/eZdZddd„Zd„Zd„ZRS(s¹ Factory for creating ``_()`` functions. A `GettextFactory` allows you to mark translatable messages that are evaluated at initialization time, but deferred their actual translation till request time. When you create a `GettextFactory` you can provide a specific gettext *domain* and *localedir*. By default the *domain* will be ``'ipa'`` and the *localedir* will be ``None``. Both are available via instance attributes of the same name. For example: >>> _ = GettextFactory() >>> _.domain 'ipa' >>> _.localedir is None True When the *localedir* is ``None``, gettext will use the default system localedir (typically ``'/usr/share/locale/'``). In general, you should **not** provide a *localedir*... it is intended only to support in-tree testing. Third party plugins will most likely want to use a different gettext *domain*. For example: >>> _ = GettextFactory(domain='ipa_3rd_party') >>> _.domain 'ipa_3rd_party' When you call your `GettextFactory` instance, it will return a `Gettext` instance associated with the same *domain* and *localedir*. For example: >>> my_msg = _('Hello world') >>> my_msg.domain 'ipa_3rd_party' >>> my_msg.localedir is None True The message isn't translated till `Gettext.__unicode__()` is called, which should be done during each request. See the `Gettext` class for additional details. tipacCs||_||_dS(s£ Initialize. :param domain: The gettext domain in which this message will be translated, e.g. ``'ipa'`` or ``'ipa_3rd_party'``; default is ``'ipa'`` :param localedir: The directory containing the gettext translations, e.g. ``'/usr/share/locale/'``; default is ``None``, in which case gettext will use the default system locale directory. N(R R(RR R((s)/home/mkosek/freeipa-clean/ipalib/text.pyR¶s cCsd|jj|j|jfS(Ns%s(domain=%r, localedir=%r)(RRR R(R((s)/home/mkosek/freeipa-clean/ipalib/text.pyRÄs cCst||j|jƒS(N(RR R(RR((s)/home/mkosek/freeipa-clean/ipalib/text.pyR.ÈsN(RRRR RRR.(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR/‰s+ tNGettextFactorycBseZdZd„ZRS(sí Factory for creating ``ngettext()`` functions. `NGettextFactory` is similar to `GettextFactory`, except `NGettextFactory` is for plural forms. So that standard tools like xgettext can find your plural forms, you should reference your `NGettextFactory` instance using a variable named *ngettext*. For example: >>> ngettext = NGettextFactory() >>> ngettext NGettextFactory(domain='ipa', localedir=None) When you call your `NGettextFactory` instance to create a deferred translation, you provide the *singular* message, the *plural* message, and a dummy *count*. An `NGettext` instance will be returned. For example: >>> my_msg = ngettext('%(count)d goose', '%(count)d geese', 0) >>> my_msg NGettext('%(count)d goose', '%(count)d geese', domain='ipa', localedir=None) The *count* is ignored (because the translation is deferred), but you should still provide it so parsing tools aren't confused. For consistency, it is recommended to always provide ``0`` for the *count*. See `NGettext` for details on how the deferred translation is later performed. See `GettextFactory` for details on setting a different gettext *domain* (likely needed for 3rd-party plugins). cCst|||j|jƒS(N(R(R R(RR)R*R+((s)/home/mkosek/freeipa-clean/ipalib/text.pyR.ìs(RRRR.(((s)/home/mkosek/freeipa-clean/ipalib/text.pyR1Ìs(Rt threadingtlocaleRtrequestRR tobjectRRR&R(R/R1t_tngettextR (((s)/home/mkosek/freeipa-clean/ipalib/text.pytqs    /G1]C%  freeipa-3.3.4/ipalib/pkcs10.py0000664000175000017500000000466312202434255015425 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . import os import sys import base64 import nss.nss as nss from ipapython import ipautil from ipalib import api PEM = 0 DER = 1 def get_subjectaltname(request): """ Given a CSR return the subjectaltname value, if any. The return value is a tuple of strings or None """ for extension in request.extensions: if extension.oid_tag == nss.SEC_OID_X509_SUBJECT_ALT_NAME: return nss.x509_alt_name(extension.value) return None def get_subject(request): """ Given a CSR return the subject value. This returns an nss.DN object. """ return request.subject def strip_header(csr): """ Remove the header and footer from a CSR. """ headerlen = 40 s = csr.find("-----BEGIN NEW CERTIFICATE REQUEST-----") if s == -1: headerlen = 36 s = csr.find("-----BEGIN CERTIFICATE REQUEST-----") if s >= 0: e = csr.find("-----END") csr = csr[s+headerlen:e] return csr def load_certificate_request(csr): """ Given a base64-encoded certificate request, with or without the header/footer, return a request object. """ csr = strip_header(csr) substrate = base64.b64decode(csr) # A fail-safe so we can always read a CSR. python-nss/NSS will segfault # otherwise if not nss.nss_is_initialized(): nss.nss_init_nodb() return nss.CertificateRequest(substrate) if __name__ == '__main__': nss.nss_init_nodb() # Read PEM request from stdin and print out its components csrlines = sys.stdin.readlines() csr = ''.join(csrlines) csr = load_certificate_request(csr) print csr print get_subject(csr) print get_subjectaltname(csr) freeipa-3.3.4/ipalib/aci.pyc0000664000175000017500000002507212271707517015232 0ustar mkosekmkosekó †fçRc @sþddlZddlZejdejƒZejdejƒZejdejƒZddgZddd d d d d ddg Zdd!d„ƒYZ e dkrúe dƒZ e GHdGHe dƒZ e GHdGHe dƒZ e GHdGHe dƒZ e GHdGHe ƒZ de _ e j ddgdƒe jdƒe jdƒe jdƒddd ge _e GHe ƒZde_ ej ddgdƒejdƒejdƒejdƒd ddge_eGHe jeƒGHe dƒZ e GHe d ƒZ e GHndS("iÿÿÿÿNs<\(version\s+3.0\s*;\s*acl\s+\"([^\"]*)\"\s*;\s*([^;]*);\s*\)s(\w+)\s*\((.*)\)\s+(.*)s!([a-zA-Z0-9;\.]+)\s*(\!?=)\s*(.*)tallowtdenytreadtwritetaddtdeletetsearchtcomparet selfwritetproxytalltACIcBsªeZdZdd„Zd„Zd„Zd„Zd„Zd„Z d„Z d„Z d d „Z d d „Z d d „Zd „Zd„Zd„Zd„Zd„ZRS(s¥ Holds the basic data for an ACI entry, as stored in the cn=accounts entry in LDAP. Has methods to parse an ACI string and export to an ACI String. cCskd|_d|_d|_||_i|_d|_dg|_i|_|dk rg|j |ƒndS(NRR( tNonetnamet source_groupt dest_groupt orig_acistrttargettactiont permissionstbindrulet _parse_acistr(tselftacistr((s(/home/mkosek/freeipa-clean/ipalib/aci.pyt__init__-s         cCsM|dkr|jS|dkr&|jS|dkr9|jStd|ƒ‚dS(s*Fake getting attributes by key for sortingiiisUnknown key value %sN(R RRt TypeError(Rtkey((s(/home/mkosek/freeipa-clean/ipalib/aci.pyt __getitem__9s   cCs |jƒS(sAn alias for export_to_string()(texport_to_string(R((s(/home/mkosek/freeipa-clean/ipalib/aci.pyt__repr__Csc Cs|jƒd}x»|jD]°}|j|d}t|j|dƒttfkr¨d}x'|j|dD]}||d}qlW|d }|d|||f}q|d|||j|df}qW|d|j|jdj|jƒ|j d |j d|j dfd }|S( s/Output a Directory Server-compatible ACI stringttoperatort expressions || iüÿÿÿs (%s %s "%s")s((version 3.0;acl "%s";%s (%s) %s %s "%s"t,tkeywords;)( tvalidateRttypettupletlistR RtjoinRR(RtacitttopRtl((s(/home/mkosek/freeipa-clean/ipalib/aci.pyRGs # &KcCs<|jdƒr|d}n|jdƒr8|d }n|S(Nt"iiÿÿÿÿ(t startswithtendswith(Rts((s(/home/mkosek/freeipa-clean/ipalib/aci.pyt_remove_quotesXs   c Cs£tj|jdƒƒ}|jd|_g}t}d}xb|D]Z}|dkr|jƒjƒ}|jƒ}|dkrÇ|dkrÇ||jƒ}|dkrÇ|dkrÇtd|ƒ‚qÇn|}|jƒjƒ}|j|ƒ}|jƒ} | dkrtd| ƒ‚qn|d krltj d |ƒ} i|j |<||j |d <| |j |d Rt set_bindrule(RRtvstarttacimatcht bindperms((s(/home/mkosek/freeipa-clean/ipalib/aci.pyR„s 'cCs+t|jƒttfkr'td‚nx3|jD](}|jƒtkr1td|‚q1q1W|jsrtd‚nt|jt ƒstd‚nt|j t ƒ s¸t |j ƒdkrÄtd‚nt|j t ƒsâtd‚n|j jdƒ s|j jd ƒ s|j jd ƒ r'td ‚ntS( syDo some basic verification that this will produce a valid LDAP ACI. returns True if valid spermissions must be a listsinvalid permission: '%s'sname must be setsname must be a stringis%target must be a non-empty dictionarysbindrule must be a dictionaryRR"R sbindrule is missing a component(R$RR%R&R<tlowert PERMISSIONSR t isinstancet basestringRtdictRIRtgettTrue(Rtp((s(/home/mkosek/freeipa-clean/ipalib/aci.pyR#”s     (  9 R2cCsSi|jd<|jdƒs-d|d}n||jdd<||jddsT   Ù                 freeipa-3.3.4/ipalib/request.pyc0000664000175000017500000000254512271707517016166 0ustar mkosekmkosekó ­8 Rc@smdZddlZddlmZmZddlmZmZejƒZ defd„ƒYZ d„Z dS(s Per-request thread-local data. iÿÿÿÿN(tReadOnlytlock(tOVERRIDE_ERRORtCALLABLE_ERRORt ConnectioncBseZdZd„ZRS(sH Base class for connection objects stored on `request.context`. cCsN||_t|ƒs7ttd|t|ƒfƒ‚n||_t|ƒdS(Nt disconnect(tconntcallablet TypeErrorRttypeRR(tselfRR((s,/home/mkosek/freeipa-clean/ipalib/request.pyt__init__'s    (t__name__t __module__t__doc__R (((s,/home/mkosek/freeipa-clean/ipalib/request.pyR"scCsGx3tjjƒD]"}t|tƒr|jƒqqWtjjƒdS(sB Delete all attributes on thread-local `request.context`. N(tcontextt__dict__tvaluest isinstanceRRtclear(tvalue((s,/home/mkosek/freeipa-clean/ipalib/request.pytdestroy_context1s( Rt threadingtbaseRRt constantsRRtlocalRRR(((s,/home/mkosek/freeipa-clean/ipalib/request.pyts   freeipa-3.3.4/ipalib/rpc.py0000664000175000017500000006751312271663206015121 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # Rob Crittenden # # 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 . """ RPC client and shared RPC client/server functionality. This module adds some additional functionality on top of the ``xmlrpclib`` module in the Python standard library. For documentation on the ``xmlrpclib`` module, see: http://docs.python.org/library/xmlrpclib.html Also see the `ipaserver.rpcserver` module. """ from types import NoneType from decimal import Decimal import threading import sys import os import errno import locale import datetime from xmlrpclib import (Binary, Fault, dumps, loads, ServerProxy, Transport, ProtocolError, MININT, MAXINT) import kerberos from dns import resolver, rdatatype from dns.exception import DNSException 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.ipa_log_manager import root_logger from ipapython import ipautil from ipapython import kernel_keyring from ipapython.cookie import Cookie from ipalib.text import _ import httplib import socket from ipapython.nsslib import NSSHTTPS, NSSConnection from nss.error import NSPRError 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 from ipapython.dn import DN COOKIE_NAME = 'ipa_session' KEYRING_COOKIE_NAME = '%s_cookie:%%s' % COOKIE_NAME def client_session_keyring_keyname(principal): ''' Return the key name used for storing the client session data for the given principal. ''' return KEYRING_COOKIE_NAME % principal def update_persistent_client_session_data(principal, data): ''' Given a principal create or update the session data for that principal in the persistent secure storage. Raises ValueError if unable to perform the action for any reason. ''' try: keyname = client_session_keyring_keyname(principal) except Exception, e: raise ValueError(str(e)) # kernel_keyring only raises ValueError (why??) kernel_keyring.update_key(keyname, data) def read_persistent_client_session_data(principal): ''' Given a principal return the stored session data for that principal from the persistent secure storage. Raises ValueError if unable to perform the action for any reason. ''' try: keyname = client_session_keyring_keyname(principal) except Exception, e: raise ValueError(str(e)) # kernel_keyring only raises ValueError (why??) return kernel_keyring.read_key(keyname) def delete_persistent_client_session_data(principal): ''' Given a principal remove the session data for that principal from the persistent secure storage. Raises ValueError if unable to perform the action for any reason. ''' try: keyname = client_session_keyring_keyname(principal) except Exception, e: raise ValueError(str(e)) # kernel_keyring only raises ValueError (why??) kernel_keyring.del_key(keyname) def xml_wrap(value): """ Wrap all ``str`` in ``xmlrpclib.Binary``. Because ``xmlrpclib.dumps()`` will itself convert all ``unicode`` instances into UTF-8 encoded ``str`` instances, we don't do it here. So in total, when encoding data for an XML-RPC packet, the following transformations occur: * All ``str`` instances are treated as binary data and are wrapped in an ``xmlrpclib.Binary()`` instance. * Only ``unicode`` instances are treated as character data. They get converted to UTF-8 encoded ``str`` instances (although as mentioned, not by this function). Also see `xml_unwrap()`. :param value: The simple scalar or simple compound value to wrap. """ if type(value) in (list, tuple): return tuple(xml_wrap(v) for v in value) if isinstance(value, dict): return dict( (k, xml_wrap(v)) for (k, v) in value.iteritems() ) if type(value) is str: return Binary(value) if type(value) is Decimal: # transfer Decimal as a string return unicode(value) if isinstance(value, (int, long)) and (value < MININT or value > MAXINT): return unicode(value) if isinstance(value, DN): return str(value) assert type(value) in (unicode, int, long, float, bool, NoneType) return value def xml_unwrap(value, encoding='UTF-8'): """ Unwrap all ``xmlrpc.Binary``, decode all ``str`` into ``unicode``. When decoding data from an XML-RPC packet, the following transformations occur: * The binary payloads of all ``xmlrpclib.Binary`` instances are returned as ``str`` instances. * All ``str`` instances are treated as UTF-8 encoded Unicode strings. They are decoded and the resulting ``unicode`` instance is returned. Also see `xml_wrap()`. :param value: The value to unwrap. :param encoding: The Unicode encoding to use (defaults to ``'UTF-8'``). """ if type(value) in (list, tuple): return tuple(xml_unwrap(v, encoding) for v in value) if type(value) is dict: return dict( (k, xml_unwrap(v, encoding)) for (k, v) in value.iteritems() ) if type(value) is str: return value.decode(encoding) if isinstance(value, Binary): assert type(value.data) is str return value.data assert type(value) in (unicode, int, float, bool, NoneType) return value def xml_dumps(params, methodname=None, methodresponse=False, encoding='UTF-8'): """ Encode an XML-RPC data packet, transparently wraping ``params``. This function will wrap ``params`` using `xml_wrap()` and will then encode the XML-RPC data packet using ``xmlrpclib.dumps()`` (from the Python standard library). For documentation on the ``xmlrpclib.dumps()`` function, see: http://docs.python.org/library/xmlrpclib.html#convenience-functions Also see `xml_loads()`. :param params: A ``tuple`` or an ``xmlrpclib.Fault`` instance. :param methodname: The name of the method to call if this is a request. :param methodresponse: Set this to ``True`` if this is a response. :param encoding: The Unicode encoding to use (defaults to ``'UTF-8'``). """ if type(params) is tuple: params = xml_wrap(params) else: assert isinstance(params, Fault) return dumps(params, methodname=methodname, methodresponse=methodresponse, encoding=encoding, allow_none=True, ) def decode_fault(e, encoding='UTF-8'): assert isinstance(e, Fault) if type(e.faultString) is str: return Fault(e.faultCode, e.faultString.decode(encoding)) return e def xml_loads(data, encoding='UTF-8'): """ Decode the XML-RPC packet in ``data``, transparently unwrapping its params. This function will decode the XML-RPC packet in ``data`` using ``xmlrpclib.loads()`` (from the Python standard library). If ``data`` contains a fault, ``xmlrpclib.loads()`` will itself raise an ``xmlrpclib.Fault`` exception. Assuming an exception is not raised, this function will then unwrap the params in ``data`` using `xml_unwrap()`. Finally, a ``(params, methodname)`` tuple is returned containing the unwrapped params and the name of the method being called. If the packet contains no method name, ``methodname`` will be ``None``. For documentation on the ``xmlrpclib.loads()`` function, see: http://docs.python.org/library/xmlrpclib.html#convenience-functions Also see `xml_dumps()`. :param data: The XML-RPC packet to decode. """ try: (params, method) = loads(data) return (xml_unwrap(params), method) except Fault, e: raise decode_fault(e) class LanguageAwareTransport(Transport): """Transport sending Accept-Language header""" def get_host_info(self, host): (host, extra_headers, x509) = Transport.get_host_info(self, host) try: lang = locale.setlocale(locale.LC_ALL, '').split('.')[0].lower() except locale.Error: # fallback to default locale lang = 'en_us' if not isinstance(extra_headers, list): extra_headers = [] extra_headers.append( ('Accept-Language', lang.replace('_', '-')) ) extra_headers.append( ('Referer', 'https://%s/ipa/xml' % str(host)) ) return (host, extra_headers, x509) class SSLTransport(LanguageAwareTransport): """Handles an HTTPS transaction to an XML-RPC server.""" def __nss_initialized(self, dbdir): """ If there is another connections open it may have already initialized NSS. This is likely to lead to an NSS shutdown failure. One way to mitigate this is to tell NSS to not initialize if it has already been done in another open connection. Returns True if another connection is using the same db. """ for value in context.__dict__.values(): if not isinstance(value, Connection): continue if not isinstance(value.conn._ServerProxy__transport, SSLTransport): continue if hasattr(value.conn._ServerProxy__transport, 'dbdir') and \ value.conn._ServerProxy__transport.dbdir == dbdir: return True return False def make_connection(self, host): host, self._extra_headers, x509 = self.get_host_info(host) # Python 2.7 changed the internal class used in xmlrpclib from # HTTP to HTTPConnection. We need to use the proper subclass # If we an existing connection exists using the same NSS database # there is no need to re-initialize. Pass thsi into the NSS # connection creator. if sys.version_info >= (2, 7): if self._connection and host == self._connection[0]: return self._connection[1] dbdir = '/etc/pki/nssdb' no_init = self.__nss_initialized(dbdir) if sys.version_info < (2, 7): conn = NSSHTTPS(host, 443, dbdir=dbdir, no_init=no_init) else: conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init) self.dbdir=dbdir conn.connect() if sys.version_info < (2, 7): return conn else: self._connection = host, conn return self._connection[1] class KerbTransport(SSLTransport): """ Handles Kerberos Negotiation authentication to an XML-RPC server. """ flags = kerberos.GSS_C_MUTUAL_FLAG | kerberos.GSS_C_SEQUENCE_FLAG def _handle_exception(self, e, service=None): (major, minor) = ipautil.get_gsserror(e) if minor[1] == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN: raise errors.ServiceError(service=service) elif minor[1] == KRB5_FCC_NOFILE: raise errors.NoCCacheError() elif minor[1] == KRB5KRB_AP_ERR_TKT_EXPIRED: raise errors.TicketExpired() elif minor[1] == KRB5_FCC_PERM: raise errors.BadCCachePerms() elif minor[1] == KRB5_CC_FORMAT: raise errors.BadCCacheFormat() elif minor[1] == KRB5_REALM_CANT_RESOLVE: raise errors.CannotResolveKDC() else: raise errors.KerberosError(major=major, minor=minor) def get_host_info(self, host): """ Two things can happen here. If we have a session we will add a cookie for that. If not we will set an Authorization header. """ (host, extra_headers, x509) = SSLTransport.get_host_info(self, host) if not isinstance(extra_headers, list): extra_headers = [] session_cookie = getattr(context, 'session_cookie', None) if session_cookie: extra_headers.append(('Cookie', session_cookie)) return (host, extra_headers, x509) # Set the remote host principal service = "HTTP@" + host.split(':')[0] try: (rc, vc) = kerberos.authGSSClientInit(service, self.flags) except kerberos.GSSError, e: self._handle_exception(e) try: kerberos.authGSSClientStep(vc, "") except kerberos.GSSError, e: self._handle_exception(e, service=service) for (h, v) in extra_headers: if h == 'Authorization': extra_headers.remove((h, v)) break extra_headers.append( ('Authorization', 'negotiate %s' % kerberos.authGSSClientResponse(vc)) ) return (host, extra_headers, x509) def single_request(self, host, handler, request_body, verbose=0): try: return SSLTransport.single_request(self, host, handler, request_body, verbose) finally: self.close() def store_session_cookie(self, cookie_header): ''' Given the contents of a Set-Cookie header scan the header and extract each cookie contained within until the session cookie is located. Examine the session cookie if the domain and path are specified, if not update the cookie with those values from the request URL. Then write the session cookie into the key store for the principal. If the cookie header is None or the session cookie is not present in the header no action is taken. Context Dependencies: The per thread context is expected to contain: principal The current pricipal the HTTP request was issued for. request_url The URL of the HTTP request. ''' if cookie_header is None: return principal = getattr(context, 'principal', None) request_url = getattr(context, 'request_url', None) root_logger.debug("received Set-Cookie '%s'", cookie_header) # Search for the session cookie try: session_cookie = Cookie.get_named_cookie_from_string(cookie_header, COOKIE_NAME, request_url) except Exception, e: root_logger.error("unable to parse cookie header '%s': %s", cookie_header, e) return if session_cookie is None: return cookie_string = str(session_cookie) root_logger.debug("storing cookie '%s' for principal %s", cookie_string, principal) try: update_persistent_client_session_data(principal, cookie_string) except Exception, e: # Not fatal, we just can't use the session cookie we were sent. pass def parse_response(self, response): self.store_session_cookie(response.getheader('Set-Cookie')) return SSLTransport.parse_response(self, response) class DelegatedKerbTransport(KerbTransport): """ Handles Kerberos Negotiation authentication and TGT delegation to an XML-RPC server. """ flags = kerberos.GSS_C_DELEG_FLAG | kerberos.GSS_C_MUTUAL_FLAG | \ kerberos.GSS_C_SEQUENCE_FLAG class xmlclient(Connectible): """ Forwarding backend plugin for XML-RPC client. Also see the `ipaserver.rpcserver.xmlserver` plugin. """ def __init__(self): super(xmlclient, self).__init__() self.__errors = dict((e.errno, e) for e in public_errors) def get_url_list(self, xmlrpc_uri): """ Create a list of urls consisting of the available IPA servers. """ # the configured URL defines what we use for the discovered servers (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(xmlrpc_uri) servers = [] name = '_ldap._tcp.%s.' % self.env.domain try: answers = resolver.query(name, rdatatype.SRV) except DNSException, e: answers = [] for answer in answers: server = str(answer.target).rstrip(".") servers.append('https://%s%s' % (ipautil.format_netloc(server), path)) servers = list(set(servers)) # the list/set conversion won't preserve order so stick in the # local config file version here. cfg_server = xmlrpc_uri if cfg_server in servers: # make sure the configured master server is there just once and # it is the first one servers.remove(cfg_server) servers.insert(0, cfg_server) else: servers.insert(0, cfg_server) return servers def get_session_cookie_from_persistent_storage(self, principal): ''' Retrieves the session cookie for the given principal from the persistent secure storage. Returns None if not found or unable to retrieve the session cookie for any reason, otherwise returns a Cookie object containing the session cookie. ''' # Get the session data, it should contain a cookie string # (possibly with more than one cookie). try: cookie_string = read_persistent_client_session_data(principal) except Exception, e: return None # Search for the session cookie within the cookie string try: session_cookie = Cookie.get_named_cookie_from_string(cookie_string, COOKIE_NAME) except Exception, e: return None return session_cookie def apply_session_cookie(self, url): ''' Attempt to load a session cookie for the current principal from the persistent secure storage. If the cookie is successfully loaded adjust the input url's to point to the session path and insert the session cookie into the per thread context for later insertion into the HTTP request. If the cookie is not successfully loaded then the original url is returned and the per thread context is not modified. Context Dependencies: The per thread context is expected to contain: principal The current pricipal the HTTP request was issued for. The per thread context will be updated with: session_cookie A cookie string to be inserted into the Cookie header of the HTPP request. ''' original_url = url principal = getattr(context, 'principal', None) session_cookie = self.get_session_cookie_from_persistent_storage(principal) if session_cookie is None: self.log.debug("failed to find session_cookie in persistent storage for principal '%s'", principal) return original_url else: self.debug("found session_cookie in persistent storage for principal '%s', cookie: '%s'", principal, session_cookie) # Decide if we should send the cookie to the server try: session_cookie.http_return_ok(original_url) except Cookie.Expired, e: self.debug("deleting session data for principal '%s': %s", principal, e) try: delete_persistent_client_session_data(principal) except Exception, e: pass return original_url except Cookie.URLMismatch, e: self.debug("not sending session cookie, URL mismatch: %s", e) return original_url except Exception, e: self.error("not sending session cookie, unknown error: %s", e) return original_url # O.K. session_cookie is valid to be returned, stash it away where it will will # get included in a HTTP Cookie headed sent to the server. self.log.debug("setting session_cookie into context '%s'", session_cookie.http_cookie()) setattr(context, 'session_cookie', session_cookie.http_cookie()) # Form the session URL by substituting the session path into the original URL scheme, netloc, path, params, query, fragment = urlparse.urlparse(original_url) path = '/ipa/session/xml' session_url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment)) return session_url def create_connection(self, ccache=None, verbose=False, fallback=True, delegate=False): try: 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: xmlrpc_uri = self.apply_session_cookie(xmlrpc_uri) except ValueError: # No session key, do full Kerberos auth pass urls = self.get_url_list(xmlrpc_uri) serverproxy = None for url in urls: kw = dict(allow_none=True, encoding='UTF-8') kw['verbose'] = verbose if url.startswith('https://'): if delegate: kw['transport'] = DelegatedKerbTransport() else: kw['transport'] = KerbTransport() else: kw['transport'] = LanguageAwareTransport() self.log.debug('trying %s' % url) setattr(context, 'request_url', url) serverproxy = ServerProxy(url, **kw) if len(urls) == 1: # if we have only 1 server and then let the # main requester handle any errors. This also means it # must handle a 401 but we save a ping. return serverproxy try: command = getattr(serverproxy, 'ping') try: response = command() except Fault, e: e = decode_fault(e) if e.faultCode in self.__errors: error = self.__errors[e.faultCode] raise error(message=e.faultString) else: raise UnknownError( code=e.faultCode, error=e.faultString, server=url, ) # We don't care about the response, just that we got one break except KerberosError, krberr: # kerberos error on one server is likely on all raise errors.KerberosError(major=str(krberr), minor='') except ProtocolError, e: if hasattr(context, 'session_cookie') and e.errcode == 401: # Unauthorized. Remove the session and try again. delattr(context, 'session_cookie') try: delete_persistent_client_session_data(principal) except Exception, e: # This shouldn't happen if we have a session but it isn't fatal. pass return self.create_connection(ccache, verbose, fallback, delegate) if not fallback: raise serverproxy = None except Exception, e: if not fallback: raise else: self.log.info('Connection to %s failed with %s', url, e) serverproxy = None if serverproxy is None: raise NetworkError(uri=_('any of the configured servers'), error=', '.join(urls)) return serverproxy def destroy_connection(self): if sys.version_info >= (2, 7): conn = getattr(context, self.id, None) if conn is not None: conn = conn.conn._ServerProxy__transport conn.close() def forward(self, name, *args, **kw): """ Forward call to command named ``name`` over XML-RPC. This method will encode and forward an XML-RPC request, and will then decode and return the corresponding XML-RPC response. :param command: The name of the command being forwarded. :param args: Positional arguments to pass to remote command. :param kw: Keyword arguments to pass to remote command. """ if name not in self.Command: raise ValueError( '%s.forward(): %r not in api.Command' % (self.name, name) ) server = getattr(context, 'request_url', None) self.debug("Forwarding '%s' to server '%s'", name, server) command = getattr(self.conn, name) params = [args, kw] try: response = command(*xml_wrap(params)) return xml_unwrap(response) except Fault, e: e = decode_fault(e) self.debug('Caught fault %d from server %s: %s', e.faultCode, server, e.faultString) if e.faultCode in self.__errors: error = self.__errors[e.faultCode] raise error(message=e.faultString) raise UnknownError( code=e.faultCode, error=e.faultString, server=server, ) except NSPRError, e: raise NetworkError(uri=server, error=str(e)) except ProtocolError, e: # By catching a 401 here we can detect the case where we have # a single IPA server and the session is invalid. Otherwise # we always have to do a ping(). session_cookie = getattr(context, 'session_cookie', None) if session_cookie and e.errcode == 401: # Unauthorized. Remove the session and try again. delattr(context, 'session_cookie') try: principal = getattr(context, 'principal', None) delete_persistent_client_session_data(principal) except Exception, e: # This shouldn't happen if we have a session but it isn't fatal. pass # Create a new serverproxy with the non-session URI. If there # is an existing connection we need to save the NSS dbdir so # we can skip an unnecessary NSS_Initialize() and avoid # NSS_Shutdown issues. serverproxy = self.create_connection(os.environ.get('KRB5CCNAME'), self.env.verbose, self.env.fallback, self.env.delegate) dbdir = None current_conn = getattr(context, self.id, None) if current_conn is not None: dbdir = getattr(current_conn.conn._ServerProxy__transport, 'dbdir', None) if dbdir is not None: self.debug('Using dbdir %s' % dbdir) setattr(context, self.id, Connection(serverproxy, self.disconnect)) if dbdir is not None: current_conn = getattr(context, self.id, None) current_conn.conn._ServerProxy__transport.dbdir = dbdir return self.forward(name, *args, **kw) raise NetworkError(uri=server, error=e.errmsg) except socket.error, e: raise NetworkError(uri=server, error=str(e)) except (OverflowError, TypeError), e: raise XMLRPCMarshallError(error=str(e)) freeipa-3.3.4/ipalib/__init__.pyc0000664000175000017500000010063712271707517016236 0ustar mkosekmkosekó †fçRc@södZddlZddlZddlmZddlmZmZmZm Z ddlm Z m Z m Z ddl mZmZmZmZmZddlmZmZmZmZmZmZmZmZmZmZmZddlmZm Z m!Z!m"Z"dd l#m$Z$dd l%m&Z&m'Z'm(Z(m)Z)dZ*e*ddkr[de*d Z+n de*Z+dd„Z,e,ddƒZ.ej/j0ddƒdkròddl1m2Z2xe2D]Z3e.j4e3ƒq²We.j5ddde6de7ƒe.j8ƒndS(s"x Package containing the core library. ============================= Tutorial for Plugin Authors ============================= This tutorial will introduce you to writing plugins for freeIPA v2. It does not cover every detail, but it provides enough to get you started and is heavily cross-referenced with further documentation that (hopefully) fills in the missing details. In addition to this tutorial, the many built-in plugins in `ipalib.plugins` and `ipaserver.plugins` provide real-life examples of how to write good plugins. ---------------------------- How this tutorial is written ---------------------------- The code examples in this tutorial are presented as if entered into a Python interactive interpreter session. As such, when you create a real plugin in a source file, a few details will be different (in addition to the fact that you will never include the ``>>>`` nor ``...`` that the interpreter places at the beginning of each line of code). The tutorial examples all have this pattern: :: >>> from ipalib import Command, create_api >>> api = create_api() >>> class my_command(Command): ... pass ... >>> api.register(my_command) >>> api.finalize() In the tutorial we call `create_api()` to create an *example* instance of `plugable.API` to work with. But a real plugin will simply use ``ipalib.api``, the standard run-time instance of `plugable.API`. A real plugin will have this pattern: :: from ipalib import Command, api class my_command(Command): pass api.register(my_command) As seen above, also note that in a real plugin you will *not* call `plugable.API.finalize()`. When in doubt, look at some of the built-in plugins for guidance, like those in `ipalib.plugins`. If you don't know what the Python *interactive interpreter* is, or are confused about what this *Python* is in the first place, then you probably should start with the Python tutorial: http://docs.python.org/tutorial/index.html ------------------------------------ First steps: A simple command plugin ------------------------------------ Our first example will create the most basic command plugin possible. This command will be seen in the list of command plugins, but it wont be capable of actually doing anything yet. A command plugin simultaneously adds a new command that can be called through the command-line ``ipa`` script *and* adds a new XML-RPC method... the two are one in the same, simply invoked in different ways. A freeIPA plugin is a Python class, and when you create a plugin, you register this class itself (instead of an instance of the class). To be a command plugin, your plugin must subclass from `frontend.Command` (or from a subclass thereof). Here is our first example: >>> from ipalib import Command, create_api >>> api = create_api() >>> class my_command(Command): # Step 1, define class ... """My example plugin.""" ... >>> api.register(my_command) # Step 2, register class Notice that we are registering the ``my_command`` class itself, not an instance of ``my_command``. Until `plugable.API.finalize()` is called, your plugin class has not been instantiated nor does the ``Command`` namespace yet exist. For example: >>> hasattr(api, 'Command') False >>> api.finalize() # plugable.API.finalize() >>> hasattr(api.Command, 'my_command') True >>> api.Command.my_command.doc Gettext('My example plugin.', domain='ipa', localedir=None) Notice that your plugin instance is accessed through an attribute named ``my_command``, the same name as your plugin class name. ------------------------------ Make your command do something ------------------------------ This simplest way to make your example command plugin do something is to implement a ``run()`` method, like this: >>> class my_command(Command): ... """My example plugin with run().""" ... ... def run(self, **options): ... return dict(result='My run() method was called!') ... >>> api = create_api() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command() # Call your command {'result': 'My run() method was called!'} When `frontend.Command.__call__()` is called, it first validates any arguments and options your command plugin takes (if any) and then calls its ``run()`` method. ------------------------ Forwarding vs. execution ------------------------ However, unlike the example above, a typical command plugin will implement an ``execute()`` method instead of a ``run()`` method. Your command plugin can be loaded in two distinct contexts: 1. In a *client* context - Your command plugin is only used to validate any arguments and options it takes, and then ``self.forward()`` is called, which forwards the call over XML-RPC to an IPA server where the actual work is done. 2. In a *server* context - Your same command plugin validates any arguments and options it takes, and then ``self.execute()`` is called, which you should implement to perform whatever work your plugin does. The base `frontend.Command.run()` method simply dispatches the call to ``self.execute()`` if ``self.env.in_server`` is True, or otherwise dispatches the call to ``self.forward()``. For example, say you have a command plugin like this: >>> class my_command(Command): ... """Forwarding vs. execution.""" ... ... def forward(self, **options): ... return dict( ... result='forward(): in_server=%r' % self.env.in_server ... ) ... ... def execute(self, **options): ... return dict( ... result='execute(): in_server=%r' % self.env.in_server ... ) ... The ``options`` will contain a dict of command options. One option is added automatically: ``version``. It contains the API version of the client. In order to maintain forward compatibility, you should always specify the API version current at the time you're writing your client. If ``my_command`` is loaded in a *client* context, ``forward()`` will be called: >>> api = create_api() >>> api.env.in_server = False # run() will dispatch to forward() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'forward(): in_server=False'} On the other hand, if ``my_command`` is loaded in a *server* context, ``execute()`` will be called: >>> api = create_api() >>> api.env.in_server = True # run() will dispatch to execute() >>> api.register(my_command) >>> api.finalize() >>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'execute(): in_server=True'} Normally there should be no reason to override `frontend.Command.forward()`, but, as above, it can be done for demonstration purposes. In contrast, there *is* a reason you might want to override `frontend.Command.run()`: if it only makes sense to execute your command locally, if it should never be forwarded to the server. In this case, you should implement your *do-stuff* in the ``run()`` method instead of in the ``execute()`` method. For example, the ``ipa`` command line script has a ``help`` command (`ipalib.cli.help`) that is specific to the command-line-interface and should never be forwarded to the server. --------------- Backend plugins --------------- There are two types of plugins: 1. *Frontend plugins* - These are loaded in both the *client* and *server* contexts. These need to be installed with any application built atop the `ipalib` library. The built-in frontend plugins can be found in `ipalib.plugins`. The ``my_command`` example above is a frontend plugin. 2. *Backend plugins* - These are only loaded in a *server* context and only need to be installed on the IPA server. The built-in backend plugins can be found in `ipaserver.plugins`. Backend plugins should provide a set of methods that standardize how IPA interacts with some external system or library. For example, all interaction with LDAP is done through the ``ldap`` backend plugin defined in `ipaserver.plugins.b_ldap`. As a good rule of thumb, anytime you need to import some package that is not part of the Python standard library, you should probably interact with that package via a corresponding backend plugin you implement. Backend plugins are much more free-form than command plugins. Aside from a few reserved attribute names, you can define arbitrary public methods on your backend plugin. Here is a simple example: >>> from ipalib import Backend >>> class my_backend(Backend): ... """My example backend plugin.""" ... ... def do_stuff(self): ... """Part of your API.""" ... return 'Stuff got done.' ... >>> api = create_api() >>> api.register(my_backend) >>> api.finalize() >>> api.Backend.my_backend.do_stuff() 'Stuff got done.' ------------------------------- How your command should do work ------------------------------- We now return to our ``my_command`` plugin example. Plugins are separated into frontend and backend plugins so that there are not unnecessary dependencies required by an application that only uses `ipalib` and its built-in frontend plugins (and then forwards over XML-RPC for execution). But how do we avoid introducing additional dependencies? For example, the ``user_add`` command needs to talk to LDAP to add the user, yet we want to somehow load the ``user_add`` plugin on client machines without requiring the ``python-ldap`` package (Python bindings to openldap) to be installed. To answer that, we consult our golden rule: **The golden rule:** A command plugin should implement its ``execute()`` method strictly via calls to methods on one or more backend plugins. So the module containing the ``user_add`` command does not itself import the Python LDAP bindings, only the module containing the ``ldap`` backend plugin does that, and the backend plugins are only installed on the server. The ``user_add.execute()`` method, which is only called when in a server context, is implemented as a series of calls to methods on the ``ldap`` backend plugin. When `plugable.Plugin.set_api()` is called, each plugin stores a reference to the `plugable.API` instance it has been loaded into. So your plugin can access the ``my_backend`` plugin as ``self.api.Backend.my_backend``. Additionally, convenience attributes are set for each namespace, so your plugin can also access the ``my_backend`` plugin as simply ``self.Backend.my_backend``. This next example will tie everything together. First we create our backend plugin: >>> api = create_api() >>> api.env.in_server = True # We want to execute, not forward >>> class my_backend(Backend): ... """My example backend plugin.""" ... ... def do_stuff(self): ... """my_command.execute() calls this.""" ... return 'my_backend.do_stuff() indeed did do stuff!' ... >>> api.register(my_backend) Second, we have our frontend plugin, the command: >>> class my_command(Command): ... """My example command plugin.""" ... ... def execute(self, **options): ... """Implemented against Backend.my_backend""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... >>> api.register(my_command) Lastly, we call ``api.finalize()`` and see what happens when we call ``my_command()``: >>> api.finalize() >>> api.Command.my_command(version=u'2.47') {'result': 'my_backend.do_stuff() indeed did do stuff!'} When not in a server context, ``my_command.execute()`` never gets called, so it never tries to access the non-existent backend plugin at ``self.Backend.my_backend.`` To emphasize this point, here is one last example: >>> api = create_api() >>> api.env.in_server = False # We want to forward, not execute >>> class my_command(Command): ... """My example command plugin.""" ... ... def execute(self, **options): ... """Same as above.""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... ... def forward(self, **options): ... return dict(result='Just my_command.forward() getting called here.') ... >>> api.register(my_command) >>> api.finalize() Notice that the ``my_backend`` plugin has certainly not be registered: >>> hasattr(api.Backend, 'my_backend') False And yet we can call ``my_command()``: >>> api.Command.my_command() {'result': 'Just my_command.forward() getting called here.'} ---------------------------------------- Calling other commands from your command ---------------------------------------- It can be useful to have your ``execute()`` method call other command plugins. Among other things, this allows for meta-commands that conveniently call several other commands in a single operation. For example: >>> api = create_api() >>> api.env.in_server = True # We want to execute, not forward >>> class meta_command(Command): ... """My meta-command plugin.""" ... ... def execute(self, **options): ... """Calls command_1(), command_2()""" ... msg = '%s; %s.' % ( ... self.Command.command_1()['result'], ... self.Command.command_2()['result'], ... ) ... return dict(result=msg) >>> class command_1(Command): ... def execute(self, **options): ... return dict(result='command_1.execute() called') ... >>> class command_2(Command): ... def execute(self, **options): ... return dict(result='command_2.execute() called') ... >>> api.register(meta_command) >>> api.register(command_1) >>> api.register(command_2) >>> api.finalize() >>> api.Command.meta_command(version=u'2.47') {'result': 'command_1.execute() called; command_2.execute() called.'} Because this is quite useful, we are going to revise our golden rule somewhat: **The revised golden rule:** A command plugin should implement its ``execute()`` method strictly via what it can access through ``self.api``, most likely via the backend plugins in ``self.api.Backend`` (which can also be conveniently accessed as ``self.Backend``). ----------------------------------------------- Defining arguments and options for your command ----------------------------------------------- You can define a command that will accept specific arguments and options. For example: >>> from ipalib import Str >>> class nudge(Command): ... """Takes one argument, one option""" ... ... takes_args = ('programmer',) ... ... takes_options = (Str('stuff', default=u'documentation')) ... ... def execute(self, programmer, **kw): ... return dict( ... result='%s, go write more %s!' % (programmer, kw['stuff']) ... ) ... >>> api = create_api() >>> api.env.in_server = True >>> api.register(nudge) >>> api.finalize() >>> api.Command.nudge(u'Jason', version=u'2.47') {'result': u'Jason, go write more documentation!'} >>> api.Command.nudge(u'Jason', stuff=u'unit tests', version=u'2.47') {'result': u'Jason, go write more unit tests!'} The ``args`` and ``options`` attributes are `plugable.NameSpace` instances containing a command's arguments and options, respectively, as you can see: >>> list(api.Command.nudge.args) # Iterates through argument names ['programmer'] >>> api.Command.nudge.args.programmer Str('programmer') >>> list(api.Command.nudge.options) # Iterates through option names ['stuff', 'version'] >>> api.Command.nudge.options.stuff Str('stuff', default=u'documentation') >>> api.Command.nudge.options.stuff.default u'documentation' The 'version' option is added to commands automatically. The arguments and options must not contain colliding names. They are both merged together into the ``params`` attribute, another `plugable.NameSpace` instance, as you can see: >>> api.Command.nudge.params NameSpace(<3 members>, sort=False) >>> list(api.Command.nudge.params) # Iterates through the param names ['programmer', 'stuff', 'version'] When calling a command, its positional arguments can also be provided as keyword arguments, and in any order. For example: >>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason', version=u'2.47') {'result': u'Jason, go write more lines of code!'} When a command plugin is called, the values supplied for its parameters are put through a sophisticated processing pipeline that includes steps for normalization, type conversion, validation, and dynamically constructing the defaults for missing values. The details wont be covered here; however, here is a quick teaser: >>> from ipalib import Int >>> class create_player(Command): ... takes_options = ( ... 'first', ... 'last', ... Str('nick', ... normalizer=lambda value: value.lower(), ... default_from=lambda first, last: first[0] + last, ... ), ... Int('points', default=0), ... ) ... >>> cp = create_player() >>> cp.finalize() >>> cp.convert(points=u' 1000 ') {'points': 1000} >>> cp.normalize(nick=u'NickName') {'nick': u'nickname'} >>> cp.get_default(first=u'Jason', last=u'DeRose') {'nick': u'jderose', 'points': 0} For the full details on the parameter system, see the `frontend.parse_param_spec()` function, and the `frontend.Param` and `frontend.Command` classes. --------------------------------------- Allowed return values from your command --------------------------------------- The return values from your command can be rendered by different user interfaces (CLI, web-UI); furthermore, a call to your command can be transparently forwarded over the network (XML-RPC, JSON). As such, the return values from your command must be usable by the least common denominator. Your command should return only simple data types and simple data structures, the kinds that can be represented in an XML-RPC request or in the JSON format. The return values from your command's ``execute()`` method can include only the following: Simple scalar values: These can be ``str``, ``unicode``, ``int``, and ``float`` instances, plus the ``True``, ``False``, and ``None`` constants. Simple compound values: These can be ``dict``, ``list``, and ``tuple`` instances. These compound values must contain only the simple scalar values above or other simple compound values. These compound values can also be empty. For our purposes here, the ``list`` and ``tuple`` types are equivalent and can be used interchangeably. Also note that your ``execute()`` method should not contain any ``print`` statements or otherwise cause any output on ``sys.stdout``. Your command can (and should) produce log messages by using ``self.log`` (see below). To learn more about XML-RPC (XML Remote Procedure Call), see: http://docs.python.org/library/xmlrpclib.html http://en.wikipedia.org/wiki/XML-RPC To learn more about JSON (Java Script Object Notation), see: http://docs.python.org/library/json.html http://www.json.org/ --------------------------------------- How your command should print to stdout --------------------------------------- As noted above, your command should not print anything while in its ``execute()`` method. So how does your command format its output when called from the ``ipa`` script? After the `cli.CLI.run_cmd()` method calls your command, it will call your command's ``output_for_cli()`` method (if you have implemented one). If you implement an ``output_for_cli()`` method, it must have the following signature: :: output_for_cli(textui, result, *args, **options) textui An object implementing methods for outputting to the console. Currently the `ipalib.cli.textui` plugin is passed, which your method can also access as ``self.Backend.textui``. However, in case this changes in the future, your method should use the instance passed to it in this first argument. result This is the return value from calling your command plugin. Depending upon how your command is implemented, this is probably the return value from your ``execute()`` method. args The arguments your command was called with. If your command takes no arguments, you can omit this. You can also explicitly list your arguments rather than using the generic ``*args`` form. options The options your command was called with. If your command takes no options, you can omit this. If your command takes any options, you must use the ``**options`` form as they will be provided strictly as keyword arguments. For example, say we setup a command like this: >>> class show_items(Command): ... ... takes_args = ('key?',) ... ... takes_options = (Flag('reverse'),) ... ... def execute(self, key, **options): ... items = dict( ... fruit=u'apple', ... pet=u'dog', ... city=u'Berlin', ... ) ... if key in items: ... return dict(result=items[key]) ... items = [ ... (k, items[k]) for k in sorted(items, reverse=options['reverse']) ... ] ... return dict(result=items) ... ... def output_for_cli(self, textui, result, key, **options): ... result = result['result'] ... if key is not None: ... textui.print_plain('%s = %r' % (key, result)) ... else: ... textui.print_name(self.name) ... textui.print_keyval(result) ... format = '%d items' ... if options['reverse']: ... format += ' (in reverse order)' ... textui.print_count(result, format) ... >>> api = create_api() >>> api.bootstrap(in_server=True) # We want to execute, not forward >>> api.register(show_items) >>> api.finalize() Normally when you invoke the ``ipa`` script, `cli.CLI.load_plugins()` will register the `cli.textui` backend plugin, but for the sake of our example, we will just create an instance here: >>> from ipalib import cli >>> textui = cli.textui() # We'll pass this to output_for_cli() Now for what we are concerned with in this example, calling your command through the ``ipa`` script basically will do the following: >>> result = api.Command.show_items() >>> api.Command.show_items.output_for_cli(textui, result, None, reverse=False) ----------- show-items: ----------- city = u'Berlin' fruit = u'apple' pet = u'dog' ------- 3 items ------- Similarly, calling it with ``reverse=True`` would result in the following: >>> result = api.Command.show_items(reverse=True) >>> api.Command.show_items.output_for_cli(textui, result, None, reverse=True) ----------- show-items: ----------- pet = u'dog' fruit = u'apple' city = u'Berlin' -------------------------- 3 items (in reverse order) -------------------------- Lastly, providing a ``key`` would result in the following: >>> result = api.Command.show_items(u'city') >>> api.Command.show_items.output_for_cli(textui, result, 'city', reverse=False) city = u'Berlin' See the `ipalib.cli.textui` plugin for a description of its methods. ------------------------ Logging from your plugin ------------------------ After `plugable.Plugin.set_api()` is called, your plugin will have a ``self.log`` attribute. Plugins should only log through this attribute. For example: >>> class paint_house(Command): ... ... takes_args = 'color' ... ... def execute(self, color, **options): ... """Uses self.log.error()""" ... if color not in ('red', 'blue', 'green'): ... self.log.error("I don't have %s paint!", color) # Log error ... return ... return 'I painted the house %s.' % color ... Some basic knowledge of the Python ``logging`` module might be helpful. See: http://docs.python.org/library/logging.html The important thing to remember is that your plugin should not configure logging itself, but should instead simply use the ``self.log`` logger. Also see the `plugable.API.bootstrap()` method for details on how the logging is configured. --------------------- Environment variables --------------------- Plugins access configuration variables and run-time information through ``self.api.env`` (or for convenience, ``self.env`` is equivalent). This attribute is a refences to the `ipalib.config.Env` instance created in `plugable.API.__init__()`. After `API.bootstrap()` has been called, the `Env` instance will be populated with all the environment information used by the built-in plugins. This will be called before any plugins are registered, so plugin authors can assume these variables will all exist by the time the module containing their plugin (or plugins) is imported. `Env._bootstrap()`, which is called by `API.bootstrap()`, will create several run-time variables that connot be overriden in configuration files or through command-line options. Here is an overview of this run-time information: ============= ============================= ======================= Key Example value Description ============= ============================= ======================= bin '/usr/bin' Dir. containing script dot_ipa '/home/jderose/.ipa' User config directory home os.environ['HOME'] User home dir. ipalib '.../site-packages/ipalib' Dir. of ipalib package mode 'unit_test' The mode ipalib is in script sys.argv[0] Path of script site_packages '.../python2.5/site-packages' Dir. containing ipalib/ ============= ============================= ======================= If your plugin requires new environment variables *and* will be included in the freeIPA built-in plugins, you should add the defaults for your variables in `ipalib.constants.DEFAULT_CONFIG`. Also, you should consider whether your new environment variables should have any auto-magic logic to determine their values if they haven't already been set by the time `config.Env._bootstrap()`, `config.Env._finalize_core()`, or `config.Env._finalize()` is called. On the other hand, if your plugin requires new environment variables and will be installed in a 3rd-party package, your plugin should set these variables in the module it is defined in. `config.Env` values work on a first-one-wins basis... after a value has been set, it can not be overridden with a new value. As any variables can be set using the command-line ``-e`` global option or set in a configuration file, your module must check whether a variable has already been set before setting its default value. For example: >>> if 'message_of_the_day' not in api.env: ... api.env.message_of_the_day = 'Hello, world!' ... Your plugin can access any environment variables via ``self.env``. For example: >>> class motd(Command): ... """Print message of the day.""" ... ... def execute(self, **options): ... return dict(result=self.env.message) ... >>> api = create_api() >>> api.bootstrap(in_server=True, message='Hello, world!') >>> api.register(motd) >>> api.finalize() >>> api.Command.motd(version=u'2.47') {'result': u'Hello, world!'} Also see the `plugable.API.bootstrap_with_global_options()` method. --------------------------------------------- Indispensable ipa script commands and options --------------------------------------------- The ``console`` command will launch a custom interactive Python interpreter session. The global environment will have an ``api`` variable, which is the standard `plugable.API` instance found at ``ipalib.api``. All plugins will have been loaded (well, except the backend plugins if ``in_server`` is False) and ``api`` will be fully initialized. To launch the console from within the top-level directory in the source tree, just run ``ipa console`` from a terminal, like this: :: $ ./ipa console By default, ``in_server`` is False. If you want to start the console in a server context (so that all the backend plugins are loaded), you can use the ``-e`` option to set the ``in_server`` environment variable, like this: :: $ ./ipa -e in_server=True console You can specify multiple environment variables by including the ``-e`` option multiple times, like this: :: $ ./ipa -e in_server=True -e mode=dummy console The space after the ``-e`` is optional. This is equivalent to the above command: :: $ ./ipa -ein_server=True -emode=dummy console The ``env`` command will print out the full environment in key=value pairs, like this: :: $ ./ipa env If you use the ``--server`` option, it will forward the call to the server over XML-RPC and print out what the environment is on the server, like this: :: $ ./ipa env --server The ``plugins`` command will show details of all the plugin that are loaded, like this: :: $ ./ipa plugins ----------------------------------- Learning more about freeIPA plugins ----------------------------------- To learn more about writing freeIPA plugins, you should: 1. Look at some of the built-in plugins, like the frontend plugins in `ipalib.plugins.f_user` and the backend plugins in `ipaserver.plugins.b_ldap`. 2. Learn about the base classes for frontend plugins in `ipalib.frontend`. 3. Learn about the core plugin framework in `ipalib.plugable`. Furthermore, the freeIPA plugin architecture was inspired by the Bazaar plugin architecture. Although the two are different enough that learning how to write plugins for Bazaar will not particularly help you write plugins for freeIPA, some might be interested in the documentation on writing plugins for Bazaar, available here: http://bazaar-vcs.org/WritingPlugins If nothing else, we just want to give credit where credit is deserved! However, freeIPA does not use any *code* from Bazaar... it merely borrows a little inspiration. -------------------------- A note on docstring markup -------------------------- Lastly, a quick note on markup: All the Python docstrings in freeIPA v2 (including this tutorial) use the *reStructuredText* markup language. For information on reStructuredText, see: http://docutils.sourceforge.net/rst.html For information on using reStructuredText markup with epydoc, see: http://epydoc.sourceforge.net/manual-othermarkup.html -------------------------------------------------- Next steps: get involved with freeIPA development! -------------------------------------------------- The freeIPA team is always interested in feedback and contribution from the community. To get involved with freeIPA, see the *Contribute* page on freeIPA.org: http://freeipa.org/page/Contribute iÿÿÿÿN(tBackend(tCommandt LocalOrRemotetUpdatertAdvice(tObjecttMethodtProperty(tCreatetRetrievetUpdatetDeletetSearch( t DefaultFromtBooltFlagtInttDecimaltBytestStrtIA5StrtPasswordtDNParamtDeprecatedParam(t BytesEnumtStrEnumt AccessTimetFile(tSkipPluginModule(t_tngettexttGettextFactorytNGettextFactoryiitalphaitfinals%d.%d.%ds%d.%d.%d.%s.%dtdummycCsRtjtttttttƒ}|dk r<||j _ n|dksNt ‚|S(sA Return standard `plugable.API` instance. This standard instance allows plugins that subclass from the following base classes: - `frontend.Command` - `frontend.Object` - `frontend.Method` - `frontend.Property` - `frontend.Advice` - `backend.Backend` t productionN( tplugabletAPIRRRRRRRtNonetenvtmodetAssertionError(R)tapi((s-/home/mkosek/freeipa-clean/ipalib/__init__.pyt create_api„s   R)tIPA_UNIT_TEST_MODEtcli_test(t cli_pluginstcontexttclit in_servertin_tree(iiiR!i(9t__doc__tosR%tbackendRtfrontendRRRRRRRtcrudRR R R R t parametersR RRRRRRRRRRRRRRterrorsRttextRRRR t version_infot __version__R,R'R+tenvirontgetR1R/tklasstregistert bootstraptFalsetTruetfinalize(((s-/home/mkosek/freeipa-clean/ipalib/__init__.pytps,  "(L""   freeipa-3.3.4/ipalib/output.pyc0000664000175000017500000001047512271707517016037 0ustar mkosekmkosekó ­8 Rc@s”dZddlmZddlmZddlmZmZddlm Z defd„ƒYZ de fd „ƒYZ d Z d e fd „ƒYZ e d de dƒƒZe deefe dƒƒZe dee dƒddgƒZeefZee d ƒefZee d ƒe dee dƒƒe dee dƒƒfZee d ee dƒƒefZee d ee dƒƒefZeZdS(s& Simple description of return values. iÿÿÿÿ(tgetdoc(tNoneType(tReadOnlytlock(t_tOutputcBsAeZdZdZdZdZgZddgd„Zd„Z RS(s Simple description of a member in the return value ``dict``. This class controls both the type of object being returned by a command as well as how the output will be displayed. For example, this class defines two return results: an entry and a value. >>> from ipalib import crud, output >>> class user(crud.Update): ... ... has_output = ( ... output.Entry('result'), ... output.value, ... ) The order of the values in has_output controls the order of output. If you have values that you don't want to be printed then add ``'no_display'`` to flags. The difference between ``'no_display'`` and ``'no_output'`` is that ``'no_output'`` will prevent a Param value from being returned at all. ``'no_display'`` will cause the API to return a value, it simply won't be displayed to the user. This is so some things may be returned that while not interesting to us, but may be to others. >>> from ipalib import crud, output >>> myvalue = output.Output('myvalue', unicode, ... 'Do not print this value', flags=['no_display'], ... ) >>> class user(crud.Update): ... ... has_output = ( ... output.Entry('result'), ... myvalue, ... ) cCsP||_|dk r!||_n|dk r9||_n||_t|ƒdS(N(tnametNonettypetdoctflagsR(tselfRRR R ((s+/home/mkosek/freeipa-clean/ipalib/output.pyt__init__Ks      cCs#d|jj|j|j|jfS(Ns%s(%r, %r, %r)(t __class__t__name__RRR (R ((s+/home/mkosek/freeipa-clean/ipalib/output.pyt__repr__TsN( Rt __module__t__doc__RRtvalidateR R R R(((s+/home/mkosek/freeipa-clean/ipalib/output.pyRs& tEntrycBseZeZedƒZRS(s'A dictionary representing an LDAP entry(RRtdictRRR (((s+/home/mkosek/freeipa-clean/ipalib/output.pyRZssP%s.validate_output() => %s.validate(): output[%r][%d]: need a %r; got a %r: %rt ListOfEntriescBs)eZeefZedƒZd„ZRS(sA list of LDAP entriesc Cs‚t||jƒst‚xct|ƒD]U\}}t|tƒs%tt|j|jj |j|tt|ƒ|fƒ‚q%q%WdS(N( t isinstanceRtAssertionErrort enumerateRt TypeErrortemsgRR R(R tcmdtentriestitentry((s+/home/mkosek/freeipa-clean/ipalib/output.pyRfs (RRtlistttupleRRR R(((s+/home/mkosek/freeipa-clean/ipalib/output.pyRbs  tresultR s*All commands should at least have a resulttsummarys-User-friendly description of action performedtvalues:The primary_key value of the entry, e.g. 'jdoe' for a userR t no_displaytcountsNumber of entries returnedt truncateds%True if not all results were returnedsList of deletions that faileds'True means the operation was successfulN(RtinspectRttypesRtplugableRRttextRRRRRR!tunicodeR"R#tstandardtstandard_entrytinttbooltstandard_list_of_entriesRtstandard_deletetstandard_booleantstandard_value(((s+/home/mkosek/freeipa-clean/ipalib/output.pyts:<          freeipa-3.3.4/ipalib/backend.py0000664000175000017500000001126312270466515015716 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Base classes for all backed-end plugins. """ import threading import plugable import os from errors import PublicError, InternalError, CommandError from request import context, Connection, destroy_context class Backend(plugable.Plugin): """ Base class for all backend plugins. """ class Connectible(Backend): """ Base class for backend plugins that create connections. In addition to the nicety of providing a standard connection API, all backend plugins that create connections should use this base class so that `request.destroy_context()` can properly close all open connections. """ def __init__(self, shared_instance=True): Backend.__init__(self) if shared_instance: self.id = self.name else: self.id = '%s_%s' % (self.name, str(id(self))) def connect(self, *args, **kw): """ Create thread-local connection. """ if hasattr(context, self.id): raise StandardError( "connect: 'context.%s' already exists in thread %r" % ( self.id, threading.currentThread().getName() ) ) conn = self.create_connection(*args, **kw) setattr(context, self.id, Connection(conn, self.disconnect)) assert self.conn is conn self.debug('Created connection context.%s' % self.id) def create_connection(self, *args, **kw): raise NotImplementedError('%s.create_connection()' % self.id) def disconnect(self): if not hasattr(context, self.id): raise StandardError( "disconnect: 'context.%s' does not exist in thread %r" % ( self.id, threading.currentThread().getName() ) ) self.destroy_connection() delattr(context, self.id) self.debug('Destroyed connection context.%s' % self.id) def destroy_connection(self): raise NotImplementedError('%s.destroy_connection()' % self.id) def isconnected(self): """ Return ``True`` if thread-local connection on `request.context` exists. """ return hasattr(context, self.id) def __get_conn(self): """ Return thread-local connection. """ if not hasattr(context, self.id): raise AttributeError('no context.%s in thread %r' % ( self.id, threading.currentThread().getName()) ) return getattr(context, self.id).conn conn = property(__get_conn) class Executioner(Backend): def create_context(self, ccache=None, client_ip=None): """ client_ip: The IP address of the remote client. """ if ccache is not None: os.environ["KRB5CCNAME"] = ccache if self.env.in_server: self.Backend.ldap2.connect(ccache=ccache) else: self.Backend.xmlclient.connect(verbose=(self.env.verbose >= 2), fallback=self.env.fallback, delegate=self.env.delegate) if client_ip is not None: setattr(context, "client_ip", client_ip) def destroy_context(self): destroy_context() def execute(self, _name, *args, **options): error = None try: if _name not in self.Command: raise CommandError(name=_name) result = self.Command[_name](*args, **options) except PublicError, e: error = e except StandardError, e: self.exception( 'non-public: %s: %s', e.__class__.__name__, str(e) ) error = InternalError() except Exception, e: self.exception( 'unhandled exception: %s: %s', e.__class__.__name__, str(e) ) error = InternalError() destroy_context() if error is None: return result assert isinstance(error, PublicError) raise error #pylint: disable=E0702 freeipa-3.3.4/ipalib/util.py0000664000175000017500000004225212271663206015303 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Various utility functions. """ import os import imp import time import socket import re import decimal import netaddr from types import NoneType from weakref import WeakKeyDictionary from dns import resolver, rdatatype from dns.exception import DNSException from ipalib import errors from ipalib.text import _ from ipapython.ssh import SSHPublicKey from ipapython.dn import DN, RDN def json_serialize(obj): if isinstance(obj, (list, tuple)): return [json_serialize(o) for o in obj] if isinstance(obj, dict): return dict((k, json_serialize(v)) for (k, v) in obj.iteritems()) if isinstance(obj, (bool, float, int, long, unicode, NoneType)): return obj if isinstance(obj, str): return obj.decode('utf-8') if isinstance(obj, (decimal.Decimal, DN)): return str(obj) if not callable(getattr(obj, '__json__', None)): # raise TypeError('%r is not JSON serializable') return '' return json_serialize(obj.__json__()) def get_current_principal(): try: # krbV isn't necessarily available on client machines, fail gracefully import krbV return unicode(krbV.default_context().default_ccache().principal().name) except ImportError: raise RuntimeError('python-krbV is not available.') except krbV.Krb5Error: #TODO: do a kinit? raise errors.CCacheError() # FIXME: This function has no unit test def find_modules_in_dir(src_dir): """ Iterate through module names found in ``src_dir``. """ if not (os.path.abspath(src_dir) == src_dir and os.path.isdir(src_dir)): return if os.path.islink(src_dir): return suffix = '.py' for name in sorted(os.listdir(src_dir)): if not name.endswith(suffix): continue pyfile = os.path.join(src_dir, name) if os.path.islink(pyfile) or not os.path.isfile(pyfile): continue module = name[:-len(suffix)] if module == '__init__': continue yield (module, pyfile) def validate_host_dns(log, fqdn): """ See if the hostname has a DNS A record. """ try: answers = resolver.query(fqdn, rdatatype.A) log.debug( 'IPA: found %d records for %s: %s' % (len(answers), fqdn, ' '.join(str(answer) for answer in answers)) ) except DNSException, e: log.debug( 'IPA: DNS A record lookup failed for %s' % fqdn ) raise errors.DNSNotARecordError() def has_soa_or_ns_record(domain): """ Checks to see if given domain has SOA or NS record. Returns True or False. """ try: resolver.query(domain, rdatatype.SOA) soa_record_found = True except DNSException: soa_record_found = False try: resolver.query(domain, rdatatype.NS) ns_record_found = True except DNSException: ns_record_found = False return soa_record_found or ns_record_found def normalize_name(name): result = dict() components = name.split('@') if len(components) == 2: result['domain'] = unicode(components[1]).lower() result['name'] = unicode(components[0]).lower() else: components = name.split('\\') if len(components) == 2: result['flatname'] = unicode(components[0]).lower() result['name'] = unicode(components[1]).lower() else: result['name'] = unicode(name).lower() return result def isvalid_base64(data): """ Validate the incoming data as valid base64 data or not. The character set must only include of a-z, A-Z, 0-9, + or / and be padded with = to be a length divisible by 4 (so only 0-2 =s are allowed). Its length must be divisible by 4. White space is not significant so it is removed. This doesn't guarantee we have a base64-encoded value, just that it fits the base64 requirements. """ data = ''.join(data.split()) if len(data) % 4 > 0 or \ re.match('^[a-zA-Z0-9\+\/]+\={0,2}$', data) is None: return False else: return True def validate_ipaddr(ipaddr): """ Check to see if the given IP address is a valid IPv4 or IPv6 address. Returns True or False """ try: socket.inet_pton(socket.AF_INET, ipaddr) except socket.error: try: socket.inet_pton(socket.AF_INET6, ipaddr) except socket.error: return False return True def check_writable_file(filename): """ Determine if the file is writable. If the file doesn't exist then open the file to test writability. """ if filename is None: raise errors.FileError(reason=_('Filename is empty')) try: if os.path.exists(filename): if not os.access(filename, os.W_OK): raise errors.FileError(reason=_('Permission denied: %(file)s') % dict(file=filename)) else: fp = open(filename, 'w') fp.close() except (IOError, OSError), e: raise errors.FileError(reason=str(e)) def normalize_zonemgr(zonemgr): if not zonemgr: # do not normalize empty or None value return zonemgr if '@' in zonemgr: # local-part needs to be normalized name, at, domain = zonemgr.partition('@') name = name.replace('.', '\\.') zonemgr = u''.join((name, u'.', domain)) if not zonemgr.endswith('.'): zonemgr = zonemgr + u'.' return zonemgr def normalize_zone(zone): if zone[-1] != '.': return zone + '.' else: return zone def validate_dns_label(dns_label, allow_underscore=False): label_chars = r'a-z0-9' underscore_err_msg = '' if allow_underscore: label_chars += "_" underscore_err_msg = u' _,' label_regex = r'^[%(chars)s]([%(chars)s-]?[%(chars)s])*$' % dict(chars=label_chars) regex = re.compile(label_regex, re.IGNORECASE) if not dns_label: raise ValueError(_('empty DNS label')) if len(dns_label) > 63: raise ValueError(_('DNS label cannot be longer that 63 characters')) if not regex.match(dns_label): raise ValueError(_('only letters, numbers,%(underscore)s and - are allowed. ' \ 'DNS label may not start or end with -') \ % dict(underscore=underscore_err_msg)) def validate_domain_name(domain_name, allow_underscore=False): if domain_name.endswith('.'): domain_name = domain_name[:-1] domain_name = domain_name.split(".") # apply DNS name validator to every name part map(lambda label:validate_dns_label(label,allow_underscore), domain_name) def validate_zonemgr(zonemgr): """ See RFC 1033, 1035 """ regex_local_part = re.compile(r'^[a-z0-9]([a-z0-9-_]?[a-z0-9])*$', re.IGNORECASE) local_part_errmsg = _('mail account may only include letters, numbers, -, _ and a dot. There may not be consecutive -, _ and . characters. Its parts may not start or end with - or _') local_part_sep = '.' local_part = None domain = None if len(zonemgr) > 255: raise ValueError(_('cannot be longer that 255 characters')) if zonemgr.endswith('.'): zonemgr = zonemgr[:-1] if zonemgr.count('@') == 1: local_part, dot, domain = zonemgr.partition('@') elif zonemgr.count('@') > 1: raise ValueError(_('too many \'@\' characters')) else: last_fake_sep = zonemgr.rfind('\\.') if last_fake_sep != -1: # there is a 'fake' local-part/domain separator local_part_sep = '\\.' sep = zonemgr.find('.', last_fake_sep+2) if sep != -1: local_part = zonemgr[:sep] domain = zonemgr[sep+1:] else: local_part, dot, domain = zonemgr.partition('.') if not domain: raise ValueError(_('missing address domain')) validate_domain_name(domain) if not local_part: raise ValueError(_('missing mail account')) if not all(regex_local_part.match(part) for part in \ local_part.split(local_part_sep)): raise ValueError(local_part_errmsg) def validate_hostname(hostname, check_fqdn=True, allow_underscore=False): """ See RFC 952, 1123 :param hostname Checked value :param check_fqdn Check if hostname is fully qualified """ if len(hostname) > 255: raise ValueError(_('cannot be longer that 255 characters')) if hostname.endswith('.'): hostname = hostname[:-1] if '..' in hostname: raise ValueError(_('hostname contains empty label (consecutive dots)')) if '.' not in hostname: if check_fqdn: raise ValueError(_('not fully qualified')) validate_dns_label(hostname,allow_underscore) else: validate_domain_name(hostname,allow_underscore) def normalize_sshpubkey(value): return SSHPublicKey(value).openssh() def validate_sshpubkey(ugettext, value): try: SSHPublicKey(value) except ValueError, UnicodeDecodeError: return _('invalid SSH public key') def validate_sshpubkey_no_options(ugettext, value): try: pubkey = SSHPublicKey(value) except ValueError, UnicodeDecodeError: return _('invalid SSH public key') if pubkey.has_options(): return _('options are not allowed') def convert_sshpubkey_post(ldap, dn, entry_attrs): if 'ipasshpubkey' in entry_attrs: pubkeys = entry_attrs['ipasshpubkey'] else: old_entry_attrs = ldap.get_entry(dn, ['ipasshpubkey']) pubkeys = old_entry_attrs[1].get('ipasshpubkey') if not pubkeys: return newpubkeys = [] fingerprints = [] for pubkey in pubkeys: try: pubkey = SSHPublicKey(pubkey) except ValueError, UnicodeDecodeError: continue fp = pubkey.fingerprint_hex_md5() comment = pubkey.comment() if comment: fp = u'%s %s' % (fp, comment) fp = u'%s (%s)' % (fp, pubkey.keytype()) newpubkeys.append(pubkey.openssh()) fingerprints.append(fp) if 'ipasshpubkey' in entry_attrs: entry_attrs['ipasshpubkey'] = newpubkeys or None if fingerprints: entry_attrs['sshpubkeyfp'] = fingerprints class cachedproperty(object): """ A property-like attribute that caches the return value of a method call. When the attribute is first read, the method is called and its return value is saved and returned. On subsequent reads, the saved value is returned. Typical usage: class C(object): @cachedproperty def attr(self): return 'value' """ __slots__ = ('getter', 'store') def __init__(self, getter): self.getter = getter self.store = WeakKeyDictionary() def __get__(self, obj, cls): if obj is None: return None if obj not in self.store: self.store[obj] = self.getter(obj) return self.store[obj] def __set__(self, obj, value): raise AttributeError("can't set attribute") def __delete__(self, obj): raise AttributeError("can't delete attribute") # regexp matching signed floating point number (group 1) followed by # optional whitespace followed by time unit, e.g. day, hour (group 7) time_duration_re = re.compile(r'([-+]?((\d+)|(\d+\.\d+)|(\.\d+)|(\d+\.)))\s*([a-z]+)', re.IGNORECASE) # number of seconds in a time unit time_duration_units = { 'year' : 365*24*60*60, 'years' : 365*24*60*60, 'y' : 365*24*60*60, 'month' : 30*24*60*60, 'months' : 30*24*60*60, 'week' : 7*24*60*60, 'weeks' : 7*24*60*60, 'w' : 7*24*60*60, 'day' : 24*60*60, 'days' : 24*60*60, 'd' : 24*60*60, 'hour' : 60*60, 'hours' : 60*60, 'h' : 60*60, 'minute' : 60, 'minutes' : 60, 'min' : 60, 'second' : 1, 'seconds' : 1, 'sec' : 1, 's' : 1, } def parse_time_duration(value): ''' Given a time duration string, parse it and return the total number of seconds represented as a floating point value. Negative values are permitted. The string should be composed of one or more numbers followed by a time unit. Whitespace and punctuation is optional. The numbers may be optionally signed. The time units are case insenstive except for the single character 'M' or 'm' which means month and minute respectively. Recognized time units are: * year, years, y * month, months, M * week, weeks, w * day, days, d * hour, hours, h * minute, minutes, min, m * second, seconds, sec, s Examples: "1h" # 1 hour "2 HOURS, 30 Minutes" # 2.5 hours "1week -1 day" # 6 days ".5day" # 12 hours "2M" # 2 months "1h:15m" # 1.25 hours "1h, -15min" # 45 minutes "30 seconds" # .5 minute Note: Despite the appearance you can perform arithmetic the parsing is much simpler, the parser searches for signed values and adds the signed value to a running total. Only + and - are permitted and must appear prior to a digit. :parameters: value : string A time duration string in the specified format :returns: total number of seconds as float (may be negative) ''' matches = 0 duration = 0.0 for match in time_duration_re.finditer(value): matches += 1 magnitude = match.group(1) unit = match.group(7) # Get the unit, only M and m are case sensitive if unit == 'M': # month seconds_per_unit = 30*24*60*60 elif unit == 'm': # minute seconds_per_unit = 60 else: unit = unit.lower() seconds_per_unit = time_duration_units.get(unit) if seconds_per_unit is None: raise ValueError('unknown time duration unit "%s"' % unit) magnitude = float(magnitude) seconds = magnitude * seconds_per_unit duration += seconds if matches == 0: raise ValueError('no time duration found in "%s"' % value) return duration def get_dns_forward_zone_update_policy(realm, rrtypes=('A', 'AAAA', 'SSHFP')): """ Generate update policy for a forward DNS zone (idnsUpdatePolicy attribute). Bind uses this policy to grant/reject access for client machines trying to dynamically update their records. :param realm: A realm of the of the client :param rrtypes: A list of resource records types that client shall be allowed to update """ policy_element = "grant %(realm)s krb5-self * %(rrtype)s" policies = [ policy_element % dict(realm=realm, rrtype=rrtype) \ for rrtype in rrtypes ] policy = "; ".join(policies) policy += ";" return policy def get_dns_reverse_zone_update_policy(realm, reverse_zone, rrtypes=('PTR',)): """ Generate update policy for a reverse DNS zone (idnsUpdatePolicy attribute). Bind uses this policy to grant/reject access for client machines trying to dynamically update their records. :param realm: A realm of the of the client :param reverse_zone: Name of the actual zone. All clients with IPs in this sub-domain will be allowed to perform changes :param rrtypes: A list of resource records types that client shall be allowed to update """ policy_element = "grant %(realm)s krb5-subdomain %(zone)s %(rrtype)s" policies = [ policy_element \ % dict(realm=realm, zone=reverse_zone, rrtype=rrtype) \ for rrtype in rrtypes ] policy = "; ".join(policies) policy += ";" return policy # dictionary of valid reverse zone -> number of address components REVERSE_DNS_ZONES = { '.in-addr.arpa.' : 4, '.ip6.arpa.' : 32, } def zone_is_reverse(zone_name): zone_name = normalize_zone(zone_name) if any(zone_name.endswith(name) for name in REVERSE_DNS_ZONES): return True return False def get_reverse_zone_default(ip_address): ip = netaddr.IPAddress(str(ip_address)) items = ip.reverse_dns.split('.') if ip.version == 4: items = items[1:] # /24 for IPv4 elif ip.version == 6: items = items[16:] # /64 for IPv6 return normalize_zone('.'.join(items)) def validate_rdn_param(ugettext, value): try: rdn = RDN(value) except Exception, e: return str(e) return None freeipa-3.3.4/ipalib/x509.py0000664000175000017500000001703112271663206015030 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2010 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 . # Certificates should be stored internally DER-encoded. We can be passed # a certificate several ways: read if from LDAP, read it from a 3rd party # app (dogtag, candlepin, etc) or as user input. The normalize_certificate() # function will convert an incoming certificate to DER-encoding. # Conventions # # Where possible the following naming conventions are used: # # cert: the certificate is a PEM-encoded certificate # dercert: the certificate is DER-encoded # nsscert: the certificate is an NSS Certificate object # rawcert: the cert is in an unknown format import os import sys import base64 import re import nss.nss as nss from nss.error import NSPRError from ipapython import ipautil from ipalib import api from ipalib import _ from ipalib import util from ipalib import errors from ipapython.dn import DN PEM = 0 DER = 1 PEM_REGEX = re.compile(r'(?<=-----BEGIN CERTIFICATE-----).*?(?=-----END CERTIFICATE-----)', re.DOTALL) _subject_base = None def subject_base(): global _subject_base if _subject_base is None: config = api.Command['config_show']()['result'] _subject_base = DN(config['ipacertificatesubjectbase'][0]) return _subject_base def valid_issuer(issuer): if not api.env.enable_ra: return True # Handle all supported forms of issuer -- currently dogtag only. if api.env.ra_plugin == 'dogtag': return DN(issuer) == DN(('CN', 'Certificate Authority'), subject_base()) return True def strip_header(pem): """ Remove the header and footer from a certificate. """ s = pem.find("-----BEGIN CERTIFICATE-----") if s >= 0: e = pem.find("-----END CERTIFICATE-----") pem = pem[s+27:e] return pem def load_certificate(data, datatype=PEM, dbdir=None): """ Given a base64-encoded certificate, with or without the header/footer, return a request object. Returns a nss.Certificate type """ if type(data) in (tuple, list): data = data[0] if (datatype == PEM): data = strip_header(data) data = base64.b64decode(data) if not nss.nss_is_initialized(): if dbdir is None: if 'in_tree' in api.env: if api.env.in_tree: dbdir = api.env.dot_ipa + os.sep + 'alias' else: dbdir = "/etc/httpd/alias" nss.nss_init(dbdir) else: nss.nss_init_nodb() else: nss.nss_init(dbdir) return nss.Certificate(buffer(data)) def load_certificate_chain_from_file(filename, dbdir=None): """ Load a certificate chain from a PEM file. Returns a list of nss.Certificate objects. """ fd = open(filename, 'r') data = fd.read() fd.close() chain = PEM_REGEX.findall(data) chain = [load_certificate(cert, PEM, dbdir) for cert in chain] return chain def load_certificate_from_file(filename, dbdir=None): """ Load a certificate from a PEM file. Returns a nss.Certificate type """ fd = open(filename, 'r') data = fd.read() fd.close() return load_certificate(data, PEM, dbdir) def get_subject(certificate, datatype=PEM, dbdir=None): """ Load an X509.3 certificate and get the subject. """ nsscert = load_certificate(certificate, datatype, dbdir) subject = nsscert.subject del(nsscert) return subject def get_issuer(certificate, datatype=PEM, dbdir=None): """ Load an X509.3 certificate and get the issuer. """ nsscert = load_certificate(certificate, datatype, dbdir) issuer = nsscert.issuer del(nsscert) return issuer def get_serial_number(certificate, datatype=PEM, dbdir=None): """ Return the decimal value of the serial number. """ nsscert = load_certificate(certificate, datatype, dbdir) serial_number = nsscert.serial_number del(nsscert) return serial_number def make_pem(data): """ Convert a raw base64-encoded blob into something that looks like a PE file with lines split to 64 characters and proper headers. """ pemcert = '\n'.join([data[x:x+64] for x in range(0, len(data), 64)]) return '-----BEGIN CERTIFICATE-----\n' + \ pemcert + \ '\n-----END CERTIFICATE-----' def normalize_certificate(rawcert): """ Incoming certificates should be DER-encoded. If not it is converted to DER-format. Note that this can't be a normalizer on a Param because only unicode variables are normalized. """ if not rawcert: return None rawcert = strip_header(rawcert) if util.isvalid_base64(rawcert): try: dercert = base64.b64decode(rawcert) except Exception, e: raise errors.Base64DecodeError(reason=str(e)) else: dercert = rawcert # At this point we should have a certificate, either because the data # was base64-encoded and now its not or it came in as DER format. # Let's decode it and see. Fetching the serial number will pass the # certificate through the NSS DER parser. try: serial = unicode(get_serial_number(dercert, DER)) except NSPRError, nsprerr: if nsprerr.errno == -8183: # SEC_ERROR_BAD_DER raise errors.CertificateFormatError( error=_('improperly formatted DER-encoded certificate')) else: raise errors.CertificateFormatError(error=str(nsprerr)) return dercert def write_certificate(rawcert, filename): """ Write the certificate to a file in PEM format. The cert value can be either DER or PEM-encoded, it will be normalized to DER regardless, then back out to PEM. """ dercert = normalize_certificate(rawcert) try: fp = open(filename, 'w') fp.write(make_pem(base64.b64encode(dercert))) fp.close() except (IOError, OSError), e: raise errors.FileError(reason=str(e)) def verify_cert_subject(ldap, hostname, dercert): """ Verify that the certificate issuer we're adding matches the issuer base of our installation. This assumes the certificate has already been normalized. This raises an exception on errors and returns nothing otherwise. """ nsscert = load_certificate(dercert, datatype=DER) subject = str(nsscert.subject) issuer = str(nsscert.issuer) del(nsscert) if (not valid_issuer(issuer)): raise errors.CertificateOperationError(error=_('Issuer "%(issuer)s" does not match the expected issuer') % \ {'issuer' : issuer}) if __name__ == '__main__': # this can be run with: # python ipalib/x509.py < /etc/ipa/ca.crt from ipalib import api api.bootstrap() api.finalize() nss.nss_init_nodb() # Read PEM certs from stdin and print out its components certlines = sys.stdin.readlines() cert = ''.join(certlines) nsscert = load_certificate(cert) print nsscert freeipa-3.3.4/ipalib/x509.pyc0000664000175000017500000001615212271707517015202 0ustar mkosekmkosekó †fçRc@sÙddlZddlZddlZddlZddljZddlmZddlm Z ddl m Z ddl m Z ddl m Z ddl mZddlmZd Zd Zejd ejƒZdad „Zd „Zd„Zedd„Zdd„Zdd„Zedd„Zedd„Zedd„Z d„Z!d„Z"d„Z#d„Z$e%dkrÕddl m Z e j&ƒe j'ƒej(ƒej)j*ƒZ+dj,e+ƒZ-ee-ƒZ.e.GHndS(iÿÿÿÿN(t NSPRError(tipautil(tapi(t_(tutil(terrors(tDNiis@(?<=-----BEGIN CERTIFICATE-----).*?(?=-----END CERTIFICATE-----)cCs;tdkr7tjdƒd}t|ddƒantS(Nt config_showtresulttipacertificatesubjectbasei(t _subject_basetNoneRtCommandR(tconfig((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt subject_base6s cCsBtjjstStjjdkr>t|ƒtdtƒƒkStS(NtdogtagtCNsCertificate Authority(RsCertificate Authority(Rtenvt enable_ratTruet ra_pluginRR(tissuer((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt valid_issuer?s  cCsB|jdƒ}|dkr>|jdƒ}||d|!}n|S(s: Remove the header and footer from a certificate. s-----BEGIN CERTIFICATE-----is-----END CERTIFICATE-----i(tfind(tpemtste((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt strip_headerGs  cCsât|ƒttfkr%|d}n|tkrOt|ƒ}tj|ƒ}ntjƒsÏ|dkr¿dt j kr²t j j rœt j j tjd}nd}tj|ƒqÌtjƒqÏtj|ƒntjt|ƒƒS(s‘ Given a base64-encoded certificate, with or without the header/footer, return a request object. Returns a nss.Certificate type itin_treetaliass/etc/httpd/aliasN(ttypettupletlisttPEMRtbase64t b64decodetnsstnss_is_initializedR RRRtdot_ipatostseptnss_initt nss_init_nodbt Certificatetbuffer(tdatatdatatypetdbdir((s)/home/mkosek/freeipa-clean/ipalib/x509.pytload_certificateRs       cCs]t|dƒ}|jƒ}|jƒtj|ƒ}g|D]}t|t|ƒ^q;}|S(sc Load a certificate chain from a PEM file. Returns a list of nss.Certificate objects. tr(topentreadtcloset PEM_REGEXtfindallR0R!(tfilenameR/tfdR-tchaintcert((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt load_certificate_chain_from_fileos   %cCs5t|dƒ}|jƒ}|jƒt|t|ƒS(sQ Load a certificate from a PEM file. Returns a nss.Certificate type R1(R2R3R4R0R!(R7R/R8R-((s)/home/mkosek/freeipa-clean/ipalib/x509.pytload_certificate_from_file~s  cCs"t|||ƒ}|j}~|S(s9 Load an X509.3 certificate and get the subject. (R0tsubject(t certificateR.R/tnsscertR=((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt get_subjectŠs cCs"t|||ƒ}|j}~|S(s8 Load an X509.3 certificate and get the issuer. (R0R(R>R.R/R?R((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt get_issuer”s cCs"t|||ƒ}|j}~|S(s8 Return the decimal value of the serial number. (R0t serial_number(R>R.R/R?RB((s)/home/mkosek/freeipa-clean/ipalib/x509.pytget_serial_numberžs cCsKdjgtdt|ƒdƒD]}|||d!^qƒ}d|dS(sŽ Convert a raw base64-encoded blob into something that looks like a PE file with lines split to 64 characters and proper headers. s ii@s-----BEGIN CERTIFICATE----- s -----END CERTIFICATE-----(tjointrangetlen(R-txtpemcert((s)/home/mkosek/freeipa-clean/ipalib/x509.pytmake_pem§s?cCsä|s dSt|ƒ}tj|ƒriytj|ƒ}Wqotk re}tjdt |ƒƒ‚qoXn|}yt t |t ƒƒ}WnUt k rß}|jdkrÄtjdtdƒƒ‚qàtjdt |ƒƒ‚nX|S(sÈ Incoming certificates should be DER-encoded. If not it is converted to DER-format. Note that this can't be a normalizer on a Param because only unicode variables are normalized. treasoni àÿÿterrors,improperly formatted DER-encoded certificateN(R RRtisvalid_base64R"R#t ExceptionRtBase64DecodeErrortstrtunicodeRCtDERRterrnotCertificateFormatErrorR(trawcerttdercertRtserialtnsprerr((s)/home/mkosek/freeipa-clean/ipalib/x509.pytnormalize_certificate±s"  cCs}t|ƒ}y9t|dƒ}|jttj|ƒƒƒ|jƒWn1ttfk rx}t j dt |ƒƒ‚nXdS(s± Write the certificate to a file in PEM format. The cert value can be either DER or PEM-encoded, it will be normalized to DER regardless, then back out to PEM. twRJN( RXR2twriteRIR"t b64encodeR4tIOErrortOSErrorRt FileErrorRO(RTR7RUtfpR((s)/home/mkosek/freeipa-clean/ipalib/x509.pytwrite_certificateÕs cCsit|dtƒ}t|jƒ}t|jƒ}~t|ƒsetjdtdƒi|d6ƒ‚ndS(sð Verify that the certificate issuer we're adding matches the issuer base of our installation. This assumes the certificate has already been normalized. This raises an exception on errors and returns nothing otherwise. R.RKs6Issuer "%(issuer)s" does not match the expected issuerRN( R0RQROR=RRRtCertificateOperationErrorR(tldapthostnameRUR?R=R((s)/home/mkosek/freeipa-clean/ipalib/x509.pytverify_cert_subjectås  t__main__t(/R'tsysR"tretnss.nssR$t nss.errorRt ipapythonRtipalibRRRRt ipapython.dnRR!RQtcompiletDOTALLR5R R RRRR0R;R<R@RARCRIRXR`Rdt__name__t bootstraptfinalizeR*tstdint readlinest certlinesRDR:R?(((s)/home/mkosek/freeipa-clean/ipalib/x509.pyt"sJ           $       freeipa-3.3.4/ipalib/constants.pyc0000664000175000017500000001366512271707517016517 0ustar mkosekmkosekó †fçRcT@sŠdZddlZddlmZddlmZyejƒZWn'yejƒZWqldZqlXnXddde ƒgfZ dZ dZ d Zd Zd Zd Zd ZdZdZdefdždŸded d¡ƒfded¢ƒfded£d¤ƒfded¥d¦ƒfd ed§d¨ƒfd"ed©dªƒfd$ed«d¬ƒfd&ed­d®ƒfd(ed¯d°ƒfd+ed±d²ƒfd-ed³ƒfd/ed´ƒfd1edµd¶ƒfd3ed·d¸ƒfd4ed¹dºd»ƒfd6ed¼d½d¾ƒfd8ed¿dÀdÁƒfd:edÂdÃfd=edăfd?edÅdƃfdAedÇdȃfdCedɃfdEedÊd˃fdHedÌd̓fdKedÎdσfdMedÐdуfdOedÒdÓƒfdQedÔdÕƒfdTedÖd׃fdVedØdÙƒfdXedÚƒfdZedÛd܃fd[edÝdÞƒfd]edßdàdáƒfd`edâdãdädåƒfdbedædçdèƒfddedéƒfdêdëdìdídîdpefdïdðdñdwefdxefdòd{efdódôdõdöd÷død„efd…efd†efd‡efdˆefdùdúdefdŽefdefdefd‘efd’efd“efd”efd•efd–efd—efd˜efd™efdšefd›efdœefdeffSZdS(ûs( All constants centralised in one file. iÿÿÿÿN(tDN(tVERSIONtus!^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$sname must match '%s'; got '%s's%s: need a %r; got %r (a %r)s+%s: need a callable; got %r (which is a %r)s&cannot override %s.%s value %r with %rslocked: cannot set %s.%s to %rslocked: cannot delete %s.%ss tglobaltversiontdomains example.comtrealms EXAMPLE.COMtbasedntdctexampletcomtcontainer_accountstcntaccountstcontainer_usertuserstcontainer_grouptgroupstcontainer_servicetservicestcontainer_hostt computerstcontainer_hostgroupt hostgroupstcontainer_rolegrouptrolestcontainer_permissiont permissionstpbactcontainer_privileget privilegestcontainer_automountt automounttcontainer_policiestpoliciestcontainer_configstconfigstcontainer_rolestcontainer_applicationst applicationstcontainer_policygroupst policygroupstcontainer_policylinkst policylinkstcontainer_netgrouptngtalttcontainer_hbacthbactcontainer_hbacservicet hbacservicestcontainer_hbacservicegroupthbacservicegroupst container_dnstdnstcontainer_virtualsvirtual operationstetctcontainer_sudorulet sudorulestsudotcontainer_sudocmdtsudocmdstcontainer_sudocmdgroupt sudocmdgroupstcontainer_automembert automembertcontainer_selinuxtusermaptselinuxtcontainer_s4u2proxyt s4u2proxytcontainer_cifsdomainstadtcontainer_truststtruststcontainer_adtruststcontainer_rangestrangest container_dnatdnatipatcontainer_dna_posix_idss posix-idstcontainer_realm_domainss Realm Domainst container_otptotpt xmlrpc_urishttp://localhost:8888/ipa/xmlt rpc_json_urishttp://localhost:8888/ipa/jsontldap_urisldap://localhost:389tstartup_timeouti,t mount_ipas/ipa/t webui_prodtsession_auth_durations 20 minutestsession_duration_typetinactivity_timeouttverboseitdebugtstartup_tracebacktmodet productiontca_hosttca_portiPt ca_agent_porti»t ca_ee_porttca_install_porttca_agent_install_porttca_ee_install_portt prompt_allt interactivetfallbacktdelegatet enable_rat ra_plugintselfsigntdogtag_versioni t validate_apithosttipalibt site_packagestscripttbinthometin_treetdot_ipatcontexttconfdirtconft conf_defaulttplugins_on_demandt in_servertlogdirtlog(sdomains example.com(Rs EXAMPLE.COM(RR (RR (R R (R R(R R (R sgroups(R R (R R(R R (R R(R R (R R(R R (R R(R R (R R(R R(R R(R R(R R (R R"(R R$(R R"(R R(R R"(R R'(R R$(R R"(R R)(R R$(R R"(R R+(R R$(R R"(R sng(R R.(R R0(R R2(R R0(R R4(R R0(R R6(R svirtual operations(R R8(R R:(R R;(R R=(R R;(R R?(R R;(R RA(R R8(R RC(R RD(R RF(R R8(R RH(R R8(R RJ(R RH(R RJ(R RM(R R8(R RO(R sipa(R R8(R s posix-ids(R RO(R sipa(R R8(R s Realm Domains(R sipa(R R8(R RT(RUshttp://localhost:8888/ipa/xml(RVshttp://localhost:8888/ipa/json(RWsldap://localhost:389(RXi,(RYs/ipa/(R[s 20 minutes(R\R](sverbosei(smodes production(RdiP(Rei»(Rfi»(RgN(RhN(RiN(RoRp(Rqi (t__doc__tsockett ipapython.dnRtipapython.versionRtgetfqdntFQDNt gethostnametNonettupletNULLSt NAME_REGEXt NAME_ERRORt TYPE_ERRORtCALLABLE_ERRORtOVERRIDE_ERRORt SET_ERRORt DEL_ERRORtCLI_TABtCONFIG_SECTIONtTruetFalsetobjecttDEFAULT_CONFIG(((s./home/mkosek/freeipa-clean/ipalib/constants.pytsÎ                           freeipa-3.3.4/ipalib/pkcs10.pyc0000664000175000017500000000425612271707517015600 0ustar mkosekmkosekó ­8 Rc@såddlZddlZddlZddljZddlmZddlmZdZ dZ d„Z d„Z d„Z d „Zed kráejƒejjƒZd jeƒZeeƒZeGHe eƒGHe eƒGHndS( iÿÿÿÿN(tipautil(tapiiicCs:x3|jD](}|jtjkr tj|jƒSq WdS(sr Given a CSR return the subjectaltname value, if any. The return value is a tuple of strings or None N(t extensionstoid_tagtnsstSEC_OID_X509_SUBJECT_ALT_NAMEt x509_alt_nametvaluetNone(trequestt extension((s+/home/mkosek/freeipa-clean/ipalib/pkcs10.pytget_subjectaltnamescCs|jS(sS Given a CSR return the subject value. This returns an nss.DN object. (tsubject(R ((s+/home/mkosek/freeipa-clean/ipalib/pkcs10.pyt get_subject)scCsld}|jdƒ}|dkr9d}|jdƒ}n|dkrh|jdƒ}||||!}n|S(s2 Remove the header and footer from a CSR. i(s'-----BEGIN NEW CERTIFICATE REQUEST-----iÿÿÿÿi$s#-----BEGIN CERTIFICATE REQUEST-----is-----END(tfind(tcsrt headerlentste((s+/home/mkosek/freeipa-clean/ipalib/pkcs10.pyt strip_header1s  cCsAt|ƒ}tj|ƒ}tjƒs4tjƒntj|ƒS(su Given a base64-encoded certificate request, with or without the header/footer, return a request object. (Rtbase64t b64decodeRtnss_is_initializedt nss_init_nodbtCertificateRequest(Rt substrate((s+/home/mkosek/freeipa-clean/ipalib/pkcs10.pytload_certificate_request@s    t__main__t(tostsysRtnss.nssRt ipapythonRtipalibRtPEMtDERR R RRt__name__Rtstdint readlinestcsrlinestjoinR(((s+/home/mkosek/freeipa-clean/ipalib/pkcs10.pyts&          freeipa-3.3.4/ipalib/krb_utils.pyc0000664000175000017500000002672612271707517016503 0ustar mkosekmkosekó †fçRc@sÉddlZddlZddlZddlTdZdZdZdZdZdZ d Z d Z dZ d Z ejdƒZd„Zd„Zd„Zd„Zd„Zd„Zdefd„ƒYZdS(iÿÿÿÿN(t*ii:Ç–iÃ:Ç–i:Ç–i :Ç–iÂ:Ç–iÇ:Ç–iÜ:Ç–i<is%m/%d/%y %H:%M:%Ss^((\w+):)?(.+)cCsrtj|ƒ}|r^|jdƒ}|jdƒ}|dkrHd}n |jƒ}||fStd|ƒ‚dS(s’ Given a Kerberos ccache name parse it into it's scheme and location components. Currently valid values for the scheme are: * FILE * MEMORY The scheme is always returned as upper case. If the scheme does not exist it defaults to FILE. :parameters: ccache_name The name of the Kerberos ccache. :returns: A two-tuple of (scheme, ccache) iitFILEsInvalid ccache name = "%s"N(tccache_name_retsearchtgrouptNonetuppert ValueError(t ccache_nametmatchtschemetlocation((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytkrb5_parse_ccache-s    cCsd|jƒ|fS(Ns%s:%s(R(R tname((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytkrb5_unparse_ccacheLscCsd||fS(s Given a Kerberos user principal name and a Kerberos realm return the Kerberos V5 user principal name. :parameters: user User principal name. realm The Kerberos realm the user exists in. :returns: Kerberos V5 user principal name. s%s@%s((tusertrealm((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytkrb5_format_principal_nameOs cCsd|||fS(s¥ Given a Kerberos service principal name, the host where the service is running and a Kerberos realm return the Kerberos V5 service principal name. :parameters: service Service principal name. host The DNS name of the host where the service is located. realm The Kerberos realm the service exists in. :returns: Kerberos V5 service principal name. s%s/%s@%s((tservicethostR((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyt"krb5_format_service_principal_name^scCstd||ƒS(s· Given a Kerberos realm return the Kerberos V5 TGT name. :parameters: realm The Kerberos realm the TGT exists in. :returns: Kerberos V5 TGT name. tkrbtgt(R(R((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytkrb5_format_tgt_principal_nameqs cCstjttj|ƒƒS(sý Given a UNIX timestamp format it into a string in the same manner the MIT Kerberos library does. Kerberos timestamps are always in local time. :parameters: timestamp Unix timestamp :returns: formated string (ttimetstrftimet krb5_time_fmtt localtime(t timestamp((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytkrb5_format_time}s t KRB5_CCachecBsVeZdZd„Zd„Zd„Zd„Zd„Zd„Zd„Z d„Z RS( sy Kerberos stores a TGT (Ticket Granting Ticket) and the service tickets bound to it in a ccache (credentials cache). ccaches are bound to a Kerberos user principal. This class opens a Kerberos ccache and allows one to manipulate it. Most useful is the extraction of ticket entries (cred's) in the ccache and the ability to examine their attributes. cCstj|tƒd|_d|_d|_d|_d|_yat j ƒ|_t |ƒ\|_|_t j dt |ƒd|jƒ|_|jjƒ|_Wn[t jk rû}|jd}|jd}|tkròtd||fƒ‚qü|‚nXdS(s :parameters: ccache The name of a Kerberos ccache used to hold Kerberos tickets. :returns: `KRB5_CCache` object encapsulting the ccache. R tcontextiis"%s", ccache="%s"N(tlog_mgrt get_loggertTrueRRR R tccachet principaltkrbVtdefault_contextR tCCachetstrt Krb5ErrortargstKRB5_FCC_NOFILER(tselfR"tet error_codetmessage((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyt__init__•s"     $   cCsd|j|jfS(s A Kerberos ccache is identified by a name comprised of a scheme and location component. This function returns that canonical name. See `krb5_parse_ccache()` :returns: The name of ccache with it's scheme and location components. s%s:%s(R R (R+((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyt ccache_str±s cCsd|jƒ|jjfS(Nscache="%s" principal="%s"(R0R#R (R+((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyt__str__½sc Cst|tjƒr|}nNytjt|ƒ|jƒ}Wn,tk rh}|jd||ƒ|‚nX|j|ddddddddf }y|j j |t ƒ}Wnotj k r}|j d}|tkrùtd|j|jƒfƒ‚n|‚ntk r}|‚nX|S(s> Given a Kerberos principal return the krbV credentials tuple describing the credential. If the principal does not exist in the ccache a KeyError is raised. :parameters: principal The Kerberos principal whose ticket is being retrieved. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: A krbV credentials tuple. If the principal is not in the ccache a KeyError is raised. s-could not create krbV principal from "%s", %sis("%s" credential not found in "%s" ccacheN(iN(iiii(t isinstanceR$t PrincipalR'Rt ExceptionterrorR#RR"tget_credentialstKRB5_GC_CACHEDR(R)tKRB5_CC_NOTFOUNDtKeyErrorR R0(R+R#tkrbV_principalR,t creds_tupletcredR-((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyR6Às6       c Cs't|tjƒr|}nNytjt|ƒ|jƒ}Wn,tk rh}|jd||ƒ|‚nXyp|j|ƒ}|d\}}}}|jd|j t |ƒt |ƒt |ƒt |ƒƒ||||fSWnGt k rô}|‚n/tk r"}|jd|j |ƒ|‚nXdS(sÀ Given a Kerberos principal return the ticket timestamps if the principal's ticket in the ccache is valid. If the principal does not exist in the ccache a KeyError is raised. The return credential time values are Unix timestamps in localtime. The returned timestamps are: authtime The time when the ticket was issued. starttime The time when the ticket becomes valid. endtime The time when the ticket expires. renew_till The time when the ticket becomes no longer renewable (if renewable). :parameters: principal The Kerberos principal whose ticket is being validated. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: return authtime, starttime, endtime, renew_till s-could not create krbV principal from "%s", %sisXget_credential_times: principal=%s, authtime=%s, starttime=%s, endtime=%s, renew_till=%ss6get_credential_times failed, principal="%s" error="%s"N( R2R$R3R'RR4R5R6tdebugR RR9( R+R#R:R,R<tauthtimet starttimetendtimet renew_till((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytget_credential_timesñs(    cCs‘y|j|ƒ\}}}}Wn?tk r5}tStk r`}|jd||ƒ|‚nXtjƒ}||kr}tS||krtStS(s² Given a Kerberos principal return a boolean indicating if the principal's ticket in the ccache is valid. If the ticket is not in the ccache False is returned. If the ticket exists in the ccache it's validity is checked and returned. :parameters: principal The Kerberos principal whose ticket is being validated. The principal may be either a string formatted as a Kerberos V5 principal or it may be a `krbV.Principal` object. :returns: True if the principal's ticket exists and is valid. False if the ticket does not exist or if the ticket is not valid. s5credential_is_valid failed, principal="%s" error="%s"(RBR9tFalseR4R5RR!(R+R#R>R?R@RAR,tnow((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pytcredential_is_valid)s    cCsy/td||ƒ}|j|ƒ}|r.tSWntk rBnXy#t|ƒ}|j|ƒ}|SWntk rztSXdS(s$ Test to see if ldap service ticket or the TGT is valid. :parameters: host ldap server realm kerberos realm :returns: True if either the ldap service ticket or the TGT is valid, False otherwise. tHTTPN(RRER!R9RRC(R+RRR#tvalid((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyRGKs   c Csìd}yOtd||ƒ}|j|ƒ\}}}}|rNt||ƒ}n|}Wntk rhnXyIt|ƒ}|j|ƒ\}}}}|r«t||ƒ}n|}Wntk rÅnX|jd|jƒ|t|ƒƒ|S(sö Returns the minimum endtime for tickets of interest (ldap service or TGT). :parameters: host ldap server realm kerberos realm :returns: UNIX timestamp value. iRFsKRB5_CCache %s endtime=%s (%s)(RRBtminR9RR=R0R( R+RRtresultR#R>R?R@RA((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyR@hs&      "( t__name__t __module__t__doc__R/R0R1R6RBRERGR@(((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyR‹s   1 8 " i,(R$Rtretipapython.ipa_log_managerR7R8R*tKRB5KDC_ERR_S_PRINCIPAL_UNKNOWNtKRB5KRB_AP_ERR_TKT_EXPIREDt KRB5_FCC_PERMtKRB5_CC_FORMATtKRB5_REALM_CANT_RESOLVEtkrb_ticket_expiration_thresholdRtcompileRR RRRRRtobjectR(((s./home/mkosek/freeipa-clean/ipalib/krb_utils.pyts*         freeipa-3.3.4/ipalib/capabilities.pyc0000664000175000017500000000210012271707517017112 0ustar mkosekmkosekó †fçRc@s>dZddlmZdZeddddƒZd„Zd S( søList of, and utilities for working with, client capabilities by API version The API version is given in ipapython.version.API_VERSION. This module defines a dict, ``capabilities``, that maps feature names to API versions they were introduced in. iÿÿÿÿ(tversionu2.51tmessagesu2.52toptional_uid_paramsu2.54cCs&tj|ƒ}|tjt|ƒkS(sºDetermine whether the client has the given capability :param capability: Name of the capability to test :param client_version: The API version string reported by the client (Rt LooseVersiont capabilities(tclient_versiont capabilityt version_tuple((s1/home/mkosek/freeipa-clean/ipalib/capabilities.pytclient_has_capability/sN(t__doc__t distutilsRtVERSION_WITHOUT_CAPABILITIEStdictRR(((s1/home/mkosek/freeipa-clean/ipalib/capabilities.pyts  freeipa-3.3.4/ipalib/backend.pyc0000664000175000017500000001230512271707517016060 0ustar mkosekmkosekó MmâRc@s«dZddlZddlZddlZddlmZmZmZddlm Z m Z m Z dej fd„ƒYZ de fd„ƒYZd e fd „ƒYZdS( s* Base classes for all backed-end plugins. iÿÿÿÿN(t PublicErrort InternalErrort CommandError(tcontextt Connectiontdestroy_contexttBackendcBseZdZRS(s- Base class for all backend plugins. (t__name__t __module__t__doc__(((s,/home/mkosek/freeipa-clean/ipalib/backend.pyRst ConnectiblecBs\eZdZed„Zd„Zd„Zd„Zd„Zd„Z d„Z e e ƒZ RS(s$ Base class for backend plugins that create connections. In addition to the nicety of providing a standard connection API, all backend plugins that create connections should use this base class so that `request.destroy_context()` can properly close all open connections. cCsHtj|ƒ|r"|j|_n"d|jtt|ƒƒf|_dS(Ns%s_%s(Rt__init__tnametidtstr(tselftshared_instance((s,/home/mkosek/freeipa-clean/ipalib/backend.pyR .s cOs˜tt|jƒr:td|jtjƒjƒfƒ‚n|j||Ž}tt|jt ||j ƒƒ|j |ks€t ‚|j d|jƒdS(s1 Create thread-local connection. s1connect: 'context.%s' already exists in thread %rsCreated connection context.%sN(thasattrRR t StandardErrort threadingt currentThreadtgetNametcreate_connectiontsetattrRt disconnecttconntAssertionErrortdebug(RtargstkwR((s,/home/mkosek/freeipa-clean/ipalib/backend.pytconnect5s"cOstd|jƒ‚dS(Ns%s.create_connection()(tNotImplementedErrorR (RRR((s,/home/mkosek/freeipa-clean/ipalib/backend.pyRDscCsltt|jƒs:td|jtjƒjƒfƒ‚n|jƒtt|jƒ|j d|jƒdS(Ns4disconnect: 'context.%s' does not exist in thread %rsDestroyed connection context.%s( RRR RRRRtdestroy_connectiontdelattrR(R((s,/home/mkosek/freeipa-clean/ipalib/backend.pyRGs" cCstd|jƒ‚dS(Ns%s.destroy_connection()(RR (R((s,/home/mkosek/freeipa-clean/ipalib/backend.pyR RscCstt|jƒS(sY Return ``True`` if thread-local connection on `request.context` exists. (RRR (R((s,/home/mkosek/freeipa-clean/ipalib/backend.pyt isconnectedUscCsMtt|jƒs:td|jtjƒjƒfƒ‚ntt|jƒjS(s1 Return thread-local connection. sno context.%s in thread %r( RRR tAttributeErrorRRRtgetattrR(R((s,/home/mkosek/freeipa-clean/ipalib/backend.pyt __get_conn[s"( RRR tTrueR RRRR R"t_Connectible__get_conntpropertyR(((s,/home/mkosek/freeipa-clean/ipalib/backend.pyR %s      t ExecutionercBs)eZddd„Zd„Zd„ZRS(cCsž|dk r|tjds   Bfreeipa-3.3.4/ipalib/messages.py0000664000175000017500000001210212271663206016124 0ustar mkosekmkosek# Authors: # Petr Viktorin # # Copyright (C) 2012 Red Hat # see file 'COPYING' for use and warranty inmsgion # # 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 . """ Custom message (debug, info, wraning) classes passed through RPC. These are added to the "messages" entry in a RPC response, and printed to the user as log messages. Each message class has a unique numeric "errno" attribute from the 10000-10999 range, so that it does not clash with PublicError numbers. Messages also have the 'type' argument, set to one of 'debug', 'info', 'warning', 'error'. This determines the severity of themessage. """ from inspect import isclass from ipalib.constants import TYPE_ERROR from ipalib.text import _ as ugettext from ipalib.text import Gettext, NGettext from ipalib.capabilities import client_has_capability def add_message(version, result, message): if client_has_capability(version, 'messages'): result.setdefault('messages', []).append(message.to_dict()) def process_message_arguments(obj, format=None, message=None, **kw): obj.kw = kw name = obj.__class__.__name__ if obj.format is not None and format is not None: raise ValueError( 'non-generic %r needs format=None; got format=%r' % ( name, format) ) if message is None: if obj.format is None: if format is None: raise ValueError( '%s.format is None yet format=None, message=None' % name ) obj.format = format obj.forwarded = False obj.msg = obj.format % kw if isinstance(obj.format, basestring): obj.strerror = ugettext(obj.format) % kw else: obj.strerror = obj.format % kw if 'instructions' in kw: def convert_instructions(value): if isinstance(value, list): result = u'\n'.join(map(lambda line: unicode(line), value)) return result return value instructions = u'\n'.join((unicode(_('Additional instructions:')), convert_instructions(kw['instructions']))) obj.strerror = u'\n'.join((obj.strerror, instructions)) else: if isinstance(message, (Gettext, NGettext)): message = unicode(message) elif type(message) is not unicode: raise TypeError( TYPE_ERROR % ('message', unicode, message, type(message)) ) obj.forwarded = True obj.msg = message obj.strerror = message for (key, value) in kw.iteritems(): assert not hasattr(obj, key), 'conflicting kwarg %s.%s = %r' % ( name, key, value, ) setattr(obj, key, value) _texts = [] def _(message): _texts.append(message) return message class PublicMessage(UserWarning): """ **10000** Base class for messages that can be forwarded in an RPC response. """ def __init__(self, format=None, message=None, **kw): process_message_arguments(self, format, message, **kw) super(PublicMessage, self).__init__(self.msg) errno = 10000 format = None def to_dict(self): """Export this message to a dict that can be sent through RPC""" return dict( type=unicode(self.type), name=unicode(type(self).__name__), message=self.strerror, code=self.errno, ) class VersionMissing(PublicMessage): """ **13001** Used when client did not send the API version. For example: >>> VersionMissing(server_version='2.123').strerror u"API Version number was not sent, forward compatibility not guaranteed. Assuming server's API version, 2.123" """ errno = 13001 type = 'warning' format = _("API Version number was not sent, forward compatibility not " "guaranteed. Assuming server's API version, %(server_version)s") def iter_messages(variables, base): """Return a tuple with all subclasses """ for (key, value) in variables.items(): if key.startswith('_') or not isclass(value): continue if issubclass(value, base): yield value public_messages = tuple(sorted( iter_messages(globals(), PublicMessage), key=lambda E: E.errno)) def print_report(label, classes): for cls in classes: print '%d\t%s' % (cls.errno, cls.__name__) print '(%d %s)' % (len(classes), label) if __name__ == '__main__': print_report('public messages', public_messages) freeipa-3.3.4/ipalib/base.pyc0000664000175000017500000004035312271707517015407 0ustar mkosekmkosekó ­8 Rc@s•dZddlZddlmZmZddlmZmZmZmZde fd„ƒYZ d„Z d„Z d „Z d e fd „ƒYZdS( s% Foundational classes and functions. iÿÿÿÿN(t NAME_REGEXt NAME_ERROR(t TYPE_ERRORt SET_ERRORt DEL_ERRORtOVERRIDE_ERRORtReadOnlycBs8eZdZeZd„Zd„Zd„Zd„ZRS(sB Base class for classes that can be locked into a read-only state. Be forewarned that Python does not offer true read-only attributes for user-defined classes. Do *not* rely upon the read-only-ness of this class for security purposes! The point of this class is not to make it impossible to set or to delete attributes after an instance is locked, but to make it impossible to do so *accidentally*. Rather than constantly reminding our programmers of things like, for example, "Don't set any attributes on this ``FooBar`` instance because doing so wont be thread-safe", this class offers a real way to enforce read-only attribute usage. For example, before a `ReadOnly` instance is locked, you can set and delete its attributes as normal: >>> class Person(ReadOnly): ... pass ... >>> p = Person() >>> p.name = 'John Doe' >>> p.phone = '123-456-7890' >>> del p.phone But after an instance is locked, you cannot set its attributes: >>> p.__islocked__() # Is this instance locked? False >>> p.__lock__() # This will lock the instance >>> p.__islocked__() True >>> p.department = 'Engineering' Traceback (most recent call last): ... AttributeError: locked: cannot set Person.department to 'Engineering' Nor can you deleted its attributes: >>> del p.name Traceback (most recent call last): ... AttributeError: locked: cannot delete Person.name However, as noted at the start, there are still obscure ways in which attributes can be set or deleted on a locked `ReadOnly` instance. For example: >>> object.__setattr__(p, 'department', 'Engineering') >>> p.department 'Engineering' >>> object.__delattr__(p, 'name') >>> hasattr(p, 'name') False But again, the point is that a programmer would never employ the above techniques *accidentally*. Lastly, this example aside, you should use the `lock()` function rather than the `ReadOnly.__lock__()` method. And likewise, you should use the `islocked()` function rather than the `ReadOnly.__islocked__()` method. For example: >>> readonly = ReadOnly() >>> islocked(readonly) False >>> lock(readonly) is readonly # lock() returns the instance True >>> islocked(readonly) True cCs(|jtkstdƒ‚t|_dS(s· Put this instance into a read-only state. After the instance has been locked, attempting to set or delete an attribute will raise an AttributeError. s"__lock__() can only be called onceN(t_ReadOnly__lockedtFalsetAssertionErrortTrue(tself((s)/home/mkosek/freeipa-clean/ipalib/base.pyt__lock__hscCs|jS(sE Return True if instance is locked, otherwise False. (R(R ((s)/home/mkosek/freeipa-clean/ipalib/base.pyt __islocked__rscCs>|jr+tt|jj||fƒ‚ntj|||ƒS(sô If unlocked, set attribute named ``name`` to ``value``. If this instance is locked, an AttributeError will be raised. :param name: Name of attribute to set. :param value: Value to assign to attribute. (RtAttributeErrorRt __class__t__name__tobjectt __setattr__(R tnametvalue((s)/home/mkosek/freeipa-clean/ipalib/base.pyRxs cCs8|jr(tt|jj|fƒ‚ntj||ƒS(s¹ If unlocked, delete attribute named ``name``. If this instance is locked, an AttributeError will be raised. :param name: Name of attribute to delete. (RRRRRRt __delattr__(R R((s)/home/mkosek/freeipa-clean/ipalib/base.pyR‡s ( Rt __module__t__doc__RRR R RR(((s)/home/mkosek/freeipa-clean/ipalib/base.pyRs G  cCsR|jƒtks"td|ƒ‚|jƒ|jƒtksNtd|ƒ‚|S(sí Lock an instance of the `ReadOnly` class or similar. This function can be used to lock instances of any class that implements the same locking API as the `ReadOnly` class. For example, this function can lock instances of the `config.Env` class. So that this function can be easily used within an assignment, ``instance`` is returned after it is locked. For example: >>> readonly = ReadOnly() >>> readonly is lock(readonly) True >>> readonly.attr = 'This wont work' Traceback (most recent call last): ... AttributeError: locked: cannot set ReadOnly.attr to 'This wont work' Also see the `islocked()` function. :param instance: The instance of `ReadOnly` (or similar) to lock. salready locked: %rsfailed to lock: %r(R RR R R (tinstance((s)/home/mkosek/freeipa-clean/ipalib/base.pytlock–s" "cCs8t|dƒrt|jƒs.td|ƒ‚|jƒS(sË Return ``True`` if ``instance`` is locked. This function can be used on an instance of the `ReadOnly` class or an instance of any other class implemented the same locking API. For example: >>> readonly = ReadOnly() >>> islocked(readonly) False >>> readonly.__lock__() >>> islocked(readonly) True Also see the `lock()` function. :param instance: The instance of `ReadOnly` (or similar) to interrogate. R sno __lock__() method: %r(thasattrtcallableR R R (R((s)/home/mkosek/freeipa-clean/ipalib/base.pytislocked³s! cCslt|ƒtk r7ttdt|t|ƒfƒ‚ntjt|ƒdkrhtt t|fƒ‚n|S(s Verify that ``name`` is suitable for a `NameSpace` member name. In short, ``name`` must be a valid lower-case Python identifier that neither starts nor ends with an underscore. Otherwise an exception is raised. This function will raise a ``ValueError`` if ``name`` does not match the `constants.NAME_REGEX` regular expression. For example: >>> check_name('MyName') Traceback (most recent call last): ... ValueError: name must match '^[a-z][_a-z0-9]*[a-z0-9]$|^[a-z]$'; got 'MyName' Also, this function will raise a ``TypeError`` if ``name`` is not an ``str`` instance. For example: >>> check_name(u'my_name') Traceback (most recent call last): ... TypeError: name: need a ; got u'my_name' (a ) So that `check_name()` can be easily used within an assignment, ``name`` is returned unchanged if it passes the check. For example: >>> n = check_name('my_name') >>> n 'my_name' :param name: Identifier to test. RN( ttypetstrt TypeErrorRtretmatchRtNonet ValueErrorR(R((s)/home/mkosek/freeipa-clean/ipalib/base.pyt check_nameÍs!"t NameSpacecBs\eZdZedd„Zd„Zd„Zd„Zd„Zd„Z d„Z d „Z RS( sç A read-only name-space with handy container behaviours. A `NameSpace` instance is an ordered, immutable mapping object whose values can also be accessed as attributes. A `NameSpace` instance is constructed from an iterable providing its *members*, which are simply arbitrary objects with a ``name`` attribute whose value: 1. Is unique among the members 2. Passes the `check_name()` function Beyond that, no restrictions are placed on the members: they can be classes or instances, and of any type. The members can be accessed as attributes on the `NameSpace` instance or through a dictionary interface. For example, say we create a `NameSpace` instance from a list containing a single member, like this: >>> class my_member(object): ... name = 'my_name' ... >>> namespace = NameSpace([my_member]) >>> namespace NameSpace(<1 member>, sort=True) We can then access ``my_member`` both as an attribute and as a dictionary item: >>> my_member is namespace.my_name # As an attribute True >>> my_member is namespace['my_name'] # As dictionary item True For a more detailed example, say we create a `NameSpace` instance from a generator like this: >>> class Member(object): ... def __init__(self, i): ... self.i = i ... self.name = 'member%d' % i ... def __repr__(self): ... return 'Member(%d)' % self.i ... >>> ns = NameSpace(Member(i) for i in xrange(3)) >>> ns NameSpace(<3 members>, sort=True) As above, the members can be accessed as attributes and as dictionary items: >>> ns.member0 is ns['member0'] True >>> ns.member1 is ns['member1'] True >>> ns.member2 is ns['member2'] True Members can also be accessed by index and by slice. For example: >>> ns[0] Member(0) >>> ns[-1] Member(2) >>> ns[1:] (Member(1), Member(2)) (Note that slicing a `NameSpace` returns a ``tuple``.) `NameSpace` instances provide standard container emulation for membership testing, counting, and iteration. For example: >>> 'member3' in ns # Is there a member named 'member3'? False >>> 'member2' in ns # But there is a member named 'member2' True >>> len(ns) # The number of members 3 >>> list(ns) # Iterate through the member names ['member0', 'member1', 'member2'] Although not a standard container feature, the `NameSpace.__call__()` method provides a convenient (and efficient) way to iterate through the *members* (as opposed to the member names). Think of it like an ordered version of the ``dict.itervalues()`` method. For example: >>> list(ns[name] for name in ns) # One way to do it [Member(0), Member(1), Member(2)] >>> list(ns()) # A more efficient, simpler way to do it [Member(0), Member(1), Member(2)] Another convenience method is `NameSpace.__todict__()`, which will return a copy of the ``dict`` mapping the member names to the members. For example: >>> ns.__todict__() {'member1': Member(1), 'member0': Member(0), 'member2': Member(2)} As `NameSpace.__init__()` locks the instance, `NameSpace` instances are read-only from the get-go. An ``AttributeError`` is raised if you try to set *any* attribute on a `NameSpace` instance. For example: >>> ns.member3 = Member(3) # Lets add that missing 'member3' Traceback (most recent call last): ... AttributeError: locked: cannot set NameSpace.member3 to Member(3) (For information on the locking protocol, see the `ReadOnly` class, of which `NameSpace` is a subclass.) By default the members will be sorted alphabetically by the member name. For example: >>> sorted_ns = NameSpace([Member(7), Member(3), Member(5)]) >>> sorted_ns NameSpace(<3 members>, sort=True) >>> list(sorted_ns) ['member3', 'member5', 'member7'] >>> sorted_ns[0] Member(3) But if the instance is created with the ``sort=False`` keyword argument, the original order of the members is preserved. For example: >>> unsorted_ns = NameSpace([Member(7), Member(3), Member(5)], sort=False) >>> unsorted_ns NameSpace(<3 members>, sort=False) >>> list(unsorted_ns) ['member7', 'member3', 'member5'] >>> unsorted_ns[0] Member(7) The `NameSpace` class is used in many places throughout freeIPA. For a few examples, see the `plugable.API` and the `frontend.Command` classes. RcsYt|ƒtk r7ttdt|t|ƒfƒ‚n||_|rmtt|d‡fd†ƒƒ|_nt|ƒ|_t‡fd†|jDƒƒ|_t ƒ|_ xž|jD]“}t t |ˆƒƒ}||j kr t t|jj||j ||fƒ‚nt||ƒ s*td|ƒ‚||j |sc3s|]}t|ˆƒVqdS(N(R((t.0R)(R*(s)/home/mkosek/freeipa-clean/ipalib/base.pys ‘ssOuch! Has attribute %rN(RtboolRRt_NameSpace__sortttupletsortedt_NameSpace__memberst_NameSpace__namestdictt_NameSpace__mapR$R(RRRRRR tsetattrR(R tmembersR&R*tmemberR((R*s)/home/mkosek/freeipa-clean/ipalib/base.pyt__init__s&" $" &  cCs t|jƒS(s/ Return the number of members. (tlenR1(R ((s)/home/mkosek/freeipa-clean/ipalib/base.pyt__len__žsccsx|jD] }|Vq WdS(sc Iterate through the member names. If this instance was created with ``sort=False``, the names will be in the same order as the members were passed to the constructor; otherwise the names will be in alphabetical order (which is the default). This method is like an ordered version of ``dict.iterkeys()``. N(R2(R R((s)/home/mkosek/freeipa-clean/ipalib/base.pyt__iter__¤s ccsx|jD] }|Vq WdS(se Iterate through the members. If this instance was created with ``sort=False``, the members will be in the same order as they were passed to the constructor; otherwise the members will be in alphabetical order by name (which is the default). This method is like an ordered version of ``dict.itervalues()``. N(R1(R R7((s)/home/mkosek/freeipa-clean/ipalib/base.pyt__call__±s cCs ||jkS(sK Return ``True`` if namespace has a member named ``name``. (R4(R R((s)/home/mkosek/freeipa-clean/ipalib/base.pyt __contains__¾scCslt|tƒr|j|St|ƒttfkr=|j|Sttdt ttf|t|ƒfƒ‚dS(s˜ Return a member by name or index, or return a slice of members. :param key: The name or index of a member, or a slice object. R'N( t isinstancet basestringR4RtinttsliceR1RRR(R R'((s)/home/mkosek/freeipa-clean/ipalib/base.pyt __getitem__Äs   cCsDt|ƒ}|dkr!d}nd}d|jj|||jfS(sS Return a pseudo-valid expression that could create this instance. iR7R6s%s(<%d %s>, sort=%r)(R9RRR.(R tcntR)((s)/home/mkosek/freeipa-clean/ipalib/base.pyt__repr__Òs    cCs t|jƒS(sR Return a copy of the private dict mapping member name to member. (R3R4(R ((s)/home/mkosek/freeipa-clean/ipalib/base.pyt __todict__âs( RRRR R8R:R;R<R=RBRDRE(((s)/home/mkosek/freeipa-clean/ipalib/base.pyR%ùs†    (RR t constantsRRRRRRRRRRR$R%(((s)/home/mkosek/freeipa-clean/ipalib/base.pyts "y   ,freeipa-3.3.4/ipalib/rpc.pyc0000664000175000017500000006076712271707517015274 0ustar mkosekmkosekó †fçRc@sdZddlmZddlmZddlZddlZddlZddlZddl Z ddl Z ddl m Z m Z mZmZmZmZmZmZmZddlZddlmZmZddlmZddlmZdd lmZmZm Z m!Z!m"Z"m#Z#dd l$m%Z%dd l&m'Z'm(Z(dd l)m*Z*dd l+m,Z,ddl-m.Z.ddl-m/Z/ddl0m1Z1ddl2m3Z3ddl4Z4ddl5Z5ddl6m7Z7m8Z8ddl9m:Z:ddl;m<Z<ddl=m>Z>m?Z?m@Z@mAZAmBZBmCZCddlDmEZEdZFdeFZGd„ZHd„ZId„ZJd„ZKd„ZLdd„ZMdeOdd „ZPdd!„ZQdd"„ZRd#efd$„ƒYZSd%eSfd&„ƒYZTd'eTfd(„ƒYZUd)eUfd*„ƒYZVd+efd,„ƒYZWdS(-s? RPC client and shared RPC client/server functionality. This module adds some additional functionality on top of the ``xmlrpclib`` module in the Python standard library. For documentation on the ``xmlrpclib`` module, see: http://docs.python.org/library/xmlrpclib.html Also see the `ipaserver.rpcserver` module. iÿÿÿÿ(tNoneType(tDecimalN( tBinarytFaulttdumpstloadst ServerProxyt Transportt ProtocolErrortMININTtMAXINT(tresolvert rdatatype(t DNSException(t Connectible(t public_errorst PublicErrort UnknownErrort NetworkErrort KerberosErrortXMLRPCMarshallError(terrors(tcontextt Connection(tget_current_principal(t root_logger(tipautil(tkernel_keyring(tCookie(t_(tNSSHTTPSt NSSConnection(t NSPRError(turlparse(tKRB5KDC_ERR_S_PRINCIPAL_UNKNOWNtKRB5KRB_AP_ERR_TKT_EXPIREDt KRB5_FCC_PERMtKRB5_FCC_NOFILEtKRB5_CC_FORMATtKRB5_REALM_CANT_RESOLVE(tDNt ipa_sessions %s_cookie:%%scCst|S(sc Return the key name used for storing the client session data for the given principal. (tKEYRING_COOKIE_NAME(t principal((s(/home/mkosek/freeipa-clean/ipalib/rpc.pytclient_session_keyring_keynameGscCsLyt|ƒ}Wn%tk r7}tt|ƒƒ‚nXtj||ƒdS(s½ Given a principal create or update the session data for that principal in the persistent secure storage. Raises ValueError if unable to perform the action for any reason. N(R,t Exceptiont ValueErrortstrRt update_key(R+tdatatkeynamete((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt%update_persistent_client_session_dataOs cCsEyt|ƒ}Wn%tk r7}tt|ƒƒ‚nXtj|ƒS(s¼ Given a principal return the stored session data for that principal from the persistent secure storage. Raises ValueError if unable to perform the action for any reason. (R,R-R.R/Rtread_key(R+R2R3((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt#read_persistent_client_session_data_s cCsIyt|ƒ}Wn%tk r7}tt|ƒƒ‚nXtj|ƒdS(sµ Given a principal remove the session data for that principal from the persistent secure storage. Raises ValueError if unable to perform the action for any reason. N(R,R-R.R/Rtdel_key(R+R2R3((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt%delete_persistent_client_session_dataos c Cs t|ƒttfkr,td„|DƒƒSt|tƒrUtd„|jƒDƒƒSt|ƒtkrqt|ƒSt|ƒtkrt |ƒSt|t t fƒrÄ|t ksº|t krÄt |ƒSt|tƒrÝt|ƒSt|ƒt t t tttfkst‚|S(sÈ Wrap all ``str`` in ``xmlrpclib.Binary``. Because ``xmlrpclib.dumps()`` will itself convert all ``unicode`` instances into UTF-8 encoded ``str`` instances, we don't do it here. So in total, when encoding data for an XML-RPC packet, the following transformations occur: * All ``str`` instances are treated as binary data and are wrapped in an ``xmlrpclib.Binary()`` instance. * Only ``unicode`` instances are treated as character data. They get converted to UTF-8 encoded ``str`` instances (although as mentioned, not by this function). Also see `xml_unwrap()`. :param value: The simple scalar or simple compound value to wrap. css|]}t|ƒVqdS(N(txml_wrap(t.0tv((s(/home/mkosek/freeipa-clean/ipalib/rpc.pys •scss'|]\}}|t|ƒfVqdS(N(R9(R:tkR;((s(/home/mkosek/freeipa-clean/ipalib/rpc.pys ˜s(ttypetlistttuplet isinstancetdictt iteritemsR/RRtunicodetinttlongR R R(tfloattboolRtAssertionError(tvalue((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR9s  -  *sUTF-8csßt|ƒttfkr2t‡fd†|DƒƒSt|ƒtkrdt‡fd†|jƒDƒƒSt|ƒtkrƒ|jˆƒSt|tƒr´t|j ƒtks­t ‚|j St|ƒt t t ttfksÛt ‚|S(sE Unwrap all ``xmlrpc.Binary``, decode all ``str`` into ``unicode``. When decoding data from an XML-RPC packet, the following transformations occur: * The binary payloads of all ``xmlrpclib.Binary`` instances are returned as ``str`` instances. * All ``str`` instances are treated as UTF-8 encoded Unicode strings. They are decoded and the resulting ``unicode`` instance is returned. Also see `xml_wrap()`. :param value: The value to unwrap. :param encoding: The Unicode encoding to use (defaults to ``'UTF-8'``). c3s|]}t|ˆƒVqdS(N(t xml_unwrap(R:R;(tencoding(s(/home/mkosek/freeipa-clean/ipalib/rpc.pys ºsc3s*|] \}}|t|ˆƒfVqdS(N(RJ(R:R<R;(RK(s(/home/mkosek/freeipa-clean/ipalib/rpc.pys ½s(R=R>R?RARBR/tdecodeR@RR1RHRCRDRFRGR(RIRK((RKs(/home/mkosek/freeipa-clean/ipalib/rpc.pyRJ§s 'c CsXt|ƒtkr!t|ƒ}nt|tƒs6t‚t|d|d|d|dtƒS(sÊ Encode an XML-RPC data packet, transparently wraping ``params``. This function will wrap ``params`` using `xml_wrap()` and will then encode the XML-RPC data packet using ``xmlrpclib.dumps()`` (from the Python standard library). For documentation on the ``xmlrpclib.dumps()`` function, see: http://docs.python.org/library/xmlrpclib.html#convenience-functions Also see `xml_loads()`. :param params: A ``tuple`` or an ``xmlrpclib.Fault`` instance. :param methodname: The name of the method to call if this is a request. :param methodresponse: Set this to ``True`` if this is a response. :param encoding: The Unicode encoding to use (defaults to ``'UTF-8'``). t methodnametmethodresponseRKt allow_none(R=R?R9R@RRHRtTrue(tparamsRMRNRK((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt xml_dumpsÈs cCsJt|tƒst‚t|jƒtkrFt|j|jj|ƒƒS|S(N(R@RRHR=t faultStringR/t faultCodeRL(R3RK((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt decode_faultçscCsLy&t|ƒ\}}t|ƒ|fSWntk rG}t|ƒ‚nXdS(st Decode the XML-RPC packet in ``data``, transparently unwrapping its params. This function will decode the XML-RPC packet in ``data`` using ``xmlrpclib.loads()`` (from the Python standard library). If ``data`` contains a fault, ``xmlrpclib.loads()`` will itself raise an ``xmlrpclib.Fault`` exception. Assuming an exception is not raised, this function will then unwrap the params in ``data`` using `xml_unwrap()`. Finally, a ``(params, methodname)`` tuple is returned containing the unwrapped params and the name of the method being called. If the packet contains no method name, ``methodname`` will be ``None``. For documentation on the ``xmlrpclib.loads()`` function, see: http://docs.python.org/library/xmlrpclib.html#convenience-functions Also see `xml_dumps()`. :param data: The XML-RPC packet to decode. N(RRJRRU(R1RKRQtmethodR3((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt xml_loadsîs tLanguageAwareTransportcBseZdZd„ZRS(s(Transport sending Accept-Language headercCsÅtj||ƒ\}}}y,tjtjdƒjdƒdjƒ}Wntjk rcd}nXt|t ƒs|g}n|j d|j ddƒfƒ|j dd t |ƒfƒ|||fS( Ntt.iten_ussAccept-LanguageRt-tReferershttps://%s/ipa/xml( Rt get_host_infotlocalet setlocaletLC_ALLtsplittlowertErrorR@R>tappendtreplaceR/(tselfthostt extra_headerstx509tlang((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR^s,  (t__name__t __module__t__doc__R^(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyRX st SSLTransportcBs eZdZd„Zd„ZRS(s2Handles an HTTPS transaction to an XML-RPC server.cCs|xutjjƒD]d}t|tƒs+qnt|jjtƒsFqnt|jjdƒr|jjj |krt SqWt S(s[ If there is another connections open it may have already initialized NSS. This is likely to lead to an NSS shutdown failure. One way to mitigate this is to tell NSS to not initialize if it has already been done in another open connection. Returns True if another connection is using the same db. tdbdir( Rt__dict__tvaluesR@Rtconnt_ServerProxy__transportRothasattrRpRPtFalse(RgRpRI((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt__nss_initialized&s cCsõ|j|ƒ\}|_}tjd krT|jrT||jdkrT|jdSnd}|j|ƒ}tjd kr–t|dd|d|ƒ}nt|dd|d|ƒ}||_|j ƒtjd kr×|S||f|_|jdSdS( Niiiis/etc/pki/nssdbi»Rptno_init(ii(ii(ii( R^t_extra_headerstsyst version_infot _connectiont_SSLTransport__nss_initializedRRRptconnect(RgRhRjRpRxRs((s(/home/mkosek/freeipa-clean/ipalib/rpc.pytmake_connection9s  (RlRmRnR}R(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyRo#s t KerbTransportcBsQeZdZejejBZdd„Zd„Z dd„Z d„Z d„Z RS(sK Handles Kerberos Negotiation authentication to an XML-RPC server. cCsñtj|ƒ\}}|dtkr:tjd|ƒ‚n³|dtkrYtjƒ‚n”|dtkrxtjƒ‚nu|dt kr—tj ƒ‚nV|dt kr¶tj ƒ‚n7|dt krÕtjƒ‚ntjd|d|ƒ‚dS(Nitservicetmajortminor(Rt get_gsserrorR"Rt ServiceErrorR%t NoCCacheErrorR#t TicketExpiredR$tBadCCachePermsR&tBadCCacheFormatR'tCannotResolveKDCR(RgR3RR‚Rƒ((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt_handle_exception[sc Csntj||ƒ\}}}t|tƒs3g}nttdd ƒ}|rk|jd|fƒ|||fSd|jdƒd}yt j ||j ƒ\}}Wn#t j k rÆ}|j |ƒnXyt j|dƒWn)t j k r}|j |d|ƒnXx7|D]/\} } | dkr|j| | fƒPqqW|jdd t j|ƒfƒ|||fS( s• Two things can happen here. If we have a session we will add a cookie for that. If not we will set an Authorization header. tsession_cookieRsHTTP@t:iRYRt Authorizations negotiate %sN(RoR^R@R>tgetattrRtNoneReRbtkerberostauthGSSClientInittflagstGSSErrorR‹tauthGSSClientSteptremovetauthGSSClientResponse( RgRhRiRjRŒRtrctvcR3thR;((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR^ls.   icCs/ztj|||||ƒSWd|jƒXdS(N(Rotsingle_requesttclose(RgRhthandlert request_bodytverbose((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR›“scCsá|dkrdSttddƒ}ttddƒ}tjd|ƒytj|t|ƒ}Wn'tk r†}tj d||ƒdSX|dkr—dSt |ƒ}tjd||ƒyt ||ƒWntk rÜ}nXdS(sô Given the contents of a Set-Cookie header scan the header and extract each cookie contained within until the session cookie is located. Examine the session cookie if the domain and path are specified, if not update the cookie with those values from the request URL. Then write the session cookie into the key store for the principal. If the cookie header is None or the session cookie is not present in the header no action is taken. Context Dependencies: The per thread context is expected to contain: principal The current pricipal the HTTP request was issued for. request_url The URL of the HTTP request. NR+t request_urlsreceived Set-Cookie '%s's&unable to parse cookie header '%s': %ss$storing cookie '%s' for principal %s( RRRRtdebugRtget_named_cookie_from_stringt COOKIE_NAMER-terrorR/R4(Rgt cookie_headerR+R RŒR3t cookie_string((s(/home/mkosek/freeipa-clean/ipalib/rpc.pytstore_session_cookie™s&    cCs&|j|jdƒƒtj||ƒS(Ns Set-Cookie(R§t getheaderRotparse_response(Rgtresponse((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR©ÈsN( RlRmRnR‘tGSS_C_MUTUAL_FLAGtGSS_C_SEQUENCE_FLAGR“RR‹R^R›R§R©(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR€Us  '  /tDelegatedKerbTransportcBs%eZdZejejBejBZRS(sb Handles Kerberos Negotiation authentication and TGT delegation to an XML-RPC server. (RlRmRnR‘tGSS_C_DELEG_FLAGR«R¬R“(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR­Ís t xmlclientcBsYeZdZd„Zd„Zd„Zd„Zdee ed„Z d„Z d„Z RS( sq Forwarding backend plugin for XML-RPC client. Also see the `ipaserver.rpcserver.xmlserver` plugin. cCs0tt|ƒjƒtd„tDƒƒ|_dS(Ncss|]}|j|fVqdS(N(terrno(R:R3((s(/home/mkosek/freeipa-clean/ipalib/rpc.pys Þs(tsuperR¯t__init__RARt_xmlclient__errors(Rg((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR²ÜscCs tj|ƒ\}}}}}}g}d|jj} ytj| tjƒ} Wntk rk} g} nXxF| D]>} t| j ƒj dƒ} |j dt j | ƒ|fƒqsWtt|ƒƒ}|}||krù|j|ƒ|jd|ƒn|jd|ƒ|S(sP Create a list of urls consisting of the available IPA servers. s_ldap._tcp.%s.RZs https://%s%si(R!tenvtdomainR tqueryR tSRVR R/ttargettrstripReRt format_netlocR>tsetR–tinsert(Rgt xmlrpc_uritschemetnetloctpathRQR¶tfragmenttserverstnametanswersR3tanswertservert cfg_server((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt get_url_listàs"!  $  cCsXyt|ƒ}Wntk r&}dSXytj|tƒ}Wntk rS}dSX|S(s Retrieves the session cookie for the given principal from the persistent secure storage. Returns None if not found or unable to retrieve the session cookie for any reason, otherwise returns a Cookie object containing the session cookie. N(R6R-RRR¢R£(RgR+R¦R3RŒ((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyt*get_session_cookie_from_persistent_storages c Csƒ|}ttdd ƒ}|j|ƒ}|d krJ|jjd|ƒ|S|jd||ƒy|j|ƒWn—tjk r¾}|jd||ƒyt |ƒWnt k r¹}nX|Stj k rä}|jd|ƒ|St k r}|j d|ƒ|SX|jjd|j ƒƒttd|j ƒƒtj|ƒ\}}}} } } d }tj|||| | | fƒ} | S( sE Attempt to load a session cookie for the current principal from the persistent secure storage. If the cookie is successfully loaded adjust the input url's to point to the session path and insert the session cookie into the per thread context for later insertion into the HTTP request. If the cookie is not successfully loaded then the original url is returned and the per thread context is not modified. Context Dependencies: The per thread context is expected to contain: principal The current pricipal the HTTP request was issued for. The per thread context will be updated with: session_cookie A cookie string to be inserted into the Cookie header of the HTPP request. R+sFfailed to find session_cookie in persistent storage for principal '%s'sKfound session_cookie in persistent storage for principal '%s', cookie: '%s's,deleting session data for principal '%s': %ss,not sending session cookie, URL mismatch: %ss-not sending session cookie, unknown error: %ss(setting session_cookie into context '%s'RŒs/ipa/session/xmlN(RRRRÉtlogR¡thttp_return_okRtExpiredR8R-t URLMismatchR¤t http_cookietsetattrR!t urlunparse( Rgturlt original_urlR+RŒR3R¾R¿RÀRQR¶RÁt session_url((s(/home/mkosek/freeipa-clean/ipalib/rpc.pytapply_session_cookies<    !!cCsîyA|jj}tƒ}ttd|ƒ|s@|j|ƒ}nWntk rTnX|j|ƒ}d}xJ|D]B} t dt ddƒ} || d<| j dƒrË|r»t ƒ| d}t,dt|ƒƒ‚nXdS(sš Forward call to command named ``name`` over XML-RPC. This method will encode and forward an XML-RPC request, and will then decode and return the corresponding XML-RPC response. :param command: The name of the command being forwarded. :param args: Positional arguments to pass to remote command. :param kw: Keyword arguments to pass to remote command. s#%s.forward(): %r not in api.CommandR sForwarding '%s' to server '%s's"Caught fault %d from server %s: %sR×RØR¤RÆRÙRŒi‘R+t KRB5CCNAMERpsUsing dbdir %sN(-tCommandR.RÃRRRR¡RsR9RJRRURTRSR³RR RR/RRÜRÝR8R-RÞtostenvirontgetR´RŸRâRãRéRtRÏRt disconnectRptforwardterrmsgtsocketR¤t OverflowErrort TypeErrorR(RgRÃtargsRæRÆRçRQRªR3R¤RŒR+RåRpt current_conn((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyRñ¬sb        6   N( RlRmRnR²RÈRÉRÔRRvRPRÞRêRñ(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pyR¯Õs   @  M (XRnttypesRtdecimalRt threadingRzRíR°R_tdatetimet xmlrpclibRRRRRRRR R R‘tdnsR R t dns.exceptionR tipalib.backendRt ipalib.errorsRRRRRRtipalibRtipalib.requestRRt ipalib.utilRtipapython.ipa_log_managerRt ipapythonRRtipapython.cookieRt ipalib.textRthttplibRótipapython.nsslibRRt nss.errorR turllib2R!tipalib.krb_utilsR"R#R$R%R&R't ipapython.dnR(R£R*R,R4R6R8R9RJRRvRRRURWRXRoR€R­R¯(((s(/home/mkosek/freeipa-clean/ipalib/rpc.pytsZ      @ .  .      ( !  2xfreeipa-3.3.4/ipalib/util.pyc0000664000175000017500000004525012271707517015453 0ustar mkosekmkosekó †fçRc@sµdZddlZddlZddlZddlZddlZddlZddlZddlm Z ddl m Z ddl m Z mZddlmZddlmZddlmZdd lmZdd lmZmZd „Zd „Zd „Zd„Zd„Zd„Zd„Z d„Z!d„Z"d„Z#d„Z$e%d„Z&e%d„Z'd„Z(e)e%d„Z*d„Z+d„Z,d„Z-d„Z.de/fd„ƒYZ0ej1d ej2ƒZ3idLd$6dOd%6dRd&6dUd(6dXd)6d[d+6d^d,6dad-6dcd.6ded/6dgd06dhd16did26djd36d#d46d#d56d#d66d7d86d7d96d7d:6d7d;6Z4d<„Z5dkd@„Z6dldB„Z7idCdD6dEdF6Z8dG„Z9dH„Z:dI„Z;dS(ms Various utility functions. iÿÿÿÿN(tNoneType(tWeakKeyDictionary(tresolvert rdatatype(t DNSException(terrors(t_(t SSHPublicKey(tDNtRDNcCsêt|ttfƒr2g|D]}t|ƒ^qSt|tƒr[td„|jƒDƒƒSt|tttt t t fƒr€|St|t ƒrœ|j dƒSt|tjtfƒr¾t |ƒStt|ddƒƒsÚdSt|jƒƒS(Ncss'|]\}}|t|ƒfVqdS(N(tjson_serialize(t.0tktv((s)/home/mkosek/freeipa-clean/ipalib/util.pys .ssutf-8t__json__t(t isinstancetlistttupleR tdictt iteritemstbooltfloattinttlongtunicodeRtstrtdecodetdecimaltDecimalRtcallabletgetattrtNoneR(tobjto((s)/home/mkosek/freeipa-clean/ipalib/util.pyR *s!  cCsry/ddl}t|jƒjƒjƒjƒSWn<tk rNtdƒ‚n |jk rmt j ƒ‚nXdS(Niÿÿÿÿspython-krbV is not available.( tkrbVRtdefault_contexttdefault_ccachet principaltnamet ImportErrort RuntimeErrort Krb5ErrorRt CCacheError(R#((s)/home/mkosek/freeipa-clean/ipalib/util.pytget_current_principal:s # ccsñtjj|ƒ|ko'tjj|ƒs.dStjj|ƒrDdSd}x ttj|ƒƒD]‰}|j|ƒs{q`ntjj||ƒ}tjj|ƒs`tjj |ƒ r»q`n|t |ƒ }|dkrÞq`n||fVq`WdS(s< Iterate through module names found in ``src_dir``. Ns.pyt__init__( tostpathtabspathtisdirtislinktsortedtlistdirtendswithtjointisfiletlen(tsrc_dirtsuffixR'tpyfiletmodule((s)/home/mkosek/freeipa-clean/ipalib/util.pytfind_modules_in_dirGs*% cCsƒyLtj|tjƒ}|jdt|ƒ|djd„|DƒƒfƒWn0tk r~}|jd|ƒtj ƒ‚nXdS(s1 See if the hostname has a DNS A record. s IPA: found %d records for %s: %st css|]}t|ƒVqdS(N(R(R tanswer((s)/home/mkosek/freeipa-clean/ipalib/util.pys dss&IPA: DNS A record lookup failed for %sN( RtqueryRtAtdebugR8R6RRtDNSNotARecordError(tlogtfqdntanswerste((s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_host_dns\s" cCsxytj|tjƒt}Wntk r6t}nXytj|tjƒt}Wntk rmt}nX|pw|S(sX Checks to see if given domain has SOA or NS record. Returns True or False. (RR@RtSOAtTrueRtFalsetNS(tdomaintsoa_record_foundtns_record_found((s)/home/mkosek/freeipa-clean/ipalib/util.pythas_soa_or_ns_recordms      cCsÓtƒ}|jdƒ}t|ƒdkrat|dƒjƒ|dõs(R5RStmap(t domain_nameR((Rs)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_domain_nameîs csÁtjdtjƒ‰tdƒ}d}d}d}t|ƒdkrZttdƒƒ‚n|jdƒrv|d }n|jdƒdkr¦|j dƒ\}}}n£|jdƒdkrÐttd ƒƒ‚ny|j d ƒ}|dkr1d }|j d|d ƒ}|dkrI|| }||d}qIn|j dƒ\}}}|sdttd ƒƒ‚nt |ƒ|s‰ttd ƒƒ‚nt ‡fd†|j|ƒDƒƒs½t|ƒ‚ndS(s See RFC 1033, 1035 s ^[a-z0-9]([a-z0-9-_]?[a-z0-9])*$sžmail account may only include letters, numbers, -, _ and a dot. There may not be consecutive -, _ and . characters. Its parts may not start or end with - or _Rqiÿs$cannot be longer that 255 charactersiÿÿÿÿRQistoo many '@' characterss\.ismissing address domainsmissing mail accountc3s|]}ˆj|ƒVqdS(N(RY(R tpart(tregex_local_part(s)/home/mkosek/freeipa-clean/ipalib/util.pys sN(RXR{R|RR R8R}R5tcountRrtrfindtfindR‰tallRS(Rttlocal_part_errmsgtlocal_part_sept local_partRMtdott last_fake_septsep((R‹s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_zonemgrøs<        cCs¬t|ƒdkr'ttdƒƒ‚n|jdƒrC|d }nd|krdttdƒƒ‚nd|kr›|r‹ttdƒƒ‚nt||ƒn t||ƒdS( su See RFC 952, 1123 :param hostname Checked value :param check_fqdn Check if hostname is fully qualified iÿs$cannot be longer that 255 charactersRqiÿÿÿÿs..s0hostname contains empty label (consecutive dots)snot fully qualifiedN(R8R}RR5R„R‰(thostnamet check_fqdnR((s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_hostname"s   cCst|ƒjƒS(N(Rtopenssh(tvalue((s)/home/mkosek/freeipa-clean/ipalib/util.pytnormalize_sshpubkey8scCs/yt|ƒWntk r*}tdƒSXdS(Nsinvalid SSH public key(RR}R(tugettextR›tUnicodeDecodeError((s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_sshpubkey;scCsGyt|ƒ}Wntk r,}tdƒSX|jƒrCtdƒSdS(Nsinvalid SSH public keysoptions are not allowed(RR}Rt has_options(RR›tpubkeyRž((s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_sshpubkey_no_optionsAs   c Cs.d|kr|d}n(|j|dgƒ}|djdƒ}|sKdSg}g}xž|D]–}yt|ƒ}Wntk rŒ}q^nX|jƒ} |jƒ} | r¾d| | f} nd| |jƒf} |j|jƒƒ|j| ƒq^Wd|kr|p d|ds(RxtanytREVERSE_DNS_ZONESRJRK(Rí((Rís)/home/mkosek/freeipa-clean/ipalib/util.pytzone_is_reverses cCsrtjt|ƒƒ}|jjdƒ}|jdkrC|d}n|jdkr_|d}ntdj|ƒƒS(NRqiiii(tnetaddrt IPAddressRt reverse_dnsRStversionRxR6(t ip_addresstiptitems((s)/home/mkosek/freeipa-clean/ipalib/util.pytget_reverse_zone_default"s  cCs1yt|ƒ}Wntk r,}t|ƒSXdS(N(R t ExceptionRR (RR›trdnRG((s)/home/mkosek/freeipa-clean/ipalib/util.pytvalidate_rdn_param-s  i8"i i€3ái8"i i€3ái8"i i€3áiÐiÀ¨i'iÐiÀ¨i'i¨i`'i€: i¨i`'i€: i¨i`'i€: i i€Qi i€Qi i€Qiii(RARàRá(Rê(<R¾R.timpttimeR\RXRRñttypesRtweakrefRtdnsRRt dns.exceptionRtipalibRt ipalib.textRt ipapython.sshRt ipapython.dnRR R R,R=RHRPRWR[RbRpRvRxRKR„R‰R–RJR™RœRŸR¢R²tobjectR³R{R|RÖRÙRßRéRìRïRðRøRû(((s)/home/mkosek/freeipa-clean/ipalib/util.pyts†                   *   #  G     freeipa-3.3.4/ipalib/parameters.py0000664000175000017500000017621212271663206016475 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Parameter system for command plugins. A `Param` instance can be used to describe an argument or option that a command takes, or an attribute that a command returns. The `Param` base class is not used directly, but there are many subclasses for specific Python data types (like `Str` or `Int`) and specific properties (like `Password`). To create a `Param` instance, you must always provide the parameter *name*, which should be the LDAP attribute name if the parameter describes the attribute of an LDAP entry. For example, we could create an `Str` instance describing the user's last-name attribute like this: >>> from ipalib import Str >>> sn = Str('sn') >>> sn.name 'sn' When creating a `Param`, there are also a number of optional kwargs which which can provide additional meta-data and functionality. For example, every parameter has a *cli_name*, the name used on the command-line-interface. By default the *cli_name* is the same as the *name*: >>> sn.cli_name 'sn' But often the LDAP attribute name isn't user friendly for the command-line, so you can override this with the *cli_name* kwarg: >>> sn = Str('sn', cli_name='last') >>> sn.name 'sn' >>> sn.cli_name 'last' Note that the RPC interfaces (and the internal processing pipeline) always use the parameter *name*, regardless of what the *cli_name* might be. A `Param` also has two translatable kwargs: *label* and *doc*. These must both be `Gettext` instances. They both default to a place-holder `FixMe` instance, a subclass of `Gettext` used to mark a missing translatable string: >>> sn.label FixMe('sn') >>> sn.doc FixMe('sn') The *label* is a short phrase describing the parameter. It's used on the CLI when interactively prompting for values, and as a label for form inputs in the web-UI. The *label* should start with an initial capital. For example: >>> from ipalib import _ >>> sn = Str('sn', ... cli_name='last', ... label=_('Last name'), ... ) >>> sn.label Gettext('Last name', domain='ipa', localedir=None) The *doc* is a longer description of the parameter. It's used on the CLI when displaying the help information for a command, and as extra instruction for a form input on the web-UI. By default the *doc* is the same as the *label*: >>> sn.doc Gettext('Last name', domain='ipa', localedir=None) But you can override this with the *doc* kwarg. Like the *label*, the *doc* should also start with an initial capital and should not end with any punctuation. For example: >>> sn = Str('sn', ... cli_name='last', ... label=_('Last name'), ... doc=_("The user's last name"), ... ) >>> sn.doc Gettext("The user's last name", domain='ipa', localedir=None) Demonstration aside, you should always provide at least the *label* so the various UIs are translatable. Only provide the *doc* if the parameter needs a more detailed description for clarity. """ import re import decimal import base64 from xmlrpclib import MAXINT, MININT from types import NoneType from text import _ as ugettext from plugable import ReadOnly, lock, check_name from errors import ConversionError, RequirementError, ValidationError from errors import PasswordMismatch, Base64DecodeError from constants import NULLS, TYPE_ERROR, CALLABLE_ERROR from text import Gettext, FixMe from util import json_serialize from ipapython.dn import DN class DefaultFrom(ReadOnly): """ Derive a default value from other supplied values. For example, say you wanted to create a default for the user's login from the user's first and last names. It could be implemented like this: >>> login = DefaultFrom(lambda first, last: first[0] + last) >>> login(first='John', last='Doe') 'JDoe' If you do not explicitly provide keys when you create a `DefaultFrom` instance, the keys are implicitly derived from your callback by inspecting ``callback.func_code.co_varnames``. The keys are available through the ``DefaultFrom.keys`` instance attribute, like this: >>> login.keys ('first', 'last') The callback is available through the ``DefaultFrom.callback`` instance attribute, like this: >>> login.callback # doctest:+ELLIPSIS at 0x...> >>> login.callback.func_code.co_varnames # The keys ('first', 'last') The keys can be explicitly provided as optional positional arguments after the callback. For example, this is equivalent to the ``login`` instance above: >>> login2 = DefaultFrom(lambda a, b: a[0] + b, 'first', 'last') >>> login2.keys ('first', 'last') >>> login2.callback.func_code.co_varnames # Not the keys ('a', 'b') >>> login2(first='John', last='Doe') 'JDoe' If any keys are missing when calling your `DefaultFrom` instance, your callback is not called and ``None`` is returned. For example: >>> login(first='John', lastname='Doe') is None True >>> login() is None True Any additional keys are simply ignored, like this: >>> login(last='Doe', first='John', middle='Whatever') 'JDoe' As above, because `DefaultFrom.__call__` takes only pure keyword arguments, they can be supplied in any order. Of course, the callback need not be a ``lambda`` expression. This third example is equivalent to both the ``login`` and ``login2`` instances above: >>> def get_login(first, last): ... return first[0] + last ... >>> login3 = DefaultFrom(get_login) >>> login3.keys ('first', 'last') >>> login3.callback.func_code.co_varnames ('first', 'last') >>> login3(first='John', last='Doe') 'JDoe' """ def __init__(self, callback, *keys): """ :param callback: The callable to call when all keys are present. :param keys: Optional keys used for source values. """ if not callable(callback): raise TypeError( CALLABLE_ERROR % ('callback', callback, type(callback)) ) self.callback = callback if len(keys) == 0: fc = callback.func_code if fc.co_flags & 0x0c: raise ValueError("callback: variable-length argument list not allowed") self.keys = fc.co_varnames[:fc.co_argcount] else: self.keys = keys for key in self.keys: if type(key) is not str: raise TypeError( TYPE_ERROR % ('keys', str, key, type(key)) ) lock(self) def __repr__(self): args = (self.callback.__name__,) + tuple(repr(k) for k in self.keys) return '%s(%s)' % ( self.__class__.__name__, ', '.join(args) ) def __call__(self, **kw): """ Call the callback if all keys are present. If all keys are present, the callback is called and its return value is returned. If any keys are missing, ``None`` is returned. :param kw: The keyword arguments. """ vals = tuple(kw.get(k, None) for k in self.keys) if None in vals: return try: return self.callback(*vals) except StandardError: pass def parse_param_spec(spec): """ Parse shorthand ``spec`` into to ``(name, kw)``. The ``spec`` string determines the parameter name, whether the parameter is required, and whether the parameter is multivalue according the following syntax: ====== ===== ======== ========== Spec Name Required Multivalue ====== ===== ======== ========== 'var' 'var' True False 'var?' 'var' False False 'var*' 'var' False True 'var+' 'var' True True ====== ===== ======== ========== For example, >>> parse_param_spec('login') ('login', {'required': True, 'multivalue': False}) >>> parse_param_spec('gecos?') ('gecos', {'required': False, 'multivalue': False}) >>> parse_param_spec('telephone_numbers*') ('telephone_numbers', {'required': False, 'multivalue': True}) >>> parse_param_spec('group+') ('group', {'required': True, 'multivalue': True}) :param spec: A spec string. """ if type(spec) is not str: raise TypeError( TYPE_ERROR % ('spec', str, spec, type(spec)) ) _map = { '?': dict(required=False, multivalue=False), '*': dict(required=False, multivalue=True), '+': dict(required=True, multivalue=True), } end = spec[-1] if end in _map: return (spec[:-1], _map[end]) return (spec, dict(required=True, multivalue=False)) __messages = set() def _(message): __messages.add(message) return message class Param(ReadOnly): """ Base class for all parameters. Param attributes: ================= The behavior of Param class and subclasses can be controlled using the following set of attributes: - cli_name: option name in CLI - cli_short_name: one character version of cli_name - label: very short description of the parameter. This value is used in when the Command output is printed to CLI or in a Command help - doc: parameter long description used in help - required: the parameter is marked as required for given Command - multivalue: indicates if the attribute is multivalued - primary_key: Command's parameter primary key is used for unique identification of an LDAP object and for sorting - normalizer: a custom function for Param value normalization - default_from: a custom function for generating default values of parameter instance - autofill: by default, only `required` parameters get a default value from the default_from function. When autofill is enabled, optional attributes get the default value filled too - query: this attribute is controlled by framework. When the `query` is enabled, framework assumes that the value is only queried and not inserted in the LDAP. Validation is then relaxed - custom parameter validators are skipped and only basic class validators are executed to check the parameter value - attribute: this attribute is controlled by framework and enabled for all LDAP objects parameters (unless parameter has "virtual_attribute" flag). All parameters with enabled `attribute` are being encoded and placed to an entry passed to LDAP Create/Update calls - include: a list of contexts where this parameter should be included. `Param.use_in_context()` provides further information. - exclude: a list of contexts where this parameter should be excluded. `Param.use_in_context()` provides further information. - flags: there are several flags that can be used to further tune the parameter behavior: * no_display (Output parameters only): do not display the parameter * no_create: do not include the parameter for crud.Create based commands * no_update: do not include the parameter for crud.update based commands * no_option: this attribute is not displayed in the CLI, usually because there's a better way of setting it (for example, a separate command) * virtual_attribute: the parameter is not stored physically in the LDAP and thus attribute `attribute` is not enabled * suppress_empty (Output parameters only): do not display parameter value when empty * ask_create: CLI asks for parameter value even when the parameter is not `required`. Applied for all crud.Create based commands * ask_update: CLI asks for parameter value even when the parameter is not `required`. Applied for all crud.Update based commands * req_update: The parameter is `required` in all crud.Update based commands * nonempty: This is an internal flag; a required attribute should be used instead of it. The value of this parameter must not be empty, but it may not be given at all. All crud.Update commands automatically convert required parameters to `nonempty` ones, so the value can be unspecified (unchanged) but cannot be deleted. - hint: this attribute is currently not used - alwaysask: when enabled, CLI asks for parameter value even when the parameter is not `required` - sortorder: used to sort a list of parameters for Command. See `Command.finalize()` for further information - csv: this multivalue attribute used to be given in CSV format in CLI """ # This is a dummy type so that most of the functionality of Param can be # unit tested directly without always creating a subclass; however, a real # (direct) subclass must *always* override this class attribute: type = NoneType # Ouch, this wont be very useful in the real world! # Subclasses should override this with something more specific: type_error = _('incorrect type') # _convert_scalar operates only on scalar values scalar_error = _('Only one value is allowed') kwargs = ( ('cli_name', str, None), ('cli_short_name', str, None), ('label', (basestring, Gettext), None), ('doc', (basestring, Gettext), None), ('required', bool, True), ('multivalue', bool, False), ('primary_key', bool, False), ('normalizer', callable, None), ('default_from', DefaultFrom, None), ('autofill', bool, False), ('query', bool, False), ('attribute', bool, False), ('include', frozenset, None), ('exclude', frozenset, None), ('flags', frozenset, frozenset()), ('hint', (str, Gettext), None), ('alwaysask', bool, False), ('sortorder', int, 2), # see finalize() ('csv', bool, False), ('option_group', unicode, None), # The 'default' kwarg gets appended in Param.__init__(): # ('default', self.type, None), ) def __init__(self, name, *rules, **kw): # We keep these values to use in __repr__(): self.param_spec = name self.__kw = dict(kw) if isinstance(self, Password): self.password = True else: self.password = False # Merge in kw from parse_param_spec(): (name, kw_from_spec) = parse_param_spec(name) if not 'required' in kw: kw['required'] = kw_from_spec['required'] if not 'multivalue' in kw: kw['multivalue'] = kw_from_spec['multivalue'] self.name = check_name(name) self.nice = '%s(%r)' % (self.__class__.__name__, self.param_spec) # Add 'default' to self.kwargs and makes sure no unknown kw were given: assert type(self.type) is type if kw.get('multivalue', True): self.kwargs += (('default', tuple, None),) else: self.kwargs += (('default', self.type, None),) if not set(t[0] for t in self.kwargs).issuperset(self.__kw): extra = set(kw) - set(t[0] for t in self.kwargs) raise TypeError( '%s: takes no such kwargs: %s' % (self.nice, ', '.join(repr(k) for k in sorted(extra)) ) ) # Merge in default for 'cli_name', label, doc if not given: if kw.get('cli_name') is None: kw['cli_name'] = self.name if kw.get('label') is None: kw['label'] = FixMe(self.name) if kw.get('doc') is None: kw['doc'] = kw['label'] # Wrap 'default_from' in a DefaultFrom if not already: df = kw.get('default_from', None) if callable(df) and not isinstance(df, DefaultFrom): kw['default_from'] = DefaultFrom(df) # We keep this copy with merged values also to use when cloning: self.__clonekw = kw # Perform type validation on kw, add in class rules: class_rules = [] for (key, kind, default) in self.kwargs: value = kw.get(key, default) if value is not None: if kind is frozenset: if type(value) in (list, tuple): value = frozenset(value) elif type(value) is str: value = frozenset([value]) if ( type(kind) is type and not isinstance(value, kind) or type(kind) is tuple and not isinstance(value, kind) ): raise TypeError( TYPE_ERROR % (key, kind, value, type(value)) ) elif kind is callable and not callable(value): raise TypeError( CALLABLE_ERROR % (key, value, type(value)) ) if hasattr(self, key): raise ValueError('kwarg %r conflicts with attribute on %s' % ( key, self.__class__.__name__) ) setattr(self, key, value) rule_name = '_rule_%s' % key if value is not None and hasattr(self, rule_name): class_rules.append(getattr(self, rule_name)) check_name(self.cli_name) # Check that only 'include' or 'exclude' was provided: if None not in (self.include, self.exclude): raise ValueError( '%s: cannot have both %s=%r and %s=%r' % ( self.nice, 'include', self.include, 'exclude', self.exclude, ) ) # Check that if csv is set, multivalue is set too if self.csv and not self.multivalue: raise ValueError('%s: cannot have csv without multivalue' % self.nice) # Check that all the rules are callable self.class_rules = tuple(class_rules) self.rules = rules if self.query: # by definition a query enforces no class or parameter rules self.all_rules = () else: self.all_rules = self.class_rules + self.rules for rule in self.all_rules: if not callable(rule): raise TypeError( '%s: rules must be callable; got %r' % (self.nice, rule) ) # Check that cli_short_name is only 1 character long: if not (self.cli_short_name is None or len(self.cli_short_name) == 1): raise ValueError( '%s: cli_short_name can only be a single character: %s' % ( self.nice, self.cli_short_name) ) # And we're done. lock(self) def __repr__(self): """ Return an expresion that could construct this `Param` instance. """ return '%s(%s)' % ( self.__class__.__name__, ', '.join(self.__repr_iter()) ) def __repr_iter(self): yield repr(self.param_spec) for rule in self.rules: yield rule.__name__ for key in sorted(self.__kw): value = self.__kw[key] if callable(value) and hasattr(value, '__name__'): value = value.__name__ else: value = repr(value) yield '%s=%s' % (key, value) def __call__(self, value, **kw): """ One stop shopping. """ if value in NULLS: value = self.get_default(**kw) else: value = self.convert(self.normalize(value)) if hasattr(self, 'env'): self.validate(value, self.env.context, supplied=self.name in kw) #pylint: disable=E1101 else: self.validate(value, supplied=self.name in kw) return value def get_param_name(self): """ Return the right name of an attribute depending on usage. Normally errors should use cli_name, our "friendly" name. When using the API directly or *attr return the real name. """ name = self.cli_name if not name: name = self.name return name def kw(self): """ Iterate through ``(key,value)`` for all kwargs passed to constructor. """ for key in sorted(self.__kw): value = self.__kw[key] if callable(value) and hasattr(value, '__name__'): value = value.__name__ yield (key, value) def use_in_context(self, env): """ Return ``True`` if this parameter should be used in ``env.context``. If a parameter is created with niether the ``include`` nor the ``exclude`` kwarg, this method will always return ``True``. For example: >>> from ipalib.config import Env >>> param = Param('my_param') >>> param.use_in_context(Env(context='foo')) True >>> param.use_in_context(Env(context='bar')) True If a parameter is created with an ``include`` kwarg, this method will only return ``True`` if ``env.context`` is in ``include``. For example: >>> param = Param('my_param', include=['foo', 'whatever']) >>> param.include frozenset(['foo', 'whatever']) >>> param.use_in_context(Env(context='foo')) True >>> param.use_in_context(Env(context='bar')) False If a paremeter is created with an ``exclude`` kwarg, this method will only return ``True`` if ``env.context`` is not in ``exclude``. For example: >>> param = Param('my_param', exclude=['foo', 'whatever']) >>> param.exclude frozenset(['foo', 'whatever']) >>> param.use_in_context(Env(context='foo')) False >>> param.use_in_context(Env(context='bar')) True Note that the ``include`` and ``exclude`` kwargs are mutually exclusive and that at most one can be suppelied to `Param.__init__()`. For example: >>> param = Param('nope', include=['foo'], exclude=['bar']) Traceback (most recent call last): ... ValueError: Param('nope'): cannot have both include=frozenset(['foo']) and exclude=frozenset(['bar']) So that subclasses can add additional logic based on other environment variables, the entire `config.Env` instance is passed in rather than just the value of ``env.context``. """ if self.include is not None: return (env.context in self.include) if self.exclude is not None: return (env.context not in self.exclude) return True def safe_value(self, value): """ Return a value safe for logging. This is used so that passwords don't get logged. If this is a `Password` instance and ``value`` is not ``None``, a constant ``u'********'`` is returned. For example: >>> p = Password('my_password') >>> p.safe_value(u'This is my password') u'********' >>> p.safe_value(None) is None True If this is not a `Password` instance, ``value`` is returned unchanged. For example: >>> s = Str('my_str') >>> s.safe_value(u'Some arbitrary value') u'Some arbitrary value' """ if self.password and value is not None: return u'********' return value def clone(self, **overrides): """ Return a new `Param` instance similar to this one. """ return self.clone_rename(self.name, **overrides) def clone_rename(self, name, **overrides): """ Return a new `Param` instance similar to this one, but named differently """ return self.clone_retype(name, self.__class__, **overrides) def clone_retype(self, name, klass, **overrides): """ Return a new `Param` instance similar to this one, but of a different type """ kw = dict(self.__clonekw) kw.update(overrides) return klass(name, *self.rules, **kw) def normalize(self, value): """ Normalize ``value`` using normalizer callback. For example: >>> param = Param('telephone', ... normalizer=lambda value: value.replace('.', '-') ... ) >>> param.normalize(u'800.123.4567') u'800-123-4567' If this `Param` instance was created with a normalizer callback and ``value`` is a unicode instance, the normalizer callback is called and *its* return value is returned. On the other hand, if this `Param` instance was *not* created with a normalizer callback, if ``value`` is *not* a unicode instance, or if an exception is caught when calling the normalizer callback, ``value`` is returned unchanged. :param value: A proposed value for this parameter. """ if self.multivalue: if type(value) not in (tuple, list): value = (value,) if self.multivalue: return tuple( self._normalize_scalar(v) for v in value ) else: return self._normalize_scalar(value) def _normalize_scalar(self, value): """ Normalize a scalar value. This method is called once for each value in a multivalue. """ if self.normalizer is None: return value try: return self.normalizer(value) except StandardError: return value def convert(self, value): """ Convert ``value`` to the Python type required by this parameter. For example: >>> scalar = Str('my_scalar') >>> scalar.type >>> scalar.convert(43.2) u'43.2' (Note that `Str` is a subclass of `Param`.) All values in `constants.NULLS` will be converted to ``None``. For example: >>> scalar.convert(u'') is None # An empty string True >>> scalar.convert([]) is None # An empty list True Likewise, values in `constants.NULLS` will be filtered out of a multivalue parameter. For example: >>> multi = Str('my_multi', multivalue=True) >>> multi.convert([1.5, '', 17, None, u'Hello']) (u'1.5', u'17', u'Hello') >>> multi.convert([None, u'']) is None # Filters to an empty list True Lastly, multivalue parameters will always return a ``tuple`` (assuming they don't return ``None`` as in the last example above). For example: >>> multi.convert(42) # Called with a scalar value (u'42',) >>> multi.convert([0, 1]) # Called with a list value (u'0', u'1') Note that how values are converted (and from what types they will be converted) completely depends upon how a subclass implements its `Param._convert_scalar()` method. For example, see `Str._convert_scalar()`. :param value: A proposed value for this parameter. """ if value in NULLS: return if self.multivalue: if type(value) not in (tuple, list): value = (value,) values = tuple( self._convert_scalar(v, i) for (i, v) in filter( lambda iv: iv[1] not in NULLS, enumerate(value) ) ) if len(values) == 0: return return values return self._convert_scalar(value) def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) is self.type: return value raise ConversionError(name=self.name, index=index, error=ugettext(self.type_error), ) def validate(self, value, context=None, supplied=None): """ Check validity of ``value``. :param value: A proposed value for this parameter. :param context: The context we are running in. :param supplied: True if this parameter was supplied explicitly. """ if value is None: if self.required or (supplied and 'nonempty' in self.flags): if context == 'cli': raise RequirementError(name=self.cli_name) else: raise RequirementError(name=self.name) return if self.multivalue: if type(value) is not tuple: raise TypeError( TYPE_ERROR % ('value', tuple, value, type(value)) ) if len(value) < 1: raise ValueError('value: empty tuple must be converted to None') for (i, v) in enumerate(value): self._validate_scalar(v, i) else: self._validate_scalar(value) def _validate_scalar(self, value, index=None): if type(value) is not self.type: raise TypeError( TYPE_ERROR % (self.name, self.type, value, type(value)) ) if index is not None and type(index) is not int: raise TypeError( TYPE_ERROR % ('index', int, index, type(index)) ) for rule in self.all_rules: error = rule(ugettext, value) if error is not None: raise ValidationError( name=self.get_param_name(), value=value, index=index, error=error, rule=rule, ) def get_default(self, **kw): """ Return the static default or construct and return a dynamic default. (In these examples, we will use the `Str` and `Bytes` classes, which both subclass from `Param`.) The *default* static default is ``None``. For example: >>> s = Str('my_str') >>> s.default is None True >>> s.get_default() is None True However, you can provide your own static default via the ``default`` keyword argument when you create your `Param` instance. For example: >>> s = Str('my_str', default=u'My Static Default') >>> s.default u'My Static Default' >>> s.get_default() u'My Static Default' If you need to generate a dynamic default from other supplied parameter values, provide a callback via the ``default_from`` keyword argument. This callback will be automatically wrapped in a `DefaultFrom` instance if it isn't one already (see the `DefaultFrom` class for all the gory details). For example: >>> login = Str('login', default=u'my-static-login-default', ... default_from=lambda first, last: (first[0] + last).lower(), ... ) >>> isinstance(login.default_from, DefaultFrom) True >>> login.default_from.keys ('first', 'last') Then when all the keys needed by the `DefaultFrom` instance are present, the dynamic default is constructed and returned. For example: >>> kw = dict(last=u'Doe', first=u'John') >>> login.get_default(**kw) u'jdoe' Or if any keys are missing, your *static* default is returned. For example: >>> kw = dict(first=u'John', department=u'Engineering') >>> login.get_default(**kw) u'my-static-login-default' """ if self.default_from is not None: default = self.default_from(**kw) if default is not None: try: return self.convert(self.normalize(default)) except StandardError: pass return self.default json_exclude_attrs = ( 'alwaysask', 'autofill', 'cli_name', 'cli_short_name', 'csv', 'sortorder', 'falsehoods', 'truths', 'version', ) def __json__(self): json_dict = {} for (a, k, d) in self.kwargs: if a in self.json_exclude_attrs: continue if k in (callable, DefaultFrom): continue elif isinstance(getattr(self, a), frozenset): json_dict[a] = [k for k in getattr(self, a, [])] else: val = getattr(self, a, '') if val is None or val is False: # ignore False and not set because lack of their presence is # the information itself continue; json_dict[a] = json_serialize(val) json_dict['class'] = self.__class__.__name__ json_dict['name'] = self.name json_dict['type'] = self.type.__name__ return json_dict class Bool(Param): """ A parameter for boolean values (stored in the ``bool`` type). """ type = bool type_error = _('must be True or False') # FIXME: This my quick hack to get some UI stuff working, change these defaults # --jderose 2009-08-28 kwargs = Param.kwargs + ( ('truths', frozenset, frozenset([1, u'1', True, u'true', u'TRUE'])), ('falsehoods', frozenset, frozenset([0, u'0', False, u'false', u'FALSE'])), ) def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) is self.type: return value if isinstance(value, basestring): value = value.lower() if value in self.truths: return True if value in self.falsehoods: return False if type(value) in (tuple, list): raise ConversionError(name=self.name, index=index, error=ugettext(self.scalar_error)) raise ConversionError(name=self.name, index=index, error=ugettext(self.type_error), ) class Flag(Bool): """ A boolean parameter that always gets filled in with a default value. This `Bool` subclass forces ``autofill=True`` in `Flag.__init__()`. If no default is provided, it also fills in a default value of ``False``. Lastly, unlike the `Bool` class, the default must be either ``True`` or ``False`` and cannot be ``None``. For example: >>> flag = Flag('my_flag') >>> (flag.autofill, flag.default) (True, False) To have a default value of ``True``, create your `Flag` intance with ``default=True``. For example: >>> flag = Flag('my_flag', default=True) >>> (flag.autofill, flag.default) (True, True) Also note that creating a `Flag` instance with ``autofill=False`` will have no effect. For example: >>> flag = Flag('my_flag', autofill=False) >>> flag.autofill True """ def __init__(self, name, *rules, **kw): kw['autofill'] = True if 'default' not in kw: kw['default'] = False if type(kw['default']) is not bool: default = kw['default'] raise TypeError( TYPE_ERROR % ('default', bool, default, type(default)) ) super(Flag, self).__init__(name, *rules, **kw) class Number(Param): """ Base class for the `Int` and `Decimal` parameters. """ def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) is self.type: return value if type(value) in (unicode, int, long, float): try: return self.type(value) except ValueError: pass if type(value) in (tuple, list): raise ConversionError(name=self.name, index=index, error=ugettext(self.scalar_error)) raise ConversionError(name=self.name, index=index, error=ugettext(self.type_error), ) class Int(Number): """ A parameter for integer values (stored in the ``int`` type). """ type = int type_error = _('must be an integer') kwargs = Param.kwargs + ( ('minvalue', (int, long), int(MININT)), ('maxvalue', (int, long), int(MAXINT)), ) def __init__(self, name, *rules, **kw): super(Int, self).__init__(name, *rules, **kw) if (self.minvalue > self.maxvalue) and (self.minvalue is not None and self.maxvalue is not None): raise ValueError( '%s: minvalue > maxvalue (minvalue=%r, maxvalue=%r)' % ( self.nice, self.minvalue, self.maxvalue) ) def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) in (int, long): return value if type(value) is unicode: # permit floating point strings if value.find(u'.') >= 0: try: return int(float(value)) except ValueError: pass else: try: # 2nd arg is radix base, 2nd arg only accepted for strings. # Zero means determine radix base from prefix (e.g. 0x for hex) return int(value, 0) except ValueError: pass if type(value) is float: try: return int(value) except ValueError: pass raise ConversionError(name=self.get_param_name(), index=index, error=ugettext(self.type_error), ) def _rule_minvalue(self, _, value): """ Check min constraint. """ assert type(value) in (int, long) if value < self.minvalue: return _('must be at least %(minvalue)d') % dict( minvalue=self.minvalue, ) def _rule_maxvalue(self, _, value): """ Check max constraint. """ assert type(value) in (int, long) if value > self.maxvalue: return _('can be at most %(maxvalue)d') % dict( maxvalue=self.maxvalue, ) def _validate_scalar(self, value, index=None): """ This duplicates _validate_scalar in the Param class with the exception that it allows both int and long types. The min/max rules handle size enforcement. """ if type(value) not in (int, long): raise TypeError( TYPE_ERROR % (self.name, self.type, value, type(value)) ) if index is not None and type(index) is not int: raise TypeError( TYPE_ERROR % ('index', int, index, type(index)) ) for rule in self.all_rules: error = rule(ugettext, value) if error is not None: raise ValidationError( name=self.get_param_name(), value=value, index=index, error=error, rule=rule, ) class Decimal(Number): """ A parameter for floating-point values (stored in the ``Decimal`` type). Python Decimal type helps overcome problems tied to plain "float" type, e.g. problem with representation or value comparison. In order to safely transfer the value over RPC libraries, it is being converted to string which is then converted back to Decimal number. """ type = decimal.Decimal type_error = _('must be a decimal number') kwargs = Param.kwargs + ( ('minvalue', decimal.Decimal, None), ('maxvalue', decimal.Decimal, None), # round Decimal to given precision ('precision', int, None), # when False, number is normalized to non-exponential form ('exponential', bool, False), # set of allowed decimal number classes ('numberclass', tuple, ('-Normal', '+Zero', '+Normal')), ) def __init__(self, name, *rules, **kw): for kwparam in ('minvalue', 'maxvalue', 'default'): value = kw.get(kwparam) if value is None: continue if isinstance(value, (basestring, float)): try: value = decimal.Decimal(value) except Exception, e: raise ValueError( '%s: cannot parse kwarg %s: %s' % ( name, kwparam, str(e))) kw[kwparam] = value super(Decimal, self).__init__(name, *rules, **kw) if (self.minvalue > self.maxvalue) \ and (self.minvalue is not None and \ self.maxvalue is not None): raise ValueError( '%s: minvalue > maxvalue (minvalue=%s, maxvalue=%s)' % ( self.nice, self.minvalue, self.maxvalue) ) if self.precision is not None and self.precision < 0: raise ValueError('%s: precision must be at least 0' % self.nice) def _rule_minvalue(self, _, value): """ Check min constraint. """ assert type(value) is decimal.Decimal if value < self.minvalue: return _('must be at least %(minvalue)s') % dict( minvalue=self.minvalue, ) def _rule_maxvalue(self, _, value): """ Check max constraint. """ assert type(value) is decimal.Decimal if value > self.maxvalue: return _('can be at most %(maxvalue)s') % dict( maxvalue=self.maxvalue, ) def _enforce_numberclass(self, value): numberclass = value.number_class() if numberclass not in self.numberclass: raise ValidationError(name=self.get_param_name(), error=_("number class '%(cls)s' is not included in a list " "of allowed number classes: %(allowed)s") \ % dict(cls=numberclass, allowed=u', '.join(self.numberclass)) ) def _enforce_precision(self, value): assert type(value) is decimal.Decimal if self.precision is not None: quantize_exp = decimal.Decimal(10) ** -self.precision try: value = value.quantize(quantize_exp) except decimal.DecimalException, e: raise ConversionError(name=self.get_param_name(), error=unicode(e)) return value def _remove_exponent(self, value): assert type(value) is decimal.Decimal if not self.exponential: try: # adopted from http://docs.python.org/library/decimal.html value = value.quantize(decimal.Decimal(1)) \ if value == value.to_integral() \ else value.normalize() except decimal.DecimalException, e: raise ConversionError(name=self.get_param_name(), error=unicode(e)) return value def _test_and_normalize(self, value): """ This method is run in conversion and normalization methods to test that the Decimal number conforms to Parameter boundaries and then normalizes the value. """ self._enforce_numberclass(value) value = self._remove_exponent(value) value = self._enforce_precision(value) return value def _convert_scalar(self, value, index=None): if isinstance(value, (basestring, float)): try: value = decimal.Decimal(value) except decimal.DecimalException, e: raise ConversionError(name=self.get_param_name(), index=index, error=unicode(e)) if isinstance(value, decimal.Decimal): return self._test_and_normalize(value) return super(Decimal, self)._convert_scalar(value, index) def _normalize_scalar(self, value): if isinstance(value, decimal.Decimal): return self._test_and_normalize(value) return super(Decimal, self)._normalize_scalar(value) class Data(Param): """ Base class for the `Bytes` and `Str` parameters. Previously `Str` was as subclass of `Bytes`. Now the common functionality has been split into this base class so that ``isinstance(foo, Bytes)`` wont be ``True`` when ``foo`` is actually an `Str` instance (which is confusing). """ kwargs = Param.kwargs + ( ('minlength', int, None), ('maxlength', int, None), ('length', int, None), ('pattern', (basestring,), None), ('pattern_errmsg', (basestring,), None), ) re = None re_errmsg = None def __init__(self, name, *rules, **kw): super(Data, self).__init__(name, *rules, **kw) if not ( self.length is None or (self.minlength is None and self.maxlength is None) ): raise ValueError( '%s: cannot mix length with minlength or maxlength' % self.nice ) if self.minlength is not None and self.minlength < 1: raise ValueError( '%s: minlength must be >= 1; got %r' % (self.nice, self.minlength) ) if self.maxlength is not None and self.maxlength < 1: raise ValueError( '%s: maxlength must be >= 1; got %r' % (self.nice, self.maxlength) ) if None not in (self.minlength, self.maxlength): if self.minlength > self.maxlength: raise ValueError( '%s: minlength > maxlength (minlength=%r, maxlength=%r)' % ( self.nice, self.minlength, self.maxlength) ) elif self.minlength == self.maxlength: raise ValueError( '%s: minlength == maxlength; use length=%d instead' % ( self.nice, self.minlength) ) def _rule_pattern(self, _, value): """ Check pattern (regex) contraint. """ assert type(value) is self.type if self.re.match(value) is None: if self.re_errmsg: return self.re_errmsg % dict(pattern=self.pattern,) else: return _('must match pattern "%(pattern)s"') % dict( pattern=self.pattern, ) class Bytes(Data): """ A parameter for binary data (stored in the ``str`` type). This class is named *Bytes* instead of *Str* so it's aligned with the Python v3 ``(str, unicode) => (bytes, str)`` clean-up. See: http://docs.python.org/3.0/whatsnew/3.0.html Also see the `Str` parameter. """ type = str type_error = _('must be binary data') def __init__(self, name, *rules, **kw): if kw.get('pattern', None) is None: self.re = None else: self.re = re.compile(kw['pattern']) self.re_errmsg = kw.get('pattern_errmsg', None) super(Bytes, self).__init__(name, *rules, **kw) def _rule_minlength(self, _, value): """ Check minlength constraint. """ assert type(value) is str if len(value) < self.minlength: return _('must be at least %(minlength)d bytes') % dict( minlength=self.minlength, ) def _rule_maxlength(self, _, value): """ Check maxlength constraint. """ assert type(value) is str if len(value) > self.maxlength: return _('can be at most %(maxlength)d bytes') % dict( maxlength=self.maxlength, ) def _rule_length(self, _, value): """ Check length constraint. """ assert type(value) is str if len(value) != self.length: return _('must be exactly %(length)d bytes') % dict( length=self.length, ) def _convert_scalar(self, value, index=None): if isinstance(value, unicode): try: value = base64.b64decode(value) except TypeError, e: raise Base64DecodeError(reason=str(e)) return super(Bytes, self)._convert_scalar(value, index) class Str(Data): """ A parameter for Unicode text (stored in the ``unicode`` type). This class is named *Str* instead of *Unicode* so it's aligned with the Python v3 ``(str, unicode) => (bytes, str)`` clean-up. See: http://docs.python.org/3.0/whatsnew/3.0.html Also see the `Bytes` parameter. """ kwargs = Data.kwargs + ( ('noextrawhitespace', bool, True), ) type = unicode type_error = _('must be Unicode text') def __init__(self, name, *rules, **kw): if kw.get('pattern', None) is None: self.re = None else: self.re = re.compile(kw['pattern'], re.UNICODE) self.re_errmsg = kw.get('pattern_errmsg', None) super(Str, self).__init__(name, *rules, **kw) def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) is self.type: return value if type(value) in (int, long, float, decimal.Decimal): return self.type(value) if type(value) in (tuple, list): raise ConversionError(name=self.name, index=index, error=ugettext(self.scalar_error)) raise ConversionError(name=self.name, index=index, error=ugettext(self.type_error), ) def _rule_noextrawhitespace(self, _, value): """ Do not allow leading/trailing spaces. """ assert type(value) is unicode if self.noextrawhitespace is False: return if len(value) != len(value.strip()): return _('Leading and trailing spaces are not allowed') def _rule_minlength(self, _, value): """ Check minlength constraint. """ assert type(value) is unicode if len(value) < self.minlength: return _('must be at least %(minlength)d characters') % dict( minlength=self.minlength, ) def _rule_maxlength(self, _, value): """ Check maxlength constraint. """ assert type(value) is unicode if len(value) > self.maxlength: return _('can be at most %(maxlength)d characters') % dict( maxlength=self.maxlength, ) def _rule_length(self, _, value): """ Check length constraint. """ assert type(value) is unicode if len(value) != self.length: return _('must be exactly %(length)d characters') % dict( length=self.length, ) class IA5Str(Str): """ An IA5String per RFC 4517 """ def __init__(self, name, *rules, **kw): super(IA5Str, self).__init__(name, *rules, **kw) def _convert_scalar(self, value, index=None): if isinstance(value, basestring): for i in xrange(len(value)): if ord(value[i]) > 127: raise ConversionError(name=self.get_param_name(), index=index, error=_('The character %(char)r is not allowed.') % dict(char=value[i],) ) return super(IA5Str, self)._convert_scalar(value, index) class Password(Str): """ A parameter for passwords (stored in the ``unicode`` type). """ kwargs = Str.kwargs + ( ('confirm', bool, True), ) def _convert_scalar(self, value, index=None): if isinstance(value, (tuple, list)) and len(value) == 2: (p1, p2) = value if p1 != p2: raise PasswordMismatch(name=self.name, index=index) value = p1 return super(Password, self)._convert_scalar(value, index) class Enum(Param): """ Base class for parameters with enumerable values. """ kwargs = Param.kwargs + ( ('values', tuple, tuple()), ) def __init__(self, name, *rules, **kw): super(Enum, self).__init__(name, *rules, **kw) for (i, v) in enumerate(self.values): if type(v) is not self.type: n = '%s values[%d]' % (self.nice, i) raise TypeError( TYPE_ERROR % (n, self.type, v, type(v)) ) if len(self.values) < 1: raise ValueError( '%s: list of values must not be empty' % self.nice) def _rule_values(self, _, value, **kw): if value not in self.values: if len(self.values) == 1: return _("must be '%(value)s'") % dict(value=self.values[0]) else: values = u', '.join("'%s'" % value for value in self.values) return _('must be one of %(values)s') % dict(values=values) class BytesEnum(Enum): """ Enumerable for binary data (stored in the ``str`` type). """ type = unicode class StrEnum(Enum): """ Enumerable for Unicode text (stored in the ``unicode`` type). For example: >>> enum = StrEnum('my_enum', values=(u'One', u'Two', u'Three')) >>> enum.validate(u'Two', 'cli') is None True >>> enum.validate(u'Four', 'cli') Traceback (most recent call last): ... ValidationError: invalid 'my_enum': must be one of 'One', 'Two', 'Three' """ type = unicode class Any(Param): """ A parameter capable of holding values of any type. For internal use only. """ type = object def _convert_scalar(self, value, index=None): return value def _validate_scalar(self, value, index=None): for rule in self.all_rules: error = rule(ugettext, value) if error is not None: raise ValidationError( name=self.name, value=value, index=index, error=error, rule=rule, ) class File(Str): """ File parameter type. Accepts file names and loads their content into the parameter value. """ kwargs = Data.kwargs + ( # valid for CLI, other backends (e.g. webUI) can ignore this ('stdin_if_missing', bool, False), ('noextrawhitespace', bool, False), ) class AccessTime(Str): """ Access time parameter type. Accepts values conforming to generalizedTime as defined in RFC 4517 section 3.3.13 without time zone information. """ def _check_HHMM(self, t): if len(t) != 4: raise ValueError('HHMM must be exactly 4 characters long') if not t.isnumeric(): raise ValueError('HHMM non-numeric') hh = int(t[0:2]) if hh < 0 or hh > 23: raise ValueError('HH out of range') mm = int(t[2:4]) if mm < 0 or mm > 59: raise ValueError('MM out of range') def _check_dotw(self, t): if t.isnumeric(): value = int(t) if value < 1 or value > 7: raise ValueError('day of the week out of range') elif t not in ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'): raise ValueError('invalid day of the week') def _check_dotm(self, t, month_num=1, year=4): if not t.isnumeric(): raise ValueError('day of the month non-numeric') value = int(t) if month_num in (1, 3, 5, 7, 8, 10, 12): if value < 1 or value > 31: raise ValueError('day of the month out of range') elif month_num in (4, 6, 9, 11): if value < 1 or value > 30: raise ValueError('day of the month out of range') elif month_num == 2: if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0): if value < 1 or value > 29: raise ValueError('day of the month out of range') else: if value < 1 or value > 28: raise ValueError('day of the month out of range') def _check_wotm(self, t): if not t.isnumeric(): raise ValueError('week of the month non-numeric') value = int(t) if value < 1 or value > 6: raise ValueError('week of the month out of range') def _check_woty(self, t): if not t.isnumeric(): raise ValueError('week of the year non-numeric') value = int(t) if value < 1 or value > 52: raise ValueError('week of the year out of range') def _check_doty(self, t): if not t.isnumeric(): raise ValueError('day of the year non-numeric') value = int(t) if value < 1 or value > 365: raise ValueError('day of the year out of range') def _check_month_num(self, t): if not t.isnumeric(): raise ValueError('month number non-numeric') value = int(t) if value < 1 or value > 12: raise ValueError('month number out of range') def _check_interval(self, t, check_func): intervals = t.split(',') for i in intervals: if not i: raise ValueError('invalid time range') values = i.split('-') if len(values) > 2: raise ValueError('invalid time range') for v in values: check_func(v) if len(values) == 2: if int(values[0]) > int(values[1]): raise ValueError('invalid time range') def _check_W_spec(self, ts, index): if ts[index] != 'day': raise ValueError('invalid week specifier') index += 1 self._check_interval(ts[index], self._check_dotw) return index def _check_M_spec(self, ts, index): if ts[index] == 'week': self._check_interval(ts[index + 1], self._check_wotm) index = self._check_W_spec(ts, index + 2) elif ts[index] == 'day': index += 1 self._check_interval(ts[index], self._check_dotm) else: raise ValueError('invalid month specifier') return index def _check_Y_spec(self, ts, index): if ts[index] == 'month': index += 1 self._check_interval(ts[index], self._check_month_num) month_num = int(ts[index]) index = self._check_M_spec(ts, index + 1) elif ts[index] == 'week': self._check_interval(ts[index + 1], self._check_woty) index = self._check_W_spec(ts, index + 2) elif ts[index] == 'day': index += 1 self._check_interval(ts[index], self._check_doty) else: raise ValueError('invalid year specifier') return index def _check_generalized(self, t): assert type(t) is unicode if len(t) not in (10, 12, 14): raise ValueError('incomplete generalized time') if not t.isnumeric(): raise ValueError('time non-numeric') # don't check year value, with time travel and all :) self._check_month_num(t[4:6]) year_num = int(t[0:4]) month_num = int(t[4:6]) self._check_dotm(t[6:8], month_num, year_num) if len(t) >= 12: self._check_HHMM(t[8:12]) else: self._check_HHMM('%s00' % t[8:10]) if len(t) == 14: s = int(t[12:14]) if s < 0 or s > 60: raise ValueError('seconds out of range') def _check(self, time): ts = time.split() if ts[0] == 'absolute': if len(ts) != 4: raise ValueError('invalid format, must be \'absolute generalizedTime ~ generalizedTime\'') self._check_generalized(ts[1]) if ts[2] != '~': raise ValueError('invalid time range separator') self._check_generalized(ts[3]) if int(ts[1]) >= int(ts[3]): raise ValueError('invalid time range') elif ts[0] == 'periodic': index = None if ts[1] == 'yearly': index = self._check_Y_spec(ts, 2) elif ts[1] == 'monthly': index = self._check_M_spec(ts, 2) elif ts[1] == 'weekly': index = self._check_W_spec(ts, 2) elif ts[1] == 'daily': index = 1 if index is None: raise ValueError('period must be yearly, monthy or daily, got \'%s\'' % ts[1]) self._check_interval(ts[index + 1], self._check_HHMM) else: raise ValueError('time neither absolute or periodic') def _rule_required(self, _, value): try: self._check(value) except ValueError, e: raise ValidationError(name=self.get_param_name(), error=e.args[0]) except IndexError: raise ValidationError( name=self.get_param_name(), error=ugettext('incomplete time value') ) return None class DNParam(Param): type = DN def _convert_scalar(self, value, index=None): """ Convert a single scalar value. """ if type(value) is self.type: return value try: dn = DN(value) except Exception, e: raise ConversionError(name=self.get_param_name(), index=index, error=ugettext(e)) return dn class DeprecatedParam(Any): kwargs = Param.kwargs + ( ('deprecate', bool, True), ) def __init__(self, name, *rules, **kw): if 'flags' in kw: kw['flags'] = list(kw['flags']) + ['no_option'] else: kw['flags'] = ['no_option'] super(DeprecatedParam, self).__init__(name, *rules, **kw) def _rule_deprecate(self, _, value): return _('this option is deprecated') def create_param(spec): """ Create an `Str` instance from the shorthand ``spec``. This function allows you to create `Str` parameters (the most common) from a convenient shorthand that defines the parameter name, whether it is required, and whether it is multivalue. (For the definition of the shorthand syntax, see the `parse_param_spec()` function.) If ``spec`` is an ``str`` instance, it will be used to create a new `Str` parameter, which will be returned. For example: >>> s = create_param('hometown?') >>> s Str('hometown?') >>> (s.name, s.required, s.multivalue) ('hometown', False, False) On the other hand, if ``spec`` is already a `Param` instance, it is returned unchanged. For example: >>> b = Bytes('cert') >>> create_param(b) is b True As a plugin author, you will not call this function directly (which would be no more convenient than simply creating the `Str` instance). Instead, `frontend.Command` will call it for you when it evaluates the ``takes_args`` and ``takes_options`` attributes, and `frontend.Object` will call it for you when it evaluates the ``takes_params`` attribute. :param spec: A spec string or a `Param` instance. """ if isinstance(spec, Param): return spec if type(spec) is not str: raise TypeError( TYPE_ERROR % ('spec', (str, Param), spec, type(spec)) ) return Str(spec) freeipa-3.3.4/ipa.10000664000175000017500000002332612202434255013342 0ustar mkosekmkosek.\" A man page for ipa .\" Copyright (C) 2010 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Pavel Zuna .\" .TH "ipa" "1" "Jan 24 2012" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa \- IPA command\-line interface .SH "SYNOPSIS" .nf \fBipa\fR [options] [\fB\-c\fR \fIFILE\fR] [\fB\-e\fR \fIKEY=VAL\fR] \fICOMMAND\fR [parameters] .fi .SH "DESCRIPTION" IPA is an integrated security information management solution based on 389 Directory Server (formerly know as Fedora Directory Server), MIT Kerberos, Dogtag Certificate System, NTP and DNS. It includes a web interface and command\-line administration tools for managing identity data. This manual page focuses on the \fIipa\fR script that serves as the main command\-line interface (CLI) for IPA administration. More information about the project is available on its homepage located at http://www.freeipa.org. .SH "OPTIONS" .TP \fB\-c\fR \fIFILE\fR Load configuration from \fIFILE\fR. .TP \fB\-d\fR, \fB\-\-debug\fR Produce full debugging output. .TP \fB\-\-\-delegate\fR Delegate the user's TGT to the IPA server .TP \fB\-e\fR \fIKEY=VAL\fR Set environmental variable \fIKEY\fR to the value \fIVAL\fR. This option overrides configuration files. .TP \fB\-h\fR, \fB\-\-help\fR Display a help message with a list of options. .TP \fB\-n\fR, \fB\-\-no\-prompt\fR Don't prompt for any parameters of \fBCOMMAND\fR, even if they are required. .TP \fB\-a\fR, \fB\-\-prompt\-all\fR Prompt for all parameters of \fICOMMAND\fR, even if they are optional. .TP \fB\-f\fR, \fB\-\-no\-fallback\fR Don't fall back to other IPA servers if the default doesn't work. .TP \fB\-v\fR, \fB\-\-verbose\fR Produce verbose output. A second \-v displays the XML\-RPC request .SH "COMMANDS" The principal function of the CLI is to execute administrative commands specified by the \fICOMMAND\fR argument. The majority of commands are executed remotely over XML\-RPC on a IPA server listed in the configuration file (see FILES section of this manual page). From the implementation perspective, the CLI distinguishes two types of commands \- built\-ins and plugin provided. Built\-in commands are static and are all available in all installations of IPA. There are two of them: .TP \fBconsole\fR Start the IPA interactive Python console. .TP \fBhelp\fR [\fITOPIC\fR | \fICOMMAND\fR | \fBtopics\fR | \fBcommands\fR] Display help for a command or topic. The \fBhelp\fR command invokes the built\-in documentation system. Without parameters a list of built\-in commands and help topics is displayed. Help topics are generated from loaded IPA plugin modules. Executing \fBhelp\fR with the name of an available topic displays a help message provided by the corresponding plugin module and list of commands it contains. .LP Plugin provided commands, as the name suggests, originate from IPA plugin modules. The available set may vary depending on your configuration and can be listed using the built\-in \fBhelp\fR command (see above). Most plugin provided commands are tied to a certain type of IPA object. IPA objects encompass common abstractions such as users (user identities/accounts), hosts (machine identities), services, password policies, etc. Commands associated with an object are easily identified thanks to the enforced naming convention; the command names are composed of two parts separated with a dash: the name of the corresponding IPA object type and the name of action performed on it. For example all commands used to manage user identities start with "user\-" (e.g. user\-add, user\-del). The following actions are available for most IPA object types: .TP \fBadd\fR [\fIPRIMARYKEY\fR] [options] Create a new object. .TP \fBshow\fR [\fIPRIMARYKEY\fR] [options] Display an existing object. .TP \fBmod\fR [\fIPRIMARYKEY\fR] [options] Modify an existing object. .TP \fBdel\fR [\fIPRIMARYKEY\fR] Delete an existing object. .TP \fBfind\fR [\fICRITERIA\fR] [options] Search for existing objects. .LP The above types of commands except \fBfind\fR take the objects primary key (e.g. user name for users) as their only positional argument unless there can be only one object of the given type. They can also take a number of options (some of which might be required in the case of \fBadd\fR) that represent the objects attributes. \fBfind\fR commands take an optional criteria string as their only positional argument. If present, all objects with an attribute that contains the criteria string are displayed. If an option representing an attribute is set, only object with the attribute exactly matching the specified value are displayed. Options with empty values are ignored. Without parameters all objects of the corresponding type are displayed. For IPA objects with attributes that can contain references to other objects (e.g. groups), the following action are usually available: .TP \fBadd\-member\fR [\fIPRIMARYKEY\fR] [options] Add references to other objects. .TP \fBremove\-member\fR [\fIPRIMARYKEY\fR] [options] Remove references to other objects. .LP The above types of commands take the objects primary key as their only positional argument unless there can be only one object of the given type. They also take a number of options that represent lists of other object primary keys. Each of these options represent one type of object. For some types of objects, these commands might need to take more than one primary key. This applies to IPA objects organized in hierarchies where the parent object needs to be identified first. Parent primary keys are always aligned to the left (higher in the hierarchy = more to the left). For example the automount IPA plugin enables users to manage automount maps per location, as a result all automount commands take an automountlocation primary key as their first positional argument. All commands that display objects have three special options for controlling output: .TP \fB\-\-all\fR Display all attributes. Without this option only the most relevant attributes are displayed. .TP \fB\-\-raw\fR Display objects as they are stored in the backing store. Disables formatting and attribute labels. .TP \fB\-\-rights\fR Display effective rights on all attributes of the entry. You also have to specify \fB\-\-all\fR for this to work. User rights are returned as Python dictionary where index is the name of an attribute and value is a unicode string composed (hence the u'xxxx' format) of letters specified below. Note that user rights are primarily used for internal purposes of CLI and WebUI. .ad l r \- read\p s \- search\p w \- write\p o \- obliterate (delete)\p c \- compare\p W \- self\-write\p O \- self\-obliterate .SH "EXAMPLES" .TP \fBipa help commands\fR Display a list of available commands \fBipa help topics\fR Display a high\-level list of help topics \fBipa help user\fR Display documentation and list of commands in the "user" topic. .TP \fBipa env\fR List IPA environmental variables and their values. .TP \fBipa user\-add foo \-\-first foo \-\-last bar\fR Create a new user with username "foo", first name "foo" and last name "bar". .TP \fBipa group\-add bar \-\-desc "this is an example group" Create a new group with name "bar" and description "this is an example group". .TP \fBipa group\-add\-member bar \-\-users=admin,foo\fR Add users "admin" and "foo" to the group "bar". .TP \fBipa user\-show foo \-\-raw\fR Display user "foo" as (s)he is stored on the server. .TP \fBipa group\-show bar \-\-all\fR Display group "bar" and all of its attributes. .TP \fBipa config\-mod \-\-maxusername 20\fR Set maximum user name length to 20 characters. .TP \fBipa user\-find foo\fR Search for all users with "foo" in either uid, first name, last name, full name, etc. A user with uid "foobar" would match the search criteria. .TP \fBipa user\-find foo \-\-first bar\fR Same as the previous example, except this time the users first name has to be exactly "bar". A user with uid "foobar" and first name "bar" would match the search criteria. .TP \fBipa user\-find foo \-\-first bar \-\-last foo\fR A user with uid "foobar", first name "bar" and last name "foo" would match the search criteria. .TP \fBipa user\-find \-\-uuid 936407bd\-da9b\-11de\-9abd\-54520012e7cd\fR Only the user with the specified IPA unique ID would match the search criteria. .TP \fBipa user\-find\fR All users would match the search criteria (as there are none). .SH "SERVERS" The ipa client will determine which server to connect to in this order: .TP 1. The server configured in \fB/etc/ipa/default.conf\fR in the \fIxmlrpc_uri\fR directive. .TP 2. An unordered list of servers from the ldap DNS SRV records. .TP If a kerberos error is raised by any of the requests then it will stop processing and display the error message. .SH "FILES" .TP \fB/etc/ipa/default.conf\fR IPA default configuration file. .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 2 If an entry is not found .SH "SEE ALSO" ipa\-client\-install(1), ipa\-compat\-manage(1), ipactl(1), ipa\-dns\-install(1), ipa\-getcert(1), ipa\-getkeytab(1), ipa\-join(1), ipa\-ldap\-updater(1), ipa\-nis\-manage(1), ipa\-replica\-install(1), ipa\-replica\-manage(1), ipa\-replica\-prepare(1), ipa\-rmkeytab(1), ipa\-server\-certinstall(2), ipa\-server\-install(1), ipa\-upgradeconfig(1), ipa\-host\-net\-manage(1) freeipa-3.3.4/freeipa.spec.in0000664000175000017500000016614312271663206015416 0ustar mkosekmkosek# Define ONLY_CLIENT to only make the ipa-client and ipa-python subpackages %{!?ONLY_CLIENT:%global ONLY_CLIENT 0} %global plugin_dir %{_libdir}/dirsrv/plugins %global POLICYCOREUTILSVER 2.1.12-5 %global gettext_domain ipa %if (0%{?fedora} > 15 || 0%{?rhel} >= 7) %define _hardened_build 1 %endif Name: freeipa Version: __VERSION__ Release: __RELEASE__%{?dist} Summary: The Identity, Policy and Audit system Group: System Environment/Base License: GPLv3+ URL: http://www.freeipa.org/ Source0: freeipa-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) %if ! %{ONLY_CLIENT} BuildRequires: 389-ds-base-devel >= 1.3.1.3 BuildRequires: svrcore-devel BuildRequires: policycoreutils >= %{POLICYCOREUTILSVER} BuildRequires: systemd-units %if 0%{?fedora} >= 18 BuildRequires: samba-devel >= 2:4.0.5-1 BuildRequires: samba-python BuildRequires: libwbclient-devel %else BuildRequires: samba4-devel >= 4.0.0-139 BuildRequires: samba4-python %endif BuildRequires: libtalloc-devel BuildRequires: libtevent-devel %endif # ONLY_CLIENT BuildRequires: nspr-devel BuildRequires: nss-devel BuildRequires: openssl-devel BuildRequires: openldap-devel BuildRequires: krb5-devel >= 1.11 BuildRequires: krb5-workstation BuildRequires: libuuid-devel BuildRequires: libcurl-devel >= 7.21.7-2 BuildRequires: xmlrpc-c-devel >= 1.27.4 BuildRequires: popt-devel BuildRequires: autoconf BuildRequires: automake BuildRequires: m4 BuildRequires: libtool BuildRequires: gettext BuildRequires: python-devel BuildRequires: python-ldap BuildRequires: python-setuptools BuildRequires: python-krbV BuildRequires: python-nss BuildRequires: python-netaddr BuildRequires: python-kerberos BuildRequires: python-rhsm BuildRequires: pyOpenSSL BuildRequires: pylint BuildRequires: python-polib BuildRequires: libipa_hbac-python BuildRequires: python-memcached BuildRequires: sssd >= 1.9.2 BuildRequires: python-lxml BuildRequires: python-pyasn1 >= 0.0.9a BuildRequires: python-dns BuildRequires: m2crypto BuildRequires: check BuildRequires: libsss_idmap-devel BuildRequires: libsss_nss_idmap-devel BuildRequires: java-1.7.0-openjdk BuildRequires: libverto-devel BuildRequires: systemd BuildRequires: libunistring-devel # Find out Kerberos middle version to infer ABI changes in DAL driver # We cannot load DAL driver into KDC with wrong ABI. # This is also needed to support ipa-devel repository where krb5 1.11 is available for F18 %global krb5_dal_version %{expand:%(echo "#include "|cpp -dM|grep KRB5_KDB_DAL_MAJOR_VERSION|cut -d' ' -f3)} %description IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). %if ! %{ONLY_CLIENT} %package server Summary: The IPA authentication server Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: %{name}-client = %{version}-%{release} Requires: %{name}-admintools = %{version}-%{release} Requires: 389-ds-base >= 1.3.1.3 Requires: openldap-clients > 2.4.35-4 %if 0%{?fedora} == 18 Requires: nss >= 3.14.3-2 Requires: nss-tools >= 3.14.3-2 %else Requires: nss >= 3.14.3-12.0 Requires: nss-tools >= 3.14.3-12.0 %endif %if 0%{?krb5_dal_version} >= 4 Requires: krb5-server >= 1.11.2-1 %else %if 0%{krb5_dal_version} == 3 # krb5 1.11 bumped DAL interface major version, a rebuild is needed Requires: krb5-server < 1.11 Requires: krb5-server >= 1.10 %else Requires: krb5-server >= 1.10 %endif %endif Requires: krb5-pkinit-openssl Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: httpd Requires: mod_wsgi %if 0%{?fedora} >= 18 Requires: mod_auth_kerb >= 5.4-16 %else Requires: mod_auth_kerb >= 5.4-8 %endif Requires: mod_nss >= 1.0.8-24 Requires: python-ldap Requires: python-krbV Requires: acl Requires: python-pyasn1 Requires: memcached Requires: python-memcached Requires: systemd-units >= 38 Requires(pre): systemd-units Requires(post): systemd-units Requires: selinux-policy >= 3.12.1-65 Requires(post): selinux-policy-base Requires: slapi-nis >= 0.47.7 Requires: pki-ca >= 10.0.4 Requires: dogtag-pki-server-theme %if 0%{?rhel} Requires: subscription-manager %endif Requires(preun): python systemd-units Requires(postun): python systemd-units Requires: python-dns Requires: zip Requires: policycoreutils >= %{POLICYCOREUTILSVER} Requires: tar Requires(pre): certmonger >= 0.65 Requires(pre): 389-ds-base >= 1.3.1.3 # With FreeIPA 3.3, package freeipa-server-selinux was obsoleted as the # entire SELinux policy is stored in the system policy Obsoletes: freeipa-server-selinux < 3.3.0 # 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 < 3.5 %else Conflicts: bind-dyndb-ldap < 1.1.0-0.12.rc1 %endif Conflicts: bind < 9.8.2-0.4.rc2 # Versions of nss-pam-ldapd < 0.8.4 require a mapping from uniqueMember to # member. Conflicts: nss-pam-ldapd < 0.8.4 Obsoletes: ipa-server >= 1.0 %description server IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If you are installing an IPA server you need to install this package (in other words, most people should NOT install this package). %package server-trust-ad Summary: Virtual package to install packages required for Active Directory trusts Group: System Environment/Base Requires: %{name}-server = %version-%release Requires: m2crypto %if 0%{?fedora} >= 18 Requires: samba-python Requires: samba >= 2:4.0.5-1 Requires: samba-winbind %else Requires: samba4-python Requires: samba4 Requires: samba4-winbind %endif Requires: libsss_idmap %if 0%{?fedora} >= 19 Requires: libsss_nss_idmap-python %endif # We use alternatives to divert winbind_krb5_locator.so plugin to libkrb5 # on the installes where server-trust-ad subpackage is installed because # IPA AD trusts cannot be used at the same time with the locator plugin # since Winbindd will be configured in a different mode Requires(post): %{_sbindir}/update-alternatives Requires(post): python Requires(postun): %{_sbindir}/update-alternatives Requires(preun): %{_sbindir}/update-alternatives %description server-trust-ad Cross-realm trusts with Active Directory in IPA require working Samba 4 installation. This package is provided for convenience to install all required dependencies at once. %endif # ONLY_CLIENT %package client Summary: IPA authentication for use on clients Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: python-ldap Requires: cyrus-sasl-gssapi%{?_isa} Requires: ntp Requires: krb5-workstation Requires: authconfig Requires: pam_krb5 Requires: wget Requires: libcurl >= 7.21.7-2 Requires: xmlrpc-c >= 1.27.4 Requires: sssd >= 1.11.1 Requires: certmonger >= 0.65 Requires: nss-tools Requires: bind-utils Requires: oddjob-mkhomedir Requires: python-krbV Requires: python-dns Requires: libsss_autofs Requires: autofs Requires: libnfsidmap Requires: nfs-utils Requires(post): policycoreutils Obsoletes: ipa-client >= 1.0 %description client IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If your network uses IPA for authentication, this package should be installed on every client machine. %if ! %{ONLY_CLIENT} %package admintools Summary: IPA administrative tools Group: System Environment/Base Requires: %{name}-python = %{version}-%{release} Requires: %{name}-client = %{version}-%{release} Requires: python-krbV Requires: python-ldap Obsoletes: ipa-admintools >= 1.0 %description admintools IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). This package provides command-line tools for IPA administrators. %endif # ONLY_CLIENT %package python Summary: Python libraries used by IPA Group: System Environment/Libraries Requires: python-kerberos Requires: gnupg Requires: iproute Requires: keyutils Requires: pyOpenSSL Requires: python-nss Requires: python-lxml Requires: python-netaddr Requires: libipa_hbac-python Obsoletes: ipa-python >= 1.0 %description python IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). If you are using IPA you need to install this package. %if ! %{ONLY_CLIENT} %package tests Summary: IPA tests and test tools Requires: %{name}-client = %{version}-%{release} Requires: %{name}-python = %{version}-%{release} Requires: tar Requires: xz Requires: python-nose Requires: python-paste Requires: python-coverage Requires: python-polib Requires: python-paramiko >= 1.7.7 %description tests IPA is an integrated solution to provide centrally managed Identity (machine, user, virtual machines, groups, authentication credentials), Policy (configuration settings, access control information) and Audit (events, logs, analysis thereof). This package contains tests that verify IPA functionality. %endif # ONLY_CLIENT %prep %setup -n freeipa-%{version} -q %build %ifarch ppc %{power64} s390 s390x # UI compilation segfaulted on some arches when the stack was lower (#1040576) export JAVA_STACK_SIZE="8m" %endif export CFLAGS="$CFLAGS %{optflags}" export CPPFLAGS="$CPPFLAGS %{optflags}" %if 0%{?fedora} >= 18 # use fedora18 platform which is based on fedora16 platform with systemd # support + fedora18 changes export SUPPORTED_PLATFORM=fedora18 %else export SUPPORTED_PLATFORM=fedora16 %endif # Force re-generate of platform support rm -f ipapython/services.py make version-update cd ipa-client; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd .. %if ! %{ONLY_CLIENT} cd daemons; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir} --with-openldap; cd .. cd install; ../autogen.sh --prefix=%{_usr} --sysconfdir=%{_sysconfdir} --localstatedir=%{_localstatedir} --libdir=%{_libdir} --mandir=%{_mandir}; cd .. %endif # ONLY_CLIENT %if ! %{ONLY_CLIENT} make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} all %else make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} client %endif # ONLY_CLIENT %install rm -rf %{buildroot} %if 0%{?fedora} >= 18 # use fedora18 platform which is based on fedora16 platform with systemd # support + fedora18 changes export SUPPORTED_PLATFORM=fedora18 %else export SUPPORTED_PLATFORM=fedora16 %endif # Force re-generate of platform support rm -f ipapython/services.py %if ! %{ONLY_CLIENT} make install DESTDIR=%{buildroot} %else make client-install DESTDIR=%{buildroot} %endif # ONLY_CLIENT %find_lang %{gettext_domain} %if ! %{ONLY_CLIENT} # Remove .la files from libtool - we don't want to package # these files rm %{buildroot}/%{plugin_dir}/libipa_pwd_extop.la rm %{buildroot}/%{plugin_dir}/libipa_enrollment_extop.la rm %{buildroot}/%{plugin_dir}/libipa_winsync.la rm %{buildroot}/%{plugin_dir}/libipa_repl_version.la rm %{buildroot}/%{plugin_dir}/libipa_uuid.la rm %{buildroot}/%{plugin_dir}/libipa_modrdn.la rm %{buildroot}/%{plugin_dir}/libipa_lockout.la rm %{buildroot}/%{plugin_dir}/libipa_cldap.la rm %{buildroot}/%{plugin_dir}/libipa_dns.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen.la rm %{buildroot}/%{plugin_dir}/libipa_sidgen_task.la rm %{buildroot}/%{plugin_dir}/libipa_extdom_extop.la rm %{buildroot}/%{plugin_dir}/libipa_range_check.la rm %{buildroot}/%{_libdir}/krb5/plugins/kdb/ipadb.la rm %{buildroot}/%{_libdir}/samba/pdb/ipasam.la # Some user-modifiable HTML files are provided. Move these to /etc # and link back. mkdir -p %{buildroot}/%{_sysconfdir}/ipa/html mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysrestore mkdir -p %{buildroot}/%{_localstatedir}/cache/ipa/sysupgrade mkdir %{buildroot}%{_usr}/share/ipa/html/ ln -s ../../../..%{_sysconfdir}/ipa/html/ffconfig.js \ %{buildroot}%{_usr}/share/ipa/html/ffconfig.js ln -s ../../../..%{_sysconfdir}/ipa/html/ffconfig_page.js \ %{buildroot}%{_usr}/share/ipa/html/ffconfig_page.js ln -s ../../../..%{_sysconfdir}/ipa/html/ssbrowser.html \ %{buildroot}%{_usr}/share/ipa/html/ssbrowser.html ln -s ../../../..%{_sysconfdir}/ipa/html/unauthorized.html \ %{buildroot}%{_usr}/share/ipa/html/unauthorized.html ln -s ../../../..%{_sysconfdir}/ipa/html/browserconfig.html \ %{buildroot}%{_usr}/share/ipa/html/browserconfig.html ln -s ../../../..%{_sysconfdir}/ipa/html/ipa_error.css \ %{buildroot}%{_usr}/share/ipa/html/ipa_error.css # So we can own our Apache configuration mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d/ /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa.conf /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf /bin/touch %{buildroot}%{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf mkdir -p %{buildroot}%{_usr}/share/ipa/html/ /bin/touch %{buildroot}%{_usr}/share/ipa/html/ca.crt /bin/touch %{buildroot}%{_usr}/share/ipa/html/configure.jar /bin/touch %{buildroot}%{_usr}/share/ipa/html/kerberosauth.xpi /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.con /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb.js /bin/touch %{buildroot}%{_usr}/share/ipa/html/krb5.ini /bin/touch %{buildroot}%{_usr}/share/ipa/html/krbrealm.con /bin/touch %{buildroot}%{_usr}/share/ipa/html/preferences.html mkdir -p %{buildroot}%{_initrddir} mkdir %{buildroot}%{_sysconfdir}/sysconfig/ install -m 644 init/ipa_memcached.conf %{buildroot}%{_sysconfdir}/sysconfig/ipa_memcached # Web UI plugin dir mkdir -p %{buildroot}%{_usr}/share/ipa/ui/js/plugins # NOTE: systemd specific section mkdir -p %{buildroot}%{_prefix}/lib/tmpfiles.d install -m 0644 init/systemd/ipa.conf.tmpfiles %{buildroot}%{_prefix}/lib/tmpfiles.d/%{name}.conf # END mkdir -p %{buildroot}%{_localstatedir}/run/ install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa_memcached/ install -d -m 0700 %{buildroot}%{_localstatedir}/run/ipa/ mkdir -p %{buildroot}%{_libdir}/krb5/plugins/libkrb5 touch %{buildroot}%{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so # NOTE: systemd specific section mkdir -p %{buildroot}%{_unitdir} install -m 644 init/systemd/ipa.service %{buildroot}%{_unitdir}/ipa.service install -m 644 init/systemd/ipa_memcached.service %{buildroot}%{_unitdir}/ipa_memcached.service # END mkdir -p %{buildroot}/%{_localstatedir}/lib/ipa/backup %endif # ONLY_CLIENT mkdir -p %{buildroot}%{_sysconfdir}/ipa/ /bin/touch %{buildroot}%{_sysconfdir}/ipa/default.conf /bin/touch %{buildroot}%{_sysconfdir}/ipa/ca.crt mkdir -p %{buildroot}/%{_localstatedir}/lib/ipa-client/sysrestore %if ! %{ONLY_CLIENT} mkdir -p %{buildroot}%{_sysconfdir}/bash_completion.d install -pm 644 contrib/completion/ipa.bash_completion %{buildroot}%{_sysconfdir}/bash_completion.d/ipa mkdir -p %{buildroot}%{_sysconfdir}/cron.d (cd %{buildroot}/%{python_sitelib}/ipaserver && find . -type f | \ grep -v dcerpc | grep -v adtrustinstance | \ sed -e 's,\.py.*$,.*,g' | sort -u | \ sed -e 's,\./,%%{python_sitelib}/ipaserver/,g' ) >server-python.list (cd %{buildroot}/%{python_sitelib}/ipatests && find . -type f | \ sed -e 's,\.py.*$,.*,g' | sort -u | \ sed -e 's,\./,%%{python_sitelib}/ipatests/,g' ) >tests-python.list %endif # ONLY_CLIENT %clean rm -rf %{buildroot} %if ! %{ONLY_CLIENT} %post server # NOTE: systemd specific section /bin/systemctl --system daemon-reload 2>&1 || : # END if [ $1 -gt 1 ] ; then /bin/systemctl condrestart certmonger.service 2>&1 || : 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 --quiet >/dev/null || : /usr/sbin/ipa-upgradeconfig --quiet >/dev/null || : # Restart IPA processes. This must be also run in postrans so that plugins # and software is in consistent state python -c "import sys; from ipaserver.install import installutils; sys.exit(0 if installutils.is_ipa_configured() else 1);" > /dev/null 2>&1 # NOTE: systemd specific section if [ $? -eq 0 ]; then /bin/systemctl try-restart ipa.service >/dev/null 2>&1 || : fi # END %preun server if [ $1 = 0 ]; then # NOTE: systemd specific section /bin/systemctl --quiet stop ipa.service || : /bin/systemctl --quiet disable ipa.service || : # END fi %pre server # Stop ipa_kpasswd if it exists before upgrading so we don't have a # zombie process when we're done. if [ -e /usr/sbin/ipa_kpasswd ]; then # NOTE: systemd specific section /bin/systemctl stop ipa_kpasswd.service >/dev/null 2>&1 || : # END fi %postun server-trust-ad if [ "$1" -ge "1" ]; then if [ "`readlink %{_sysconfdir}/alternatives/winbind_krb5_locator.so`" == "/dev/null" ]; then %{_sbindir}/alternatives --set winbind_krb5_locator.so /dev/null fi fi %post server-trust-ad %{_sbindir}/update-alternatives --install %{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so \ winbind_krb5_locator.so /dev/null 90 %posttrans server-trust-ad python -c "import sys; from ipaserver.install import installutils; sys.exit(0 if installutils.is_ipa_configured() else 1);" > /dev/null 2>&1 if [ $? -eq 0 ]; then # NOTE: systemd specific section /bin/systemctl try-restart httpd.service >/dev/null 2>&1 || : # END fi %preun server-trust-ad if [ $1 -eq 0 ]; then %{_sbindir}/update-alternatives --remove winbind_krb5_locator.so /dev/null fi %endif # ONLY_CLIENT %post client if [ $1 -gt 1 ] ; then # Has the client been configured? restore=0 test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}') if [ -f '/etc/sssd/sssd.conf' -a $restore -ge 2 ]; then if ! grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then echo "includedir /var/lib/sss/pubconf/krb5.include.d/" > /etc/krb5.conf.ipanew cat /etc/krb5.conf >> /etc/krb5.conf.ipanew mv /etc/krb5.conf.ipanew /etc/krb5.conf /sbin/restorecon /etc/krb5.conf fi fi if [ -f '/etc/sysconfig/ntpd' -a $restore -ge 2 ]; then if grep -E -q 'OPTIONS=.*-u ntp:ntp' /etc/sysconfig/ntpd 2>/dev/null; then sed -r '/OPTIONS=/ { s/\s+-u ntp:ntp\s+/ /; s/\s*-u ntp:ntp\s*// }' /etc/sysconfig/ntpd >/etc/sysconfig/ntpd.ipanew mv /etc/sysconfig/ntpd.ipanew /etc/sysconfig/ntpd /sbin/restorecon /etc/sysconfig/ntpd /bin/systemctl condrestart ntpd.service 2>&1 || : fi fi fi %triggerin -n freeipa-client -- openssh-server # Has the client been configured? restore=0 test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}') if [ -f '/etc/ssh/sshd_config' -a $restore -ge 2 ]; then if grep -E -q '^(AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys|PubKeyAgent /usr/bin/sss_ssh_authorizedkeys %u)$' /etc/ssh/sshd_config 2>/dev/null; then sed -r ' /^(AuthorizedKeysCommand(User|RunAs)|PubKeyAgentRunAs)[ \t]/ d ' /etc/ssh/sshd_config >/etc/ssh/sshd_config.ipanew if /usr/sbin/sshd -t -f /dev/null -o 'AuthorizedKeysCommand=/usr/bin/sss_ssh_authorizedkeys' -o 'AuthorizedKeysCommandUser=nobody'; then sed -ri ' s/^PubKeyAgent (.+) %u$/AuthorizedKeysCommand \1/ s/^AuthorizedKeysCommand .*$/\0\nAuthorizedKeysCommandUser nobody/ ' /etc/ssh/sshd_config.ipanew elif /usr/sbin/sshd -t -f /dev/null -o 'AuthorizedKeysCommand=/usr/bin/sss_ssh_authorizedkeys' -o 'AuthorizedKeysCommandRunAs=nobody'; then sed -ri ' s/^PubKeyAgent (.+) %u$/AuthorizedKeysCommand \1/ s/^AuthorizedKeysCommand .*$/\0\nAuthorizedKeysCommandRunAs nobody/ ' /etc/ssh/sshd_config.ipanew elif /usr/sbin/sshd -t -f /dev/null -o 'PubKeyAgent=/usr/bin/sss_ssh_authorizedkeys %u' -o 'PubKeyAgentRunAs=nobody'; then sed -ri ' s/^AuthorizedKeysCommand (.+)$/PubKeyAgent \1 %u/ s/^PubKeyAgent .*$/\0\nPubKeyAgentRunAs nobody/ ' /etc/ssh/sshd_config.ipanew fi mv /etc/ssh/sshd_config.ipanew /etc/ssh/sshd_config /sbin/restorecon /etc/ssh/sshd_config chmod 600 /etc/ssh/sshd_config /bin/systemctl condrestart sshd.service 2>&1 || : fi fi %if ! %{ONLY_CLIENT} %files server -f server-python.list %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_sbindir}/ipa-backup %{_sbindir}/ipa-restore %{_sbindir}/ipa-ca-install %{_sbindir}/ipa-dns-install %{_sbindir}/ipa-server-install %{_sbindir}/ipa-replica-conncheck %{_sbindir}/ipa-replica-install %{_sbindir}/ipa-replica-prepare %{_sbindir}/ipa-replica-manage %{_sbindir}/ipa-csreplica-manage %{_sbindir}/ipa-server-certinstall %{_sbindir}/ipa-ldap-updater %{_sbindir}/ipa-compat-manage %{_sbindir}/ipa-nis-manage %{_sbindir}/ipa-managed-entries %{_sbindir}/ipactl %{_sbindir}/ipa-upgradeconfig %{_sbindir}/ipa-advise %{_libexecdir}/certmonger/dogtag-ipa-retrieve-agent-submit %{_libexecdir}/ipa-otpd %config(noreplace) %{_sysconfdir}/sysconfig/ipa_memcached %dir %attr(0700,apache,apache) %{_localstatedir}/run/ipa_memcached/ %dir %attr(0700,root,root) %{_localstatedir}/run/ipa/ # NOTE: systemd specific section %{_prefix}/lib/tmpfiles.d/%{name}.conf %attr(644,root,root) %{_unitdir}/ipa.service %attr(644,root,root) %{_unitdir}/ipa_memcached.service %attr(644,root,root) %{_unitdir}/ipa-otpd.socket %attr(644,root,root) %{_unitdir}/ipa-otpd@.service # END %dir %{python_sitelib}/ipaserver %dir %{python_sitelib}/ipaserver/install %dir %{python_sitelib}/ipaserver/install/plugins %dir %{python_sitelib}/ipaserver/advise %dir %{python_sitelib}/ipaserver/advise/plugins %dir %{python_sitelib}/ipaserver/plugins %dir %{_libdir}/ipa/certmonger %attr(755,root,root) %{_libdir}/ipa/certmonger/* %dir %{_usr}/share/ipa %{_usr}/share/ipa/wsgi.py* %{_usr}/share/ipa/copy-schema-to-ca.py* %{_usr}/share/ipa/*.ldif %{_usr}/share/ipa/*.uldif %{_usr}/share/ipa/*.template %dir %{_usr}/share/ipa/advise %dir %{_usr}/share/ipa/advise/legacy %{_usr}/share/ipa/advise/legacy/*.template %dir %{_usr}/share/ipa/ffextension %{_usr}/share/ipa/ffextension/bootstrap.js %{_usr}/share/ipa/ffextension/install.rdf %{_usr}/share/ipa/ffextension/chrome.manifest %dir %{_usr}/share/ipa/ffextension/chrome %dir %{_usr}/share/ipa/ffextension/chrome/content %{_usr}/share/ipa/ffextension/chrome/content/kerberosauth.js %{_usr}/share/ipa/ffextension/chrome/content/kerberosauth_overlay.xul %dir %{_usr}/share/ipa/ffextension/locale %dir %{_usr}/share/ipa/ffextension/locale/en-US %{_usr}/share/ipa/ffextension/locale/en-US/kerberosauth.properties %dir %{_usr}/share/ipa/html %{_usr}/share/ipa/html/ffconfig.js %{_usr}/share/ipa/html/ffconfig_page.js %{_usr}/share/ipa/html/ssbrowser.html %{_usr}/share/ipa/html/browserconfig.html %{_usr}/share/ipa/html/unauthorized.html %{_usr}/share/ipa/html/ipa_error.css %dir %{_usr}/share/ipa/migration %{_usr}/share/ipa/migration/error.html %{_usr}/share/ipa/migration/index.html %{_usr}/share/ipa/migration/invalid.html %{_usr}/share/ipa/migration/migration.py* %dir %{_usr}/share/ipa/ui %{_usr}/share/ipa/ui/index.html %{_usr}/share/ipa/ui/login.html %{_usr}/share/ipa/ui/logout.html %{_usr}/share/ipa/ui/reset_password.html %{_usr}/share/ipa/ui/*.ico %{_usr}/share/ipa/ui/*.css %{_usr}/share/ipa/ui/*.js %{_usr}/share/ipa/ui/*.eot %{_usr}/share/ipa/ui/*.svg %{_usr}/share/ipa/ui/*.ttf %{_usr}/share/ipa/ui/*.woff %dir %{_usr}/share/ipa/ui/js %dir %{_usr}/share/ipa/ui/js/dojo %{_usr}/share/ipa/ui/js/dojo/dojo.js %dir %{_usr}/share/ipa/ui/js/libs %{_usr}/share/ipa/ui/js/libs/*.js %dir %{_usr}/share/ipa/ui/js/freeipa %{_usr}/share/ipa/ui/js/freeipa/app.js %dir %{_usr}/share/ipa/ui/js/plugins %dir %{_usr}/share/ipa/ui/images %{_usr}/share/ipa/ui/images/*.png %{_usr}/share/ipa/ui/images/*.gif %dir %{_usr}/share/ipa/wsgi %{_usr}/share/ipa/wsgi/plugins.py* %dir %{_sysconfdir}/ipa %dir %{_sysconfdir}/ipa/html %config(noreplace) %{_sysconfdir}/ipa/html/ffconfig.js %config(noreplace) %{_sysconfdir}/ipa/html/ffconfig_page.js %config(noreplace) %{_sysconfdir}/ipa/html/ssbrowser.html %config(noreplace) %{_sysconfdir}/ipa/html/ipa_error.css %config(noreplace) %{_sysconfdir}/ipa/html/unauthorized.html %config(noreplace) %{_sysconfdir}/ipa/html/browserconfig.html %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-rewrite.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/httpd/conf.d/ipa-pki-proxy.conf %{_usr}/share/ipa/ca_renewal %{_usr}/share/ipa/ipa.conf %{_usr}/share/ipa/ipa-rewrite.conf %{_usr}/share/ipa/ipa-pki-proxy.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_usr}/share/ipa/html/ca.crt %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/configure.jar %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/kerberosauth.xpi %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.con %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb.js %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krb5.ini %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/krbrealm.con %ghost %attr(0644,root,apache) %{_usr}/share/ipa/html/preferences.html %dir %{_usr}/share/ipa/updates/ %{_usr}/share/ipa/updates/* %attr(755,root,root) %{plugin_dir}/libipa_pwd_extop.so %attr(755,root,root) %{plugin_dir}/libipa_enrollment_extop.so %attr(755,root,root) %{plugin_dir}/libipa_winsync.so %attr(755,root,root) %{plugin_dir}/libipa_repl_version.so %attr(755,root,root) %{plugin_dir}/libipa_uuid.so %attr(755,root,root) %{plugin_dir}/libipa_modrdn.so %attr(755,root,root) %{plugin_dir}/libipa_lockout.so %attr(755,root,root) %{plugin_dir}/libipa_cldap.so %attr(755,root,root) %{plugin_dir}/libipa_dns.so %attr(755,root,root) %{plugin_dir}/libipa_range_check.so %dir %{_localstatedir}/lib/ipa %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/backup %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore %attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysupgrade %attr(755,root,root) %dir %{_localstatedir}/lib/ipa/pki-ca %ghost %{_localstatedir}/lib/ipa/pki-ca/publish %attr(755,root,root) %{_libdir}/krb5/plugins/kdb/ipadb.so %{_mandir}/man1/ipa-replica-conncheck.1.gz %{_mandir}/man1/ipa-replica-install.1.gz %{_mandir}/man1/ipa-replica-manage.1.gz %{_mandir}/man1/ipa-csreplica-manage.1.gz %{_mandir}/man1/ipa-replica-prepare.1.gz %{_mandir}/man1/ipa-server-certinstall.1.gz %{_mandir}/man1/ipa-server-install.1.gz %{_mandir}/man1/ipa-dns-install.1.gz %{_mandir}/man1/ipa-ca-install.1.gz %{_mandir}/man1/ipa-compat-manage.1.gz %{_mandir}/man1/ipa-nis-manage.1.gz %{_mandir}/man1/ipa-managed-entries.1.gz %{_mandir}/man1/ipa-ldap-updater.1.gz %{_mandir}/man8/ipactl.8.gz %{_mandir}/man8/ipa-upgradeconfig.8.gz %{_mandir}/man1/ipa-backup.1.gz %{_mandir}/man1/ipa-restore.1.gz %{_mandir}/man1/ipa-advise.1.gz %files server-trust-ad %{_sbindir}/ipa-adtrust-install %attr(755,root,root) %{plugin_dir}/libipa_extdom_extop.so %{_usr}/share/ipa/smb.conf.empty %attr(755,root,root) %{_libdir}/samba/pdb/ipasam.so %attr(755,root,root) %{plugin_dir}/libipa_sidgen.so %attr(755,root,root) %{plugin_dir}/libipa_sidgen_task.so %{_mandir}/man1/ipa-adtrust-install.1.gz %{python_sitelib}/ipaserver/dcerpc* %{python_sitelib}/ipaserver/install/adtrustinstance* %ghost %{_libdir}/krb5/plugins/libkrb5/winbind_krb5_locator.so %endif # ONLY_CLIENT %files client %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_sbindir}/ipa-client-install %{_sbindir}/ipa-client-automount %{_sbindir}/ipa-getkeytab %{_sbindir}/ipa-rmkeytab %{_sbindir}/ipa-join %dir %{_usr}/share/ipa %dir %{_usr}/share/ipa/ipaclient %dir %{_localstatedir}/lib/ipa-client %dir %{_localstatedir}/lib/ipa-client/sysrestore %{_usr}/share/ipa/ipaclient/ipa.cfg %{_usr}/share/ipa/ipaclient/ipa.js %dir %{python_sitelib}/ipaclient %{python_sitelib}/ipaclient/*.py* %{_mandir}/man1/ipa-getkeytab.1.gz %{_mandir}/man1/ipa-rmkeytab.1.gz %{_mandir}/man1/ipa-client-install.1.gz %{_mandir}/man1/ipa-client-automount.1.gz %{_mandir}/man1/ipa-join.1.gz %{_mandir}/man5/default.conf.5.gz %if ! %{ONLY_CLIENT} %files admintools %defattr(-,root,root,-) %doc COPYING README Contributors.txt %{_bindir}/ipa %config %{_sysconfdir}/bash_completion.d %{_mandir}/man1/ipa.1.gz %endif # ONLY_CLIENT %files python -f %{gettext_domain}.lang %defattr(-,root,root,-) %doc COPYING README Contributors.txt %dir %{python_sitelib}/ipapython %dir %{python_sitelib}/ipapython/platform %dir %{python_sitelib}/ipapython/platform/base %dir %{python_sitelib}/ipapython/platform/fedora16 %dir %{python_sitelib}/ipapython/platform/fedora18 %dir %{python_sitelib}/ipapython/platform/redhat %{python_sitelib}/ipapython/*.py* %{python_sitelib}/ipapython/platform/*.py* %{python_sitelib}/ipapython/platform/base/*.py* %{python_sitelib}/ipapython/platform/fedora16/*.py* %{python_sitelib}/ipapython/platform/fedora18/*.py* %{python_sitelib}/ipapython/platform/redhat/*.py* %dir %{python_sitelib}/ipalib %{python_sitelib}/ipalib/* %attr(0644,root,root) %{python_sitearch}/default_encoding_utf8.so %{python_sitelib}/ipapython-*.egg-info %{python_sitelib}/freeipa-*.egg-info %{python_sitearch}/python_default_encoding-*.egg-info %dir %attr(0755,root,root) %{_sysconfdir}/ipa/ %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/ca.crt %if ! %{ONLY_CLIENT} %files tests -f tests-python.list %defattr(-,root,root,-) %doc COPYING README Contributors.txt %dir %{python_sitelib}/ipatests %dir %{python_sitelib}/ipatests/test_cmdline %dir %{python_sitelib}/ipatests/test_install %dir %{python_sitelib}/ipatests/test_ipalib %dir %{python_sitelib}/ipatests/test_ipapython %dir %{python_sitelib}/ipatests/test_ipaserver %dir %{python_sitelib}/ipatests/test_ipaserver/install %dir %{python_sitelib}/ipatests/test_pkcs10 %dir %{python_sitelib}/ipatests/test_webui %dir %{python_sitelib}/ipatests/test_xmlrpc %{_bindir}/ipa-run-tests %{_bindir}/ipa-test-config %{_bindir}/ipa-test-task %{python_sitelib}/ipatests-*.egg-info %{_mandir}/man1/ipa-run-tests.1.gz %{_mandir}/man1/ipa-test-config.1.gz %{_mandir}/man1/ipa-test-task.1.gz %endif # ONLY_CLIENT %changelog * Fri Oct 25 2013 Martin Kosek - 3.3.2-1 - Remove mod_ssl conflict, it can now live with mod_nss installed * Wed Sep 4 2013 Ana Krivokapic - 3.3.0-3 - Conform to tmpfiles.d packaging guidelines * Wed Aug 28 2013 Petr Viktorin - 3.3.0-2 - Add man pages to the tests subpackage * Mon Aug 12 2013 Petr Viktorin - 3.3.0-1 - Downgrade required version of python-paramiko for the tests subpackage * Thu Aug 8 2013 Martin Kosek - 3.2.99-13 - Require slapi-nis 0.47.7 and sssd 1.11.0-0.1.beta2 required for core features of 3.3.0 release * Fri Jul 26 2013 Martin Kosek - 3.2.99-12 - Require pki-ca 10.0.4 which fixes external CA installation (#986901) * Wed Jul 24 2013 Petr Viktorin - 3.2.99-11 - Add tar and xz dependencies to freeipa-tests * Wed Jul 24 2013 Tomas Babej - 3.2.99-10 - Move requirement for keyutils from freeipa-server to freeipa-python * Wed Jul 24 2013 Martin Kosek - 3.2.99-9 - Bump minimum version of sssd to 1.10.92 to pick up latest SSSD 1.11 Beta development * Thu Jul 18 2013 Ana Krivokapic - 3.2.99-8 - Bump minimum version of sssd to 1.10.90 for the 'ipa_server_mode' option. * Wed Jul 17 2013 Martin Kosek - 3.2.99-7 - Require selinux-policy 3.12.1-65 containing missing policy after removal of freeipa-server-selinux subpackage * Tue Jul 16 2013 Tomas Babej - 3.2.99-6 - Do not create /var/lib/ipa/pki-ca/publish, retain reference as ghost * Thu Jul 11 2013 Martin Kosek - 3.2.99-5 - Run ipa-upgradeconfig and server restart in posttrans to avoid inconsistency issues when there are still old parts of software (like entitlements plugin) * Wed Jul 10 2013 Ana Krivokapic - 3.2.99-4 - Bump minimum version of 389-ds-base to 1.3.1.3 for user password change fix. * Wed Jun 26 2013 Jan Cholasta - 3.2.99-3 - Bump minimum version of 389-ds-base to 1.3.1.1 for SASL mapping priority support. * Mon Jun 17 2013 Petr Viktorin - 3.2.99-2 - Add the freeipa-tests subpackage * Thu Jun 13 2013 Martin Kosek - 3.2.99-1 - Drop freeipa-server-selinux subpackage - Drop redundant directory /var/cache/ipa/sessions * Fri May 10 2013 Martin Kosek - 3.1.99-13 - Add requires for openldap-2.4.35-4 to pickup fixed SASL_NOCANON behavior for socket based connections (#960222) * Tue May 7 2013 Petr Viktorin - 3.1.99-12 - Require libsss_nss_idmap-python in Fedora 19+ * Mon May 6 2013 Petr Vobornik - 3.1.99-11 - Web UI plugins * Fri May 3 2013 Rob Crittenden - 3.1.99-10 - Require pki-ca 10.0.2 for 501 response code on find for d9 -> d10 upgrades * Tue Apr 30 2013 Rob Crittenden - 3.1.99-9 - Add Conflicts on nss-pam-ldapd < 0.8.4. The mapping from uniqueMember to member is now done automatically and having it in the config file raises an error. * Tue Apr 30 2013 Jan Cholasta - 3.1.99-8 - Add triggerin scriptlet to update sshd_config on openssh-server update * Thu Apr 25 2013 Rob Crittenden - 3.1.99-7 - Update nss and nss-tools dependency to fix certutil problem (#872761) * Mon Apr 15 2013 Martin Kosek - 3.1.99-6 - Require samba 4.0.5, includes new passdb API - Require krb5 1.11.2-1, fixes missing PAC issue - Change permissions on backup dir to 700 * Fri Apr 5 2013 Rob Crittenden - 3.1.99-5 - Add backup and restore - Own /var/lib/ipa/backup * Thu Apr 4 2013 Alexander Bokovoy - 3.1.99-4 - Make sure build against Krb5 1.11 in Fedora 18 environment creates proper dependencies * Tue Apr 2 2013 Martin Kosek - 3.1.99-3 - Require 389-base-base >= 1.3.0.5 to pull the following fixes: - upgrade deadlock caused by DNA plugin reconfiguration - CVE-2013-1897: unintended information exposure when nsslapd-allow-anonymous-access is set to rootdse * Wed Mar 27 2013 Martin Kosek - 3.1.99-2 - Remove conflict with krb5-server > 1.11 as ipa-kdb is compatible - ipa-ldap-updater show produce errors only - update policycoreutils version to 2.1.12-5 to match Requires in Fedora - require at least systemd 38 which provides the journal (we no longer need to require syslog.target) * Thu Mar 21 2013 Martin Kosek - 3.1.99-1 - Require selinux-policy 3.11.1-86 to fix Fedora 17 to 18 upgrade issue * Tue Jan 29 2013 Petr Viktorin - 3.0.99-14 - Use ipa-ldap-updater --quiet instead of redirecting to /dev/null * Tue Jan 29 2013 Rob Crittenden - 3.0.99-13 - Set certmonger minimum version to 0.65 for NSS locking during renewal - Set selinux-policy to 3.11.1-73 so certmonger can run in post scriptlet * Thu Jan 24 2013 Rob Crittenden - 3.0.99-12 - Add certmonger condrestart to server post scriptlet - Make certmonger a (pre) Requires on the server subpackage * Tue Jan 22 2013 Petr Vobornik - 3.0.99-11 - dependency fix - Add BuildRequires: java-1.7.0-openjdk. - Removed BuildRequires: rhino * Fri Jan 18 2013 Petr Vobornik - 3.0.99-10 - Add Web UI layer JS files in ui/js/{dojo,freeipa,libs} directories - Add BuildRequires: rhino * Fri Dec 7 2012 Endi S. Dewata - 3.0.99-9 - Bump minimum version of pki-ca to 10.0.0-0.54.b3 * Fri Dec 7 2012 Martin Kosek - 3.0.99-8 - Bump minimum version of 389-ds-base to 1.3.0 to get transaction support * Thu Dec 6 2012 Rob Crittenden - 3.0.99-7 - Set min for selinux-policy to 3.11.1-60 to fix errors including sssd domain mapping in krb5.conf (#873429) * Wed Nov 21 2012 Alexander Bokovoy - 3.0.99-6 - Replace python-crypto by m2crypto dependency * Fri Nov 16 2012 Rob Crittenden - 3.0.99-5 - Bump minimum version of slapi-nis to 0.44 * Wed Nov 14 2012 Martin Kosek - 3.0.99-4 - Remove compatibility definitions for unsupported Fedora versions (Fedora 16 and lower) - Do not require specific package version when the package was available in Fedora 17 - Remove old SysV initscript compatibility code - we run on systemd now - Add Requires for the new Dogtag 10 and dogtag-pki-server-theme - Remove Requires on tomcat6 for Fedora 18 and later, Dogtag 10 pulls tomcat7 itself - Add Requires for tar (used by ipa-replica-prepare) * Fri Nov 09 2012 Martin Kosek - 3.0.99-3 - Set min for bind-dyndb-ldap to 2.3-2 to pick up disabling global forwarder per-zone * Fri Oct 26 2012 Sumit Bose - 3.0.99-2 - Restart httpd in post install of server-trust-ad * Wed Oct 24 2012 Martin Kosek - 3.0.99-1 - Add strict Requires for 389-ds-base and policycoreutils to avoid user removing them during package lifetime * Wed Oct 17 2012 Martin Kosek - 2.99.0-51 - Print ipa-upgradeconfig errors during RPM update * Wed Oct 10 2012 Alexander Bokovoy - 2.99.0-50 - Make sure server-trust-ad subpackage alternates winbind_krb5_locator.so plugin to /dev/null since they cannot be used when trusts are configured * Wed Oct 10 2012 Petr Viktorin - 2.99.0-49 - Add zip dependency, needed for creating unsigned Firefox extensions * Mon Oct 8 2012 Martin Kosek - 2.99.0-48 - Add directory /var/lib/ipa/pki-ca/publish for CRL published by pki-ca * Mon Oct 1 2012 Martin Kosek - 2.99.0-47 - Require samba packages instead of samba4 packages obsoleted in Fedora 18 and later - Add libwbclient-devel BuildRequires to pick up libwbclient.h on Fedora 18 and later * Tue Sep 18 2012 Petr Viktorin - 2.99.0-46 - Set certmonger minimum version to 0.60 for Dogtag 10 support. * Mon Sep 17 2012 Rob Crittenden - 2.99.0-45 - Set min for 389-ds-base to 1.2.11.14-1 on F17+ to pull in updated RUV code and nsslapd-readonly schema. * Fri Sep 14 2012 Sumit Bose - 2.99.0-44 - Updated samba4-devel dependency due to API change * Mon Aug 20 2012 Rob Crittenden - 2.99.0-43 - Set min for 389-ds-base to 1.2.11.9-1 on F17+ to pull in warning about low nsslapd-cachememsize. * Mon Aug 20 2012 Tomas Babej - 2.99.0-42 - Add samba4-winbind to build dependencies for AD server-side code * Fri Aug 17 2012 Martin Kosek - 2.99.0-41 - Set min for bind-dyndb-ldap to 1.1.0-0.16.rc1 to pick up complete zone transfer support * Thu Aug 2 2012 Martin Kosek - 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 - 2.99.0-39 - Set minimum certmonger to 0.58 for dogtag cert renewal * Wed Jul 18 2012 Alexander Bokovoy - 2.99.0-38 - Require samba4-devel >= 4.0.0-128 due to passdb API change in beta4 * Fri Jun 29 2012 Rob Crittenden - 2.99.0-37 - Add Requires on openssl - Set minimum tomcat6 to 6.0.35-4 in F-18 - Set minimum mod_auth_kerb to 5.4-16 in F-18 * Thu Jun 21 2012 Sumit Bose - 2.99.0-36 - Add extdom extop plugin * Thu Jun 21 2012 Rob Crittenden - 2.99.0-35 - Add client requires on libsss-autofs, autofs, libnfsidmap and nfs-utils for configuring automount and NFS. * Thu Jun 21 2012 Petr Vobornik - 2.99.0-34 - Add Web UI reset password pages * Wed Jun 20 2012 Ondrej Hamada - 2.99.0-33 - Set min for 389-ds-base to 1.2.11.5-1 on F17 to fix installation issue - Set min for 389-ds-base to 1.2.10.10-1 on F16 (and lower) to fix CN case persistence * Fri Jun 8 2012 Martin Kosek - 2.99.0-32 - Add directory /var/lib/ipa/sysupgrade for package upgrade metadata - Set min for bind-dyndb-ldap to 1.1.0-0.12.rc1 to pick up persistent search related bug fixes * Mon Jun 4 2012 Alexander Bokovoy - 2.99.0-31 - Add python-crypto to build dependencies for AD server-side code * Tue May 29 2012 Alexander Bokovoy - 2.99.0-30 - Add freeipa-server-trust-ad virtual package to capture all required dependencies for Active Directory trust management * Fri May 11 2012 Martin Kosek - 2.99.0-29 - Replace used DNS client library (acutil) with python-dns * Tue Apr 10 2012 Rob Crittenden - 2.99.0-28 - Set min for selinux-policy to 3.10.0-110 on F-17 to pick up certmonger policy for restarting services. - Set min for certmonger to 0.53 so we have the -C option to set restart commands. * Thu Apr 5 2012 Rob Crittenden - 2.99.0-27 - Bump minimum version of slapi-nis to 0.40 * Tue Mar 27 2012 Rob Crittenden - 2.99.0-26 - Add python-krbV Requires on client package * Mon Mar 26 2012 Rob Crittenden - 2.99.0-25 - Set min for 389-ds-base to 1.2.10.4-2 to fix upgrade issue * Fri Mar 23 2012 Petr Viktorin - 2.99.0-24 - Add python-lxml and python-pyasn1 to BuildRequires * Mon Mar 19 2012 Martin Kosek - 2.99.0-23 - Set min for bind-dyndb-ldap and bind to pick up new features and bug fixes * Thu Mar 1 2012 Jan Cholasta - 2.99.0-22 - Set min nvr of sssd to 1.8.0 for SSH support - Add BuildRequires on sssd >= 1.8.0 * Wed Feb 29 2012 Petr Vobornik - 2.99.0-21 - Add Web UI form based login page - Removed ipa_migration.css * Wed Feb 29 2012 Petr Vobornik - 2.99.0-20 - Add Web UI logout page * Mon Feb 27 2012 Rob Crittenden - 2.99.0-19 - Add Requires to ipa-client on oddjob-mkhomedir * Fri Feb 24 2012 Martin Kosek - 2.99.0-18 - Set min for bind-dyndb-ldap to 1.1.0-0.8.a2 to pick up new features * Thu Feb 23 2012 Rob Crittenden - 2.99.0-17 - Add Conflicts on mod_ssl * Thu Feb 16 2012 Rob Crittenden - 2.99.0-16 - Set min for 389-ds-base to 1.2.10.1-1 to fix install segfault, schema replication. * Tue Jan 31 2012 Rob Crittenden - 2.99.0-15 - Set min for krb5-server to 1.9.2-6 to pick up needed s4u2proxy patches * Wed Jan 11 2012 Rob Crittenden - 2.99.0-14 - Set min for mod_auth_kerb to 5.4-8 to pick up s4u2proxy support * Fri Dec 9 2011 Alexander Bokovoy - 2.99.0-13 - Fix dependency for samba4-devel package * Thu Nov 17 2011 Simo Sorce - 2.99.0-12 - Add CLDAP plugin - Set min nvr of 389-ds-base to 1.2.10-0.5.a5 for SLAPI_PLUGIN_CONFIG_ENTRY support * Mon Nov 14 2011 Endi S. Dewata - 2.99.0-11 - Make sure changes to extension.js are not removed. * Wed Oct 26 2011 Endi S. Dewata - 2.99.0-10 - Moved UI images into install/ui/images * Mon Oct 24 2011 Endi S. Dewata - 2.99.0-9 - Removed hbac-deny-remove.html * Fri Oct 21 2011 Alexander Bokovoy - 2.99.0-8 - Default to systemd for Fedora 16 and onwards * Fri Oct 14 2011 Rob Crittenden - 2.99.0-7 - Set min nvr of 389-ds-base to 1.2.10-0.4.a4 for limits fixes (740942, 742324) * Fri Oct 7 2011 Adam Young - 2.99.0-6 - Add explicit dependency on pki-setup. * Tue Sep 13 2011 Alexander Bokovoy - 2.99.0-5 - Make sure platform adaptation is packaged in -python sub-package * Fri Sep 9 2011 Martin Kosek - 2.99.0-4 - Add soft dependency for bind and bind-dyndb-ldap required versions * Wed Aug 31 2011 Rob Crittenden - 2.99.0-3 - Set min nvr of 389-ds-base to 1.2.9.7-1 for BZ 728605 * Mon Aug 29 2011 Rob Crittenden - 2.99.0-2 - Set min nvr of pki-ca to 9.0.12 for fix in BZ 700505 * Thu Aug 25 2011 Simo Sorce - 2.99.0-1 - Remove ipa_kpasswd. * Tue Aug 23 2011 Jan Cholasta - 2.1.0-1 - Add subscription-manager dependency for RHEL. * Thu Aug 11 2011 Martin Kosek - 2.0.90-12 - Set min nvr of 389-ds-base to 1.2.9.6 for fix in BZ 725743, 723937, and 725542 - Set min nvr of pki-ca to 9.0.11 for fix in BZ 728332 * Thu Aug 11 2011 Martin Kosek - 2.0.90-11 - Set min nvr of xmlrpc-c and libcurl to make sure GSSAPI delegation support is in * Tue Aug 2 2011 Endi S. Dewata - 2.0.90-10 - Add *.ico files * Fri Jul 29 2011 Alexander Bokovoy - 2.0.90-9 - Add libipa_hbac-python dependency for hbactest plugin * Thu Jul 28 2011 Rob Crittenden - 2.0.90-8 - Set min nvr of pki-ca to 9.0.10 on F-15+ to pick up updated caIPAserviceCert.cfg profile * Wed Jul 20 2011 Rob Crittenden - 2.0.90-7 - Make cyrus-sasl-gssapi requires arch-specific * Thu Jul 14 2011 Rob Crittenden - 2.0.90-6 - Add ipa-csreplica-manage tool. * Wed Jul 6 2011 Adam Young - 2.0.90-5 - Add HTML file describing issues with HBAC deny rules * Fri Jun 17 2011 Rob Crittenden - 2.0.90-4 - Ship ipa-ca-install utility * Thu May 12 2011 Rob Crittenden - 2.0.90-3 - Set min nvr of selinux-policy to 3.9.16-18 on F-15+ - Set min nvr of pki-ca to 9.0.7 on F-15+ * Thu May 5 2011 Martin Kosek - 2.0.90-2 - Add BuildRequires on pylint, python-rhsm to enable a build with enforced pylint check * Tue May 3 2011 Rob Crittenden - 2.0.90-1 - Bump version to 2.0.90 * Tue Apr 5 2011 Rob Crittenden - 1.99-47 - Set min version of 389-ds-base to 1.2.8.0-1 for fix in BZ 693466. * Thu Mar 17 2011 Rob Crittenden - 1.99-46 - Automatically apply updates when the package is upgraded. * Thu Feb 17 2011 Jakub Hrozek - 1.99-45 - Set minimum version of python-nss to 0.11 to make sure IPv6 support is in * Wed Feb 9 2011 Rob Crittenden - 1.99-44 - Set minimum version of sssd to 1.5.1 * Wed Feb 2 2011 Rob Crittenden - 1.99-43 - Set min version of 389-ds-base to 1.2.8 - Set min version of mod_nss 1.0.8-10 - Set min version of selinux-policy to 3.9.7-27 * Thu Jan 27 2011 Rob Crittenden - 1.99-42 - Apply changes discovered in Fedora package review process (#672986) * Tue Jan 25 2011 Rob Crittenden - 1.99-41 - Re-arrange doc and defattr to clean up rpmlint warnings - Remove conditionals on older releases - Move some man pages into admintools subpackage - Remove some explicit Requires in client that aren't needed - Consistent use of buildroot vs RPM_BUILD_ROOT * Wed Jan 19 2011 Adam Young - 1.99-40 - Moved directory install/static to install/ui * Thu Jan 13 2011 Simo Sorce - 1.99-39 - Remove dependency on nss_ldap/nss-pam-ldapd - The official client is sssd and that's what we use by default. * Thu Jan 13 2011 Simo Sorce - 1.99-38 - Remove radius subpackages * Thu Jan 13 2011 Rob Crittenden - 1.99-37 - Set minimum pki-ca and pki-silent versions to 9.0.0 * Wed Jan 12 2011 Rob Crittenden - 1.99-36 - Drop BuildRequires on mozldap-devel * Mon Dec 13 2010 Rob Crittenden - 1.99-35 - Add Requires on krb5-pkinit-openssl * Fri Dec 10 2010 Jr Aquino - 1.99-34 - Add ipa-host-net-manage script * Tue Dec 7 2010 Simo Sorce - 1.99-33 - Add ipa init script * Fri Nov 19 2010 Rob Crittenden - 1.99-32 - Set minimum level of 389-ds-base to 1.2.7 for enhanced memberof plugin * Wed Nov 3 2010 Rob Crittenden - 1.99-31 - remove ipa-fix-CVE-2008-3274 * Wed Oct 6 2010 Rob Crittenden - 1.99-30 - Remove duplicate %%files entries on share/ipa/static - Add python default encoding shared library * Mon Sep 20 2010 Rob Crittenden - 1.99-29 - Drop requires on python-configobj (not used any more) - Drop ipa-ldap-updater message, upgrades are done differently now * Wed Sep 8 2010 Rob Crittenden - 1.99-28 - Drop conflicts on mod_nss - Require nss-pam-ldapd on F-14 or higher instead of nss_ldap (#606847) - Drop a slew of conditionals on older Fedora releases (< 12) - Add a few conditionals against RHEL 6 - Add Requires of nss-tools on ipa-client * Fri Aug 13 2010 Rob Crittenden - 1.99-27 - Set minimum version of certmonger to 0.26 (to pck up #621670) - Set minimum version of pki-silent to 1.3.4 (adds -key_algorithm) - Set minimum version of pki-ca to 1.3.6 - Set minimum version of sssd to 1.2.1 * Tue Aug 10 2010 Rob Crittenden - 1.99-26 - Add BuildRequires for authconfig * Mon Jul 19 2010 Rob Crittenden - 1.99-25 - Bump up minimum version of python-nss to pick up nss_is_initialize() API * Thu Jun 24 2010 Adam Young - 1.99-24 - Removed python-asset based webui * Thu Jun 24 2010 Rob Crittenden - 1.99-23 - Change Requires from fedora-ds-base to 389-ds-base - Set minimum level of 389-ds-base to 1.2.6 for the replication version plugin. * Tue Jun 1 2010 Rob Crittenden - 1.99-22 - Drop Requires of python-krbV on ipa-client * Mon May 17 2010 Rob Crittenden - 1.99-21 - Load ipa_dogtag.pp in post install * Mon Apr 26 2010 Rob Crittenden - 1.99-20 - Set minimum level of sssd to 1.1.1 to pull in required hbac fixes. * Thu Mar 4 2010 Rob Crittenden - 1.99-19 - No need to create /var/log/ipa_error.log since we aren't using TurboGears any more. * Mon Mar 1 2010 Jason Gerard DeRose - 1.99-18 - Fixed share/ipa/wsgi.py so .pyc, .pyo files are included * Wed Feb 24 2010 Jason Gerard DeRose - 1.99-17 - Added Require mod_wsgi, added share/ipa/wsgi.py * Thu Feb 11 2010 Jason Gerard DeRose - 1.99-16 - Require python-wehjit >= 0.2.2 * Wed Feb 3 2010 Rob Crittenden - 1.99-15 - Add sssd and certmonger as a Requires on ipa-client * Wed Jan 27 2010 Jason Gerard DeRose - 1.99-14 - Require python-wehjit >= 0.2.0 * Fri Dec 4 2009 Rob Crittenden - 1.99-13 - Add ipa-rmkeytab tool * Tue Dec 1 2009 Rob Crittenden - 1.99-12 - Set minimum of python-pyasn1 to 0.0.9a so we have support for the ASN.1 Any type * Wed Nov 25 2009 Rob Crittenden - 1.99-11 - Remove v1-style /etc/ipa/ipa.conf, replacing with /etc/ipa/default.conf * Fri Nov 13 2009 Rob Crittenden - 1.99-10 - Add bash completion script and own /etc/bash_completion.d in case it doesn't already exist * Tue Nov 3 2009 Rob Crittenden - 1.99-9 - Remove ipa_webgui, its functions rolled into ipa_httpd * Mon Oct 12 2009 Jason Gerard DeRose - 1.99-8 - Removed python-cherrypy from BuildRequires and Requires - Added Requires python-assets, python-wehjit * Mon Aug 24 2009 Rob Crittenden - 1.99-7 - Added httpd SELinux policy so CRLs can be read * Thu May 21 2009 Rob Crittenden - 1.99-6 - Move ipalib to ipa-python subpackage - Bump minimum version of slapi-nis to 0.15 * Wed May 6 2009 Rob Crittenden - 1.99-5 - Set 0.14 as minimum version for slapi-nis * Wed Apr 22 2009 Rob Crittenden - 1.99-4 - Add Requires: python-nss to ipa-python sub-package * Thu Mar 5 2009 Rob Crittenden - 1.99-3 - Remove the IPA DNA plugin, use the DS one * Wed Mar 4 2009 Rob Crittenden - 1.99-2 - Build radius separately - Fix a few minor issues * Tue Feb 3 2009 Rob Crittenden - 1.99-1 - Replace TurboGears requirement with python-cherrypy * Sat Jan 17 2009 Tomas Mraz - 1.2.1-3 - rebuild with new openssl * Fri Dec 19 2008 Dan Walsh - 1.2.1-2 - Fix SELinux code * Mon Dec 15 2008 Simo Sorce - 1.2.1-1 - Fix breakage caused by python-kerberos update to 1.1 * Fri Dec 5 2008 Simo Sorce - 1.2.1-0 - New upstream release 1.2.1 * Sat Nov 29 2008 Ignacio Vazquez-Abrams - 1.2.0-4 - Rebuild for Python 2.6 * Fri Nov 14 2008 Simo Sorce - 1.2.0-3 - Respin after the tarball has been re-released upstream New hash is 506c9c92dcaf9f227cba5030e999f177 * Thu Nov 13 2008 Simo Sorce - 1.2.0-2 - Conditionally restart also dirsrv and httpd when upgrading * Wed Oct 29 2008 Rob Crittenden - 1.2.0-1 - Update to upstream version 1.2.0 - Set fedora-ds-base minimum version to 1.1.3 for winsync header - Set the minimum version for SELinux policy - Remove references to Fedora 7 * Wed Jul 23 2008 Simo Sorce - 1.1.0-3 - Fix for CVE-2008-3274 - Fix segfault in ipa-kpasswd in case getifaddrs returns a NULL interface - Add fix for bug #453185 - Rebuild against openldap libraries, mozldap ones do not work properly - TurboGears is currently broken in rawhide. Added patch to not build the UI locales and removed them from the ipa-server files section. * Wed Jun 18 2008 Rob Crittenden - 1.1.0-2 - Add call to /usr/sbin/upgradeconfig to post install * Wed Jun 11 2008 Rob Crittenden - 1.1.0-1 - Update to upstream version 1.1.0 - Patch for indexing memberof attribute - Patch for indexing uidnumber and gidnumber - Patch to change DNA default values for replicas - Patch to fix uninitialized variable in ipa-getkeytab * Fri May 16 2008 Rob Crittenden - 1.0.0-5 - Set fedora-ds-base minimum version to 1.1.0.1-4 and mod_nss minimum version to 1.0.7-4 so we pick up the NSS fixes. - Add selinux-policy-base(post) to Requires (446496) * Tue Apr 29 2008 Rob Crittenden - 1.0.0-4 - Add missing entry for /var/cache/ipa/kpasswd (444624) - Added patch to fix permissions problems with the Apache NSS database. - Added patch to fix problem with DNS querying where the query could be returned as the answer. - Fix spec error where patch1 was in the wrong section * Fri Apr 25 2008 Rob Crittenden - 1.0.0-3 - Added patch to fix problem reported by ldapmodify * Fri Apr 25 2008 Rob Crittenden - 1.0.0-2 - Fix Requires for krb5-server that was missing for Fedora versions > 9 - Remove quotes around test for fedora version to package egg-info * Fri Apr 18 2008 Rob Crittenden - 1.0.0-1 - Update to upstream version 1.0.0 * Tue Mar 18 2008 Rob Crittenden 0.99-12 - Pull upstream changelog 722 - Add Conflicts mod_ssl (435360) * Fri Feb 29 2008 Rob Crittenden 0.99-11 - Pull upstream changelog 698 - Fix ownership of /var/log/ipa_error.log during install (435119) - Add pwpolicy command and man page * Thu Feb 21 2008 Rob Crittenden 0.99-10 - Pull upstream changelog 678 - Add new subpackage, ipa-server-selinux - Add Requires: authconfig to ipa-python (bz #433747) - Package i18n files * Mon Feb 18 2008 Rob Crittenden 0.99-9 - Pull upstream changelog 641 - Require minimum version of krb5-server on F-7 and F-8 - Package some new files * Thu Jan 31 2008 Rob Crittenden 0.99-8 - Marked with wrong license. IPA is GPLv2. * Tue Jan 29 2008 Rob Crittenden 0.99-7 - Ensure that /etc/ipa exists before moving user-modifiable html files there - Put html files into /etc/ipa/html instead of /etc/ipa * Tue Jan 29 2008 Rob Crittenden 0.99-6 - Pull upstream changelog 608 which renamed several files * Thu Jan 24 2008 Rob Crittenden 0.99-5 - package the sessions dir /var/cache/ipa/sessions - Pull upstream changelog 597 * Thu Jan 24 2008 Rob Crittenden 0.99-4 - Updated upstream pull (596) to fix bug in ipa_webgui that was causing the UI to not start. * Thu Jan 24 2008 Rob Crittenden 0.99-3 - Included LICENSE and README in all packages for documentation - Move user-modifiable content to /etc/ipa and linked back to /usr/share/ipa/html - Changed some references to /usr to the {_usr} macro and /etc to {_sysconfdir} - Added popt-devel to BuildRequires for Fedora 8 and higher and popt for Fedora 7 - Package the egg-info for Fedora 9 and higher for ipa-python * Tue Jan 22 2008 Rob Crittenden 0.99-2 - Added auto* BuildRequires * Mon Jan 21 2008 Rob Crittenden 0.99-1 - Unified spec file * Thu Jan 17 2008 Rob Crittenden - 0.6.0-2 - Fixed License in specfile - Include files from /usr/lib/python*/site-packages/ipaserver * Fri Dec 21 2007 Karl MacMillan - 0.6.0-1 - Version bump for release * Wed Nov 21 2007 Karl MacMillan - 0.5.0-1 - Preverse mode on ipa-keytab-util - Version bump for relase and rpm name change * Thu Nov 15 2007 Rob Crittenden - 0.4.1-2 - Broke invididual Requires and BuildRequires onto separate lines and reordered them - Added python-tgexpandingformwidget as a dependency - Require at least fedora-ds-base 1.1 * Thu Nov 1 2007 Karl MacMillan - 0.4.1-1 - Version bump for release * Wed Oct 31 2007 Karl MacMillan - 0.4.0-6 - Add dep for freeipa-admintools and acl * Wed Oct 24 2007 Rob Crittenden - 0.4.0-5 - Add dependency for python-krbV * Fri Oct 19 2007 Rob Crittenden - 0.4.0-4 - Require mod_nss-1.0.7-2 for mod_proxy fixes * Thu Oct 18 2007 Karl MacMillan - 0.4.0-3 - Convert to autotools-based build * Tue Sep 25 2007 Karl MacMillan - 0.4.0-2 * Fri Sep 7 2007 Karl MacMillan - 0.3.0-1 - Added support for libipa-dna-plugin * Fri Aug 10 2007 Karl MacMillan - 0.2.0-1 - Added support for ipa_kpasswd and ipa_pwd_extop * Sun Aug 5 2007 Rob Crittenden - 0.1.0-3 - Abstracted client class to work directly or over RPC * Wed Aug 1 2007 Rob Crittenden - 0.1.0-2 - Add mod_auth_kerb and cyrus-sasl-gssapi to Requires - Remove references to admin server in ipa-server-setupssl - Generate a client certificate for the XML-RPC server to connect to LDAP with - Create a keytab for Apache - Create an ldif with a test user - Provide a certmap.conf for doing SSL client authentication * Fri Jul 27 2007 Karl MacMillan - 0.1.0-1 - Initial rpm version freeipa-3.3.4/.gitignore0000664000175000017500000000327312271663206014504 0ustar mkosekmkosekconfigure config.h config.h.in Makefile Makefile.in .deps/ .libs/ *.la *.lo *.log *.o *.pyc *.trs .bzr freeipa2-dev-doc build dist/ RELEASE daemons/AUTHORS daemons/COPYING daemons/ChangeLog daemons/INSTALL daemons/NEWS daemons/README daemons/aclocal.m4 daemons/autom4te.cache/ daemons/config.guess daemons/config.log daemons/config.status daemons/config.sub daemons/depcomp daemons/install-sh daemons/ipa-otpd/ipa-otpd daemons/ipa-otpd/ipa-otpd.socket daemons/ipa-otpd/ipa-otpd@.service daemons/ipa-version.h daemons/libtool daemons/ltmain.sh daemons/missing daemons/stamp-h1 daemons/test-driver install/AUTHORS install/COPYING install/ChangeLog install/INSTALL install/NEWS install/README install/aclocal.m4 install/autom4te.cache/ install/config.log install/config.status install/install-sh install/missing install/stamp-h1 install/po/test.po install/po/test_locale/xh_ZA/LC_MESSAGES/ipa.mo install/ui/test/results install/ui/release install/ui/src/dojo install/ui/src/build install/ui/src/plugins ipa-client/COPYING ipa-client/ChangeLog ipa-client/INSTALL ipa-client/aclocal.m4 ipa-client/autom4te.cache/ ipa-client/config.guess ipa-client/config.log ipa-client/config.status ipa-client/config.sub ipa-client/depcomp ipa-client/install-sh ipa-client/ipa-client.spec ipa-client/ipa-getkeytab ipa-client/ipa-join ipa-client/ipa-rmkeytab ipa-client/libtool ipa-client/ltmain.sh ipa-client/missing ipa-client/py-compile ipa-client/stamp-h1 ipa-client/version.m4 ipatests/test_xmlrpc/service.crt ipatests/man/aclocal.m4 ipatests/man/autom4te.cache/ ipatests/man/config.status ipatests/man/install-sh ipatests/man/missing freeipa.spec ipapython/setup.py ipapython/version.py version.m4 ipapython/services.py ipatests/setup.py freeipa-3.3.4/ipaserver/0000775000175000017500000000000012271663206014507 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/__init__.py0000664000175000017500000000146612202434255016621 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ Package containing server backend. """ freeipa-3.3.4/ipaserver/dcerpc.py0000664000175000017500000013604612271663206016333 0ustar mkosekmkosek# Authors: # Alexander Bokovoy # # Copyright (C) 2011 Red Hat # see file 'COPYING' for use and warranty information # # Portions (C) Andrew Tridgell, Andrew Bartlett # # 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 . # Make sure we only run this module at the server where samba4-python # package is installed to avoid issues with unavailable modules from ipalib.plugins.baseldap import * from ipalib import api, Str, Password, DefaultFrom, _, ngettext, Object from ipalib.parameters import Enum from ipalib import Command from ipalib import errors from ipapython import ipautil from ipapython.ipa_log_manager import * from ipapython.dn import DN from ipaserver.install import installutils from ipaserver.plugins import ldap2 from ipalib.util import normalize_name import os, string, struct, copy import uuid from samba import param from samba import credentials from samba.dcerpc import security, lsa, drsblobs, nbt, netlogon from samba.ndr import ndr_pack, ndr_print from samba import net import samba import random from M2Crypto import RC4 try: from ldap.controls import RequestControl as LDAPControl #pylint: disable=F0401 except ImportError: from ldap.controls import LDAPControl as LDAPControl #pylint: disable=F0401 import ldap as _ldap from ipapython.ipaldap import IPAdmin from ipalib.session import krbccache_dir, krbccache_prefix from dns import resolver, rdatatype from dns.exception import DNSException import pysss_nss_idmap import pysss __doc__ = _(""" Classes to manage trust joins using DCE-RPC calls The code in this module relies heavily on samba4-python package and Samba4 python bindings. """) def is_sid_valid(sid): try: security.dom_sid(sid) except TypeError: return False else: return True 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')), -1073741811: # NT_STATUS_INVALID_PARAMETER errors.RemoteRetrieveError( reason=_('AD domain controller complains about communication sequence. It may mean unsynchronized time on both sides, for example')), } 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] reason = _('''CIFS server communication error: code "%(num)s", message "%(message)s" (both may be "None")''') % dict(num=num, message=message) return errors.RemoteRetrieveError(reason=reason) class ExtendedDNControl(LDAPControl): # This class attempts to implement LDAP control that would work # with both python-ldap 2.4.x and 2.3.x, thus there is mix of properties # from both worlds and encodeControlValue has default parameter def __init__(self): self.controlValue = 1 self.controlType = "1.2.840.113556.1.4.529" self.criticality = False self.integerValue = 1 def encodeControlValue(self, value=None): return '0\x03\x02\x01\x01' class DomainValidator(object): ATTR_FLATNAME = 'ipantflatname' ATTR_SID = 'ipantsecurityidentifier' ATTR_TRUSTED_SID = 'ipanttrusteddomainsid' ATTR_TRUST_PARTNER = 'ipanttrustpartner' ATTR_TRUST_AUTHOUT = 'ipanttrustauthoutgoing' def __init__(self, api): self.api = api self.ldap = self.api.Backend.ldap2 self.domain = None self.flatname = None self.dn = None self.sid = None self._domains = None self._info = dict() self._creds = None self._parm = None def is_configured(self): cn_trust_local = DN(('cn', self.api.env.domain), self.api.env.container_cifsdomains, self.api.env.basedn) try: (dn, entry_attrs) = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID]) self.flatname = entry_attrs[self.ATTR_FLATNAME][0] self.sid = entry_attrs[self.ATTR_SID][0] self.dn = dn self.domain = self.api.env.domain except errors.NotFound, e: return False return True def get_trusted_domains(self): """ Returns case-insensitive dict of trusted domain tuples (flatname, sid, trust_auth_outgoing), keyed by domain name. """ cn_trust = DN(('cn', 'ad'), self.api.env.container_trusts, self.api.env.basedn) try: search_kw = {'objectClass': 'ipaNTTrustedDomain'} filter = self.ldap.make_filter(search_kw, rules=self.ldap.MATCH_ALL) (entries, truncated) = self.ldap.find_entries( filter=filter, base_dn=cn_trust, attrs_list=[self.ATTR_TRUSTED_SID, self.ATTR_FLATNAME, self.ATTR_TRUST_PARTNER] ) # We need to use case-insensitive dictionary since we use # domain names as keys and those are generally case-insensitive result = ipautil.CIDict() for dn, entry in entries: try: trust_partner = entry[self.ATTR_TRUST_PARTNER][0] flatname_normalized = entry[self.ATTR_FLATNAME][0].lower() trusted_sid = entry[self.ATTR_TRUSTED_SID][0] except KeyError, e: # Some piece of trusted domain info in LDAP is missing # Skip the domain, but leave log entry for investigation api.log.warn("Trusted domain '%s' entry misses an " "attribute: %s", dn, e) continue result[trust_partner] = (flatname_normalized, security.dom_sid(trusted_sid)) return result except errors.NotFound, e: return [] def set_trusted_domains(self): # At this point we have SID_NT_AUTHORITY family SID and really need to # check it against prefixes of domain SIDs we trust to if not self._domains: self._domains = self.get_trusted_domains() if len(self._domains) == 0: # Our domain is configured but no trusted domains are configured # This means we can't check the correctness of a trusted # domain SIDs raise errors.ValidationError(name='sid', error=_('no trusted domain is configured')) def get_domain_by_sid(self, sid, exact_match=False): if not self.domain: # our domain is not configured or self.is_configured() never run # reject SIDs as we can't check correctness of them raise errors.ValidationError(name='sid', error=_('domain is not configured')) # Parse sid string to see if it is really in a SID format try: test_sid = security.dom_sid(sid) except TypeError: raise errors.ValidationError(name='sid', error=_('SID is not valid')) # At this point we have SID_NT_AUTHORITY family SID and really need to # check it against prefixes of domain SIDs we trust to self.set_trusted_domains() # We have non-zero list of trusted domains and have to go through # them one by one and check their sids as prefixes / exact match # depending on the value of exact_match flag if exact_match: # check exact match of sids for domain in self._domains: if sid == str(self._domains[domain][1]): return domain raise errors.NotFound(reason=_("SID does not match exactly" "with any trusted domain's SID")) else: # check as prefixes test_sid_subauths = test_sid.sub_auths for domain in self._domains: domsid = self._domains[domain][1] sub_auths = domsid.sub_auths num_auths = min(test_sid.num_auths, domsid.num_auths) if test_sid_subauths[:num_auths] == sub_auths[:num_auths]: return domain raise errors.NotFound(reason=_('SID does not match any ' 'trusted domain')) def is_trusted_sid_valid(self, sid): try: self.get_domain_by_sid(sid) except (errors.ValidationError, errors.NotFound): return False else: return True def is_trusted_domain_sid_valid(self, sid): try: self.get_domain_by_sid(sid, exact_match=True) except (errors.ValidationError, errors.NotFound): return False else: return True def get_sid_from_domain_name(self, name): """Returns binary representation of SID for the trusted domain name or None if name is not in the list of trusted domains.""" domains = self.get_trusted_domains() if name in domains: return domains[name][1] else: return None def get_trusted_domain_objects(self, domain=None, flatname=None, filter="", attrs=None, scope=_ldap.SCOPE_SUBTREE, basedn=None): """ Search for LDAP objects in a trusted domain specified either by `domain' or `flatname'. The actual LDAP search is specified by `filter', `attrs', `scope' and `basedn'. When `basedn' is empty, database root DN is used. """ assert domain is not None or flatname is not None """Returns SID for the trusted domain object (user or group only)""" if not self.domain: # our domain is not configured or self.is_configured() never run raise errors.ValidationError(name=_('Trust setup'), error=_('Our domain is not configured')) if not self._domains: self._domains = self.get_trusted_domains() if len(self._domains) == 0: # Our domain is configured but no trusted domains are configured raise errors.ValidationError(name=_('Trust setup'), error=_('No trusted domain is not configured')) entries = None if domain is not None: if domain not in self._domains: raise errors.ValidationError(name=_('trusted domain object'), error= _('domain is not trusted')) # Now we have a name to check against our list of trusted domains entries = self.search_in_dc(domain, filter, attrs, scope, basedn) elif flatname is not None: # Flatname was specified, traverse through the list of trusted # domains first to find the proper one found_flatname = False for domain in self._domains: if self._domains[domain][0] == flatname: found_flatname = True entries = self.search_in_dc(domain, filter, attrs, scope, basedn) if entries: break if not found_flatname: raise errors.ValidationError(name=_('trusted domain object'), error= _('no trusted domain matched the specified flat name')) if not entries: raise errors.NotFound(reason=_('trusted domain object not found')) return entries def get_trusted_domain_object_sid(self, object_name): result = pysss_nss_idmap.getsidbyname(object_name) if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]): object_sid = result[object_name][pysss_nss_idmap.SID_KEY] return object_sid # Else, we are going to contact AD DC LDAP components = normalize_name(object_name) if not ('domain' in components or 'flatname' in components): # No domain or realm specified, ambiguous search raise errors.ValidationError(name=_('trusted domain object'), error= _('Ambiguous search, user domain was not specified')) attrs = ['objectSid'] filter = '(&(sAMAccountName=%(name)s)(|(objectClass=user)(objectClass=group)))' \ % dict(name=components['name']) scope = _ldap.SCOPE_SUBTREE entries = self.get_trusted_domain_objects(components.get('domain'), components.get('flatname'), filter, attrs, scope) if len(entries) > 1: # Treat non-unique entries as invalid raise errors.ValidationError(name=_('trusted domain object'), error= _('Trusted domain did not return a unique object')) sid = self.__sid_to_str(entries[0][1]['objectSid'][0]) try: test_sid = security.dom_sid(sid) return unicode(test_sid) except TypeError, e: raise errors.ValidationError(name=_('trusted domain object'), error= _('Trusted domain did not return a valid SID for the object')) def __get_trusted_domain_user_and_groups(self, object_name): """ Returns a tuple with user SID and a list of SIDs of all groups he is a member of. LIMITATIONS: - only Trusted Admins group members can use this function as it uses secret for IPA-Trusted domain link - List of group SIDs does not contain group memberships outside of the trusted domain """ components = normalize_name(object_name) domain = components.get('domain') flatname = components.get('flatname') name = components.get('name') is_valid_sid = is_sid_valid(object_name) if is_valid_sid: # Find a trusted domain for the SID domain = self.get_domain_by_sid(object_name) # Now search a trusted domain for a user with this SID attrs = ['cn'] filter = '(&(objectClass=user)(objectSid=%(sid)s))' \ % dict(sid=object_name) try: entries = self.get_trusted_domain_objects(domain=domain, filter=filter, attrs=attrs, scope=_ldap.SCOPE_SUBTREE) except errors.NotFound: raise errors.NotFound(reason=_('trusted domain user not found')) user_dn = entries[0][0] elif domain or flatname: attrs = ['cn'] filter = '(&(sAMAccountName=%(name)s)(objectClass=user))' \ % dict(name=name) try: entries = self.get_trusted_domain_objects(domain, flatname, filter, attrs, _ldap.SCOPE_SUBTREE) except errors.NotFound: raise errors.NotFound(reason=_('trusted domain user not found')) user_dn = entries[0][0] else: # No domain or realm specified, ambiguous search raise errors.ValidationError(name=_('trusted domain object'), error= _('Ambiguous search, user domain was not specified')) # Get SIDs of user object and it's groups # tokenGroups attribute must be read with a scope BASE for a known user # distinguished name to avoid search error attrs = ['objectSID', 'tokenGroups'] filter = "(objectClass=user)" entries = self.get_trusted_domain_objects(domain, flatname, filter, attrs, _ldap.SCOPE_BASE, user_dn) object_sid = self.__sid_to_str(entries[0][1]['objectSid'][0]) group_sids = [self.__sid_to_str(sid) for sid in entries[0][1]['tokenGroups']] return (object_sid, group_sids) def get_trusted_domain_user_and_groups(self, object_name): """ Returns a tuple with user SID and a list of SIDs of all groups he is a member of. First attempts to perform SID lookup via SSSD and in case of failure resorts back to checking trusted domain's AD DC LDAP directly. LIMITATIONS: - only Trusted Admins group members can use this function as it uses secret for IPA-Trusted domain link if SSSD lookup failed - List of group SIDs does not contain group memberships outside of the trusted domain """ group_sids = None group_list = None object_sid = None is_valid_sid = is_sid_valid(object_name) if is_valid_sid: object_sid = object_name result = pysss_nss_idmap.getnamebysid(object_name) if object_name in result and (pysss_nss_idmap.NAME_KEY in result[object_name]): group_list = pysss.getgrouplist(result[object_name][pysss_nss_idmap.NAME_KEY]) else: result = pysss_nss_idmap.getsidbyname(object_name) if object_name in result and (pysss_nss_idmap.SID_KEY in result[object_name]): object_sid = result[object_name][pysss_nss_idmap.SID_KEY] group_list = pysss.getgrouplist(object_name) if not group_list: return self.__get_trusted_domain_user_and_groups(object_name) group_sids = pysss_nss_idmap.getsidbyname(group_list) return (object_sid, [el[1][pysss_nss_idmap.SID_KEY] for el in group_sids.items()]) def __sid_to_str(self, sid): """ Converts binary SID to string representation Returns unicode string """ sid_rev_num = ord(sid[0]) number_sub_id = ord(sid[1]) ia = struct.unpack('!Q','\x00\x00'+sid[2:8])[0] subs = [ struct.unpack(', we use krbccache_prefix++ so there is no clash. Returns tuple (ccache path, principal) where (None, None) signifes an error on ccache initialization """ domain_suffix = domain.replace('.', '-') ccache_name = "%sTD%s" % (krbccache_prefix, domain_suffix) ccache_path = os.path.join(krbccache_dir, ccache_name) realm = api.env.realm hostname = api.env.host principal = 'HTTP/%s@%s' % (hostname, realm) keytab = '/etc/httpd/conf/ipa.keytab' # Destroy the contents of the ccache root_logger.debug('Destroying the contents of the separate ccache') (stdout, stderr, returncode) = ipautil.run( ['/usr/bin/kdestroy', '-A', '-c', ccache_path], env={'KRB5CCNAME': ccache_path}, raiseonerr=False) # Destroy the contents of the ccache root_logger.debug('Running kinit from ipa.keytab to obtain HTTP ' 'service principal with MS-PAC attached.') (stdout, stderr, returncode) = ipautil.run( ['/usr/bin/kinit', '-kt', keytab, principal], env={'KRB5CCNAME': ccache_path}, raiseonerr=False) if returncode == 0: return (ccache_path, principal) else: return (None, None) def search_in_dc(self, domain, filter, attrs, scope, basedn=None, quiet=False): """ Perform LDAP search in a trusted domain `domain' Domain Controller. Returns resulting entries or None. """ entries = None info = self.__retrieve_trusted_domain_gc_list(domain) if not info: raise errors.ValidationError( name=_('Trust setup'), error=_('Cannot retrieve trusted domain GC list')) for (host, port) in info['gc']: entries = self.__search_in_dc(info, host, port, filter, attrs, scope, basedn=basedn, quiet=quiet) if entries: break return entries def __search_in_dc(self, info, host, port, filter, attrs, scope, basedn=None, quiet=False): """ Actual search in AD LDAP server, using SASL GSSAPI authentication Returns LDAP result or None. """ (ccache_name, principal) = self.kinit_as_http(info['dns_domain']) if ccache_name: with installutils.private_ccache(path=ccache_name): entries = None try: conn = IPAdmin(host=host, port=389, # query the AD DC no_schema=True, decode_attrs=False, sasl_nocanon=True) # sasl_nocanon used to avoid hard requirement for PTR # records pointing back to the same host name conn.do_sasl_gssapi_bind() if basedn is None: # Use domain root base DN basedn = ipautil.realm_to_suffix(info['dns_domain']) entries = conn.get_entries(basedn, scope, filter, attrs) except Exception, e: msg = "Search on AD DC {host}:{port} failed with: {err}"\ .format(host=host, port=str(port), err=str(e)) if quiet: root_logger.debug(msg) else: root_logger.warning(msg) finally: return entries def __retrieve_trusted_domain_gc_list(self, domain): """ Retrieves domain information and preferred GC list Returns dictionary with following keys name -- NetBIOS name of the trusted domain dns_domain -- DNS name of the trusted domain gc -- array of tuples (server, port) for Global Catalog """ if domain in self._info: return self._info[domain] if not self._creds: self._parm = param.LoadParm() self._parm.load(os.path.join(ipautil.SHARE_DIR,"smb.conf.empty")) self._parm.set('netbios name', self.flatname) self._creds = credentials.Credentials() self._creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) self._creds.guess(self._parm) self._creds.set_workstation(self.flatname) netrc = net.Net(creds=self._creds, lp=self._parm) finddc_error = None result = None try: result = netrc.finddc(domain=domain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_GC | nbt.NBT_SERVER_CLOSEST) except RuntimeError, e: finddc_error = e if not self._domains: self._domains = self.get_trusted_domains() info = dict() servers = [] if result: info['name'] = unicode(result.domain_name) info['dns_domain'] = unicode(result.dns_domain) servers = [(unicode(result.pdc_dns_name), 3268)] else: info['name'] = self._domains[domain] info['dns_domain'] = domain # Retrieve GC servers list gc_name = '_gc._tcp.%s.' % info['dns_domain'] try: answers = resolver.query(gc_name, rdatatype.SRV) except DNSException, e: answers = [] for answer in answers: server = str(answer.target).rstrip(".") servers.append((server, answer.port)) info['gc'] = servers # Both methods should not fail at the same time if finddc_error and len(info['gc']) == 0: raise assess_dcerpc_exception(message=str(finddc_error)) self._info[domain] = info return info def string_to_array(what): blob = [0] * len(what) for i in range(len(what)): blob[i] = ord(what[i]) return blob class TrustDomainInstance(object): def __init__(self, hostname, creds=None): self.parm = param.LoadParm() self.parm.load(os.path.join(ipautil.SHARE_DIR,"smb.conf.empty")) if len(hostname) > 0: self.parm.set('netbios name', hostname) self.creds = creds self.hostname = hostname self.info = {} self._pipe = None self._policy_handle = None self.read_only = False self.ftinfo_records = None def __gen_lsa_connection(self, binding): if self.creds is None: raise errors.RequirementError(name=_('CIFS credentials object')) try: result = lsa.lsarpc(binding, self.parm, self.creds) return result except RuntimeError, (num, message): raise assess_dcerpc_exception(num=num, message=message) def init_lsa_pipe(self, remote_host): """ Try to initialize connection to the LSA pipe at remote host. This method tries consequently all possible transport options and selects one that works. See __gen_lsa_bindings() for details. The actual result may depend on details of existing credentials. For example, using signing causes NO_SESSION_KEY with Win2K8 and using kerberos against Samba with signing does not work. """ # short-cut: if LSA pipe is initialized, skip completely if self._pipe: return attempts = 0 bindings = self.__gen_lsa_bindings(remote_host) for binding in bindings: 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 %(host)s denied your credentials') % dict(host=remote_host)) if self._pipe is None: raise errors.RemoteRetrieveError( reason=_('Cannot establish LSA connection to %(host)s. Is CIFS server running?') % dict(host=remote_host)) self.binding = binding def __gen_lsa_bindings(self, remote_host): """ There are multiple transports to issue LSA calls. However, depending on a system in use they may be blocked by local operating system policies. Generate all we can use. init_lsa_pipe() will try them one by one until there is one working. We try NCACN_NP before NCACN_IP_TCP and signed sessions before unsigned. """ transports = (u'ncacn_np', u'ncacn_ip_tcp') options = ( u',', u'') binding_template=lambda x,y,z: u'%s:%s[%s]' % (x, y, z) return [binding_template(t, remote_host, o) for t in transports for o in options] def retrieve_anonymously(self, remote_host, discover_srv=False): """ When retrieving DC information anonymously, we can't get SID of the domain """ netrc = net.Net(creds=self.creds, lp=self.parm) 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) self.info['dns_domain'] = unicode(result.dns_domain) self.info['dns_forest'] = unicode(result.forest) self.info['guid'] = unicode(result.domain_uuid) self.info['dc'] = unicode(result.pdc_dns_name) # Netlogon response doesn't contain SID of the domain. # We need to do rootDSE search with LDAP_SERVER_EXTENDED_DN_OID control to reveal the SID ldap_uri = 'ldap://%s' % (result.pdc_dns_name) conn = _ldap.initialize(ldap_uri) conn.set_option(_ldap.OPT_SERVER_CONTROLS, [ExtendedDNControl()]) search_result = None try: (objtype, res) = conn.search_s('', _ldap.SCOPE_BASE)[0] search_result = res['defaultNamingContext'][0] self.info['dns_hostname'] = res['dnsHostName'][0] except _ldap.LDAPError, e: root_logger.error( "LDAP error when connecting to %(host)s: %(error)s" % dict(host=unicode(result.pdc_name), error=str(e))) except KeyError, e: root_logger.error("KeyError: {err}, LDAP entry from {host} " "returned malformed. Your DNS might be " "misconfigured." .format(host=unicode(result.pdc_name), err=unicode(e))) if search_result: self.info['sid'] = self.parse_naming_context(search_result) return True def parse_naming_context(self, context): naming_ref = re.compile('.*.*') return naming_ref.match(context).group(1) def retrieve(self, remote_host): self.init_lsa_pipe(remote_host) objectAttribute = lsa.ObjectAttribute() objectAttribute.sec_qos = lsa.QosInfo() 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) self.info['guid'] = unicode(result.domain_guid) self.info['sid'] = unicode(result.sid) self.info['dc'] = remote_host def generate_auth(self, trustdom_secret): def arcfour_encrypt(key, data): c = RC4.RC4(key) return c.update(data) password_blob = string_to_array(trustdom_secret.encode('utf-16-le')) clear_value = drsblobs.AuthInfoClear() clear_value.size = len(password_blob) clear_value.password = password_blob clear_authentication_information = drsblobs.AuthenticationInformation() clear_authentication_information.LastUpdateTime = samba.unix2nttime(int(time.time())) clear_authentication_information.AuthType = lsa.TRUST_AUTH_TYPE_CLEAR clear_authentication_information.AuthInfo = clear_value authentication_information_array = drsblobs.AuthenticationInformationArray() authentication_information_array.count = 1 authentication_information_array.array = [clear_authentication_information] outgoing = drsblobs.trustAuthInOutBlob() outgoing.count = 1 outgoing.current = authentication_information_array confounder = [3]*512 for i in range(512): confounder[i] = random.randint(0, 255) trustpass = drsblobs.trustDomainPasswords() trustpass.confounder = confounder trustpass.outgoing = outgoing trustpass.incoming = outgoing trustpass_blob = ndr_pack(trustpass) encrypted_trustpass = arcfour_encrypt(self._pipe.session_key, trustpass_blob) auth_blob = lsa.DATA_BUF2() auth_blob.size = len(encrypted_trustpass) auth_blob.data = string_to_array(encrypted_trustpass) auth_info = lsa.TrustDomainInfoAuthInfoInternal() auth_info.auth_blob = auth_blob self.auth_info = auth_info def generate_ftinfo(self, another_domain): """ Generates TrustDomainInfoFullInfo2Internal structure This structure allows to pass information about all domains associated with the another domain's realm. Only top level name and top level name exclusions are handled here. """ if not another_domain.ftinfo_records: return ftinfo_records = [] info = lsa.ForestTrustInformation() for rec in another_domain.ftinfo_records: record = lsa.ForestTrustRecord() record.flags = 0 record.time = rec['rec_time'] record.type = rec['rec_type'] record.forest_trust_data.string = rec['rec_name'] ftinfo_records.append(record) info.count = len(ftinfo_records) info.entries = ftinfo_records return info def update_ftinfo(self, another_domain): """ Updates forest trust information in this forest corresponding to the another domain's information. """ try: if another_domain.ftinfo_records: ftinfo = self.generate_ftinfo(another_domain) # Set forest trust information -- we do it only against AD DC as # smbd already has the information about itself ldname = lsa.StringLarge() ldname.string = another_domain.info['dns_domain'] collision_info = self._pipe.lsaRSetForestTrustInformation(self._policy_handle, ldname, lsa.LSA_FOREST_TRUST_DOMAIN_INFO, ftinfo, 0) if collision_info: root_logger.error("When setting forest trust information, got collision info back:\n%s" % (ndr_print(collision_info))) except RuntimeError, e: # We can ignore the error here -- setting up name suffix routes may fail pass def establish_trust(self, another_domain, trustdom_secret): """ Establishes trust between our and another domain Input: another_domain -- instance of TrustDomainInstance, initialized with #retrieve call trustdom_secret -- shared secred used for the trust """ if self.info['name'] == another_domain.info['name']: # Check that NetBIOS names do not clash raise errors.ValidationError(name=u'AD Trust Setup', error=_('the IPA server and the remote domain cannot share the same ' 'NetBIOS name: %s') % self.info['name']) self.generate_auth(trustdom_secret) info = lsa.TrustDomainInfoInfoEx() info.domain_name.string = another_domain.info['dns_domain'] info.netbios_name.string = another_domain.info['name'] info.sid = security.dom_sid(another_domain.info['sid']) info.trust_direction = lsa.LSA_TRUST_DIRECTION_INBOUND | lsa.LSA_TRUST_DIRECTION_OUTBOUND info.trust_type = lsa.LSA_TRUST_TYPE_UPLEVEL info.trust_attributes = lsa.LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE try: dname = lsa.String() 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 RuntimeError, e: pass try: trustdom_handle = 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) self.update_ftinfo(another_domain) # We should use proper trustdom handle in order to modify the # trust settings. Samba insists this has to be done with LSA # OpenTrustedDomain* calls, it is not enough to have a handle # returned by the CreateTrustedDomainEx2 call. trustdom_handle = self._pipe.OpenTrustedDomainByName(self._policy_handle, dname, security.SEC_FLAG_MAXIMUM_ALLOWED) try: infoclass = lsa.TrustDomainInfoSupportedEncTypes() infoclass.enc_types = security.KERB_ENCTYPE_RC4_HMAC_MD5 infoclass.enc_types |= security.KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96 infoclass.enc_types |= security.KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96 self._pipe.SetInformationTrustedDomain(trustdom_handle, lsa.LSA_TRUSTED_DOMAIN_SUPPORTED_ENCRYPTION_TYPES, infoclass) except RuntimeError, e: # We can ignore the error here -- changing enctypes is for # improved security but the trust will work with default values as # well. In particular, the call may fail against Windows 2003 # server as that one doesn't support AES encryption types pass def verify_trust(self, another_domain): def retrieve_netlogon_info_2(domain, function_code, data): try: netr_pipe = netlogon.netlogon(domain.binding, domain.parm, domain.creds) result = netr_pipe.netr_LogonControl2Ex(logon_server=None, function_code=function_code, level=2, data=data ) return result except RuntimeError, (num, message): raise assess_dcerpc_exception(num=num, message=message) result = retrieve_netlogon_info_2(self, netlogon.NETLOGON_CONTROL_TC_VERIFY, another_domain.info['dns_domain']) if (result and (result.flags and netlogon.NETLOGON_VERIFY_STATUS_RETURNED)): # netr_LogonControl2Ex() returns non-None result only if overall call # result was WERR_OK which means verification was correct. # We only check that it was indeed status for verification process return True return False def fetch_domains(api, mydomain, trustdomain, creds=None): trust_flags = dict( NETR_TRUST_FLAG_IN_FOREST = 0x00000001, NETR_TRUST_FLAG_OUTBOUND = 0x00000002, NETR_TRUST_FLAG_TREEROOT = 0x00000004, NETR_TRUST_FLAG_PRIMARY = 0x00000008, NETR_TRUST_FLAG_NATIVE = 0x00000010, NETR_TRUST_FLAG_INBOUND = 0x00000020, NETR_TRUST_FLAG_MIT_KRB5 = 0x00000080, NETR_TRUST_FLAG_AES = 0x00000100) trust_attributes = dict( NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE = 0x00000001, NETR_TRUST_ATTRIBUTE_UPLEVEL_ONLY = 0x00000002, NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN = 0x00000004, NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE = 0x00000008, NETR_TRUST_ATTRIBUTE_CROSS_ORGANIZATION = 0x00000010, NETR_TRUST_ATTRIBUTE_WITHIN_FOREST = 0x00000020, NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL = 0x00000040) def communicate(td): td.init_lsa_pipe(td.info['dc']) netr_pipe = netlogon.netlogon(td.binding, td.parm, td.creds) domains = netr_pipe.netr_DsrEnumerateDomainTrusts(td.binding, 1) return domains domains = None domain_validator = DomainValidator(api) configured = domain_validator.is_configured() if not configured: return None td = TrustDomainInstance('') td.parm.set('workgroup', mydomain) cr = credentials.Credentials() cr.set_kerberos_state(credentials.DONT_USE_KERBEROS) cr.guess(td.parm) cr.set_anonymous() cr.set_workstation(domain_validator.flatname) netrc = net.Net(creds=cr, lp=td.parm) try: result = netrc.finddc(domain=trustdomain, flags=nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS) except RuntimeError, e: raise assess_dcerpc_exception(message=str(e)) td.info['dc'] = unicode(result.pdc_dns_name) if creds is None: domval = DomainValidator(api) (ccache_name, principal) = domval.kinit_as_http(trustdomain) td.creds = credentials.Credentials() td.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) if ccache_name: with installutils.private_ccache(path=ccache_name): td.creds.guess(td.parm) td.creds.set_workstation(domain_validator.flatname) domains = communicate(td) else: td.creds = credentials.Credentials() td.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS) td.creds.guess(td.parm) td.creds.parse_string(creds) td.creds.set_workstation(domain_validator.flatname) domains = communicate(td) if domains is None: return None result = [] for t in domains.array: if ((t.trust_attributes & trust_attributes['NETR_TRUST_ATTRIBUTE_WITHIN_FOREST']) and (t.trust_flags & trust_flags['NETR_TRUST_FLAG_IN_FOREST'])): res = dict() res['cn'] = unicode(t.dns_name) res['ipantflatname'] = unicode(t.netbios_name) res['ipanttrusteddomainsid'] = unicode(t.sid) res['ipanttrustpartner'] = res['cn'] result.append(res) return result class TrustDomainJoins(object): def __init__(self, api): self.api = api self.local_domain = None self.remote_domain = None domain_validator = DomainValidator(api) self.configured = domain_validator.is_configured() if self.configured: self.local_flatname = domain_validator.flatname self.local_dn = domain_validator.dn self.__populate_local_domain() def __populate_local_domain(self): # Initialize local domain info using kerberos only ld = TrustDomainInstance(self.local_flatname) ld.creds = credentials.Credentials() ld.creds.set_kerberos_state(credentials.MUST_USE_KERBEROS) ld.creds.guess(ld.parm) ld.creds.set_workstation(ld.hostname) ld.retrieve(installutils.get_fqdn()) self.local_domain = ld def populate_remote_domain(self, realm, realm_server=None, realm_admin=None, realm_passwd=None): def get_instance(self): # Fetch data from foreign domain using password only rd = TrustDomainInstance('') rd.parm.set('workgroup', self.local_domain.info['name']) rd.creds = credentials.Credentials() rd.creds.set_kerberos_state(credentials.DONT_USE_KERBEROS) rd.creds.guess(rd.parm) return rd rd = get_instance(self) rd.creds.set_anonymous() rd.creds.set_workstation(self.local_domain.hostname) if realm_server is None: rd.retrieve_anonymously(realm, discover_srv=True) else: rd.retrieve_anonymously(realm_server, discover_srv=False) 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) td.creds.set_workstation(self.local_domain.hostname) if realm_server is None: # we must have rd.info['dns_hostname'] then, part of anonymous discovery td.retrieve(rd.info['dns_hostname']) else: td.retrieve(realm_server) td.read_only = False self.remote_domain = td return # Otherwise, use anonymously obtained data self.remote_domain = rd def get_realmdomains(self): """ Generate list of records for forest trust information about our realm domains. Note that the list generated currently includes only top level domains, no exclusion domains, and no TDO objects as we handle the latter in a separate way """ if self.local_domain.read_only: return self.local_domain.ftinfo_records = [] realm_domains = self.api.Command.realmdomains_show()['result'] # Use realmdomains' modification timestamp to judge records last update time (dn, entry_attrs) = self.api.Backend.ldap2.get_entry(realm_domains['dn'], ['modifyTimestamp']) # Convert the timestamp to Windows 64-bit timestamp format trust_timestamp = long(time.mktime(time.strptime(entry_attrs['modifytimestamp'][0][:14], "%Y%m%d%H%M%S"))*1e7+116444736000000000) for dom in realm_domains['associateddomain']: ftinfo = dict() ftinfo['rec_name'] = dom ftinfo['rec_time'] = trust_timestamp ftinfo['rec_type'] = lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME self.local_domain.ftinfo_records.append(ftinfo) def join_ad_full_credentials(self, realm, realm_server, realm_admin, realm_passwd): if not self.configured: return None if not(isinstance(self.remote_domain, TrustDomainInstance)): self.populate_remote_domain( realm, realm_server, realm_admin, realm_passwd ) if not self.remote_domain.read_only: trustdom_pass = samba.generate_random_password(128, 128) self.get_realmdomains() self.remote_domain.establish_trust(self.local_domain, trustdom_pass) self.local_domain.establish_trust(self.remote_domain, trustdom_pass) result = self.remote_domain.verify_trust(self.local_domain) return dict(local=self.local_domain, remote=self.remote_domain, verified=result) return None def join_ad_ipa_half(self, realm, realm_server, trustdom_passwd): if not self.configured: return None if not(isinstance(self.remote_domain, TrustDomainInstance)): self.populate_remote_domain(realm, realm_server, realm_passwd=None) self.local_domain.establish_trust(self.remote_domain, trustdom_passwd) return dict(local=self.local_domain, remote=self.remote_domain, verified=False) freeipa-3.3.4/ipaserver/plugins/0000775000175000017500000000000012271663206016170 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/plugins/__init__.py0000664000175000017500000000147212202434255020277 0ustar mkosekmkosek# Authors: Jason Gerard DeRose # # 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 . """ Sub-package containing all server plugins. """ freeipa-3.3.4/ipaserver/plugins/ldap2.py0000664000175000017500000004406712271663206017557 0ustar mkosekmkosek# Authors: # Pavel Zuna # John Dennis # # Copyright (C) 2009 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 . """ Backend plugin for LDAP. """ # Entries are represented as (dn, entry_attrs), where entry_attrs is a dict # mapping attribute names to values. Values can be a single value or list/tuple # of virtually any type. Each method passing these values to the python-ldap # binding encodes them into the appropriate representation. This applies to # everything except the CrudBackend methods, where dn is part of the entry dict. import os import re import pwd import krbV import ldap as _ldap from ipapython.dn import DN from ipapython.ipaldap import SASL_GSSAPI, IPASimpleLDAPObject, LDAPClient try: from ldap.controls.simple import GetEffectiveRightsControl #pylint: disable=F0401,E0611 except ImportError: """ python-ldap 2.4.x introduced a new API for effective rights control, which needs to be used or otherwise bind dn is not passed correctly. The following class is created for backward compatibility with python-ldap 2.3.x. Relevant BZ: https://bugzilla.redhat.com/show_bug.cgi?id=802675 """ from ldap.controls import LDAPControl class GetEffectiveRightsControl(LDAPControl): def __init__(self, criticality, authzId=None): LDAPControl.__init__(self, '1.3.6.1.4.1.42.2.27.9.5.2', criticality, authzId) from ipalib import api, errors from ipalib.crud import CrudBackend from ipalib.request import context class ldap2(LDAPClient, CrudBackend): """ LDAP Backend Take 2. """ def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None, schema=None): try: ldap_uri = ldap_uri or api.env.ldap_uri except AttributeError: ldap_uri = 'ldap://example.com' CrudBackend.__init__(self, shared_instance=shared_instance) LDAPClient.__init__(self, ldap_uri) try: if base_dn is not None: self.base_dn = DN(base_dn) else: self.base_dn = DN(api.env.basedn) except AttributeError: self.base_dn = DN() def _init_connection(self): # Connectible.conn is a proxy to thread-local storage; # do not set it pass def get_api(self): return api def __del__(self): if self.isconnected(): self.disconnect() def __str__(self): return self.ldap_uri def create_connection(self, ccache=None, bind_dn=None, bind_pw='', tls_cacertfile=None, tls_certfile=None, tls_keyfile=None, debug_level=0, autobind=False): """ Connect to LDAP server. Keyword arguments: ldapuri -- the LDAP server to connect to ccache -- Kerberos V5 ccache object or name bind_dn -- dn used to bind to the server bind_pw -- password used to bind to the server debug_level -- LDAP debug level option tls_cacertfile -- TLS CA certificate filename tls_certfile -- TLS certificate filename tls_keyfile - TLS bind key filename autobind - autobind as the current user Extends backend.Connectible.create_connection. """ if bind_dn is None: bind_dn = DN() assert isinstance(bind_dn, DN) if tls_cacertfile is not None: _ldap.set_option(_ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile) if tls_certfile is not None: _ldap.set_option(_ldap.OPT_X_TLS_CERTFILE, tls_certfile) if tls_keyfile is not None: _ldap.set_option(_ldap.OPT_X_TLS_KEYFILE, tls_keyfile) if debug_level: _ldap.set_option(_ldap.OPT_DEBUG_LEVEL, debug_level) with self.error_handler(): force_updates = api.env.context in ('installer', 'updates') conn = IPASimpleLDAPObject( self.ldap_uri, force_schema_updates=force_updates) if self.ldap_uri.startswith('ldapi://') and ccache: conn.set_option(_ldap.OPT_HOST_NAME, api.env.host) minssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MIN) maxssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MAX) # Always connect with at least an SSF of 56, confidentiality # This also protects us from a broken ldap.conf if minssf < 56: minssf = 56 conn.set_option(_ldap.OPT_X_SASL_SSF_MIN, minssf) if maxssf < minssf: conn.set_option(_ldap.OPT_X_SASL_SSF_MAX, minssf) if ccache is not None: if isinstance(ccache, krbV.CCache): principal = ccache.principal().name # Get a fully qualified CCACHE name (schema+name) # As we do not use the krbV.CCache object later, # we can safely overwrite it ccache = "%(type)s:%(name)s" % dict(type=ccache.type, name=ccache.name) else: principal = krbV.CCache(name=ccache, context=krbV.default_context()).principal().name os.environ['KRB5CCNAME'] = ccache conn.sasl_interactive_bind_s(None, SASL_GSSAPI) setattr(context, 'principal', principal) else: # no kerberos ccache, use simple bind or external sasl if autobind: pent = pwd.getpwuid(os.geteuid()) auth_tokens = _ldap.sasl.external(pent.pw_name) conn.sasl_interactive_bind_s(None, auth_tokens) else: conn.simple_bind_s(bind_dn, bind_pw) return conn def destroy_connection(self): """Disconnect from LDAP server.""" try: self.conn.unbind_s() except _ldap.LDAPError: # ignore when trying to unbind multiple times pass config_defaults = {'ipasearchtimelimit': [2], 'ipasearchrecordslimit': [0]} def get_ipa_config(self, attrs_list=None): """Returns the IPA configuration entry (dn, entry_attrs).""" dn = api.Object.config.get_dn() assert isinstance(dn, DN) try: config_entry = getattr(context, 'config_entry') if config_entry.conn is self.conn: return config_entry.clone() except AttributeError: # Not in our context yet pass try: (entry, truncated) = self.find_entries( None, attrs_list, base_dn=dn, scope=self.SCOPE_BASE, time_limit=2, size_limit=10 ) if truncated: raise errors.LimitsExceeded() config_entry = entry[0] except errors.NotFound: config_entry = self.make_entry(dn) for a in self.config_defaults: if a not in config_entry: config_entry[a] = self.config_defaults[a] context.config_entry = config_entry.clone() return config_entry def has_upg(self): """Returns True/False whether User-Private Groups are enabled. This is determined based on whether the UPG Template exists. """ upg_dn = DN(('cn', 'UPG Definition'), ('cn', 'Definitions'), ('cn', 'Managed Entries'), ('cn', 'etc'), api.env.basedn) try: upg_entry = self.conn.search_s(upg_dn, _ldap.SCOPE_BASE, attrlist=['*'])[0] disable_attr = '(objectclass=disable)' if 'originfilter' in upg_entry[1]: org_filter = upg_entry[1]['originfilter'] return not bool(re.search(r'%s' % disable_attr, org_filter[0])) else: return False except _ldap.NO_SUCH_OBJECT, e: return False def get_effective_rights(self, dn, entry_attrs): """Returns the rights the currently bound user has for the given DN. Returns 2 attributes, the attributeLevelRights for the given list of attributes and the entryLevelRights for the entry itself. """ assert isinstance(dn, DN) principal = getattr(context, 'principal') (binddn, attrs) = self.find_entry_by_attr("krbprincipalname", principal, "krbPrincipalAux", base_dn=api.env.basedn) assert isinstance(binddn, DN) sctrl = [GetEffectiveRightsControl(True, "dn: " + str(binddn))] self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, sctrl) (dn, attrs) = self.get_entry(dn, entry_attrs) # remove the control so subsequent operations don't include GER self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, []) return (dn, attrs) def can_write(self, dn, attr): """Returns True/False if the currently bound user has write permissions on the attribute. This only operates on a single attribute at a time. """ assert isinstance(dn, DN) (dn, attrs) = self.get_effective_rights(dn, [attr]) if 'attributelevelrights' in attrs: attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8') (attr, rights) = attr_rights.split(':') if 'w' in rights: return True return False def can_read(self, dn, attr): """Returns True/False if the currently bound user has read permissions on the attribute. This only operates on a single attribute at a time. """ assert isinstance(dn, DN) (dn, attrs) = self.get_effective_rights(dn, [attr]) if 'attributelevelrights' in attrs: attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8') (attr, rights) = attr_rights.split(':') if 'r' in rights: return True return False # # Entry-level effective rights # # a - Add # d - Delete # n - Rename the DN # v - View the entry # def can_delete(self, dn): """Returns True/False if the currently bound user has delete permissions on the entry. """ assert isinstance(dn, DN) (dn, attrs) = self.get_effective_rights(dn, ["*"]) if 'entrylevelrights' in attrs: entry_rights = attrs['entrylevelrights'][0].decode('UTF-8') if 'd' in entry_rights: return True return False def can_add(self, dn): """Returns True/False if the currently bound user has add permissions on the entry. """ assert isinstance(dn, DN) (dn, attrs) = self.get_effective_rights(dn, ["*"]) if 'entrylevelrights' in attrs: entry_rights = attrs['entrylevelrights'][0].decode('UTF-8') if 'a' in entry_rights: return True return False def modify_password(self, dn, new_pass, old_pass=''): """Set user password.""" assert isinstance(dn, DN) # The python-ldap passwd command doesn't verify the old password # so we'll do a simple bind to validate it. if old_pass != '': with self.error_handler(): conn = IPASimpleLDAPObject( self.ldap_uri, force_schema_updates=False) conn.simple_bind_s(dn, old_pass) conn.unbind_s() with self.error_handler(): self.conn.passwd_s(dn, old_pass, new_pass) def add_entry_to_group(self, dn, group_dn, member_attr='member', allow_same=False): """ Add entry designaed by dn to group group_dn in the member attribute member_attr. Adding a group as a member of itself is not allowed unless allow_same is True. """ assert isinstance(dn, DN) assert isinstance(group_dn, DN) self.log.debug( "add_entry_to_group: dn=%s group_dn=%s member_attr=%s", dn, group_dn, member_attr) # check if the entry exists entry = self.get_entry(dn, ['']) dn = entry.dn # check if we're not trying to add group into itself if dn == group_dn and not allow_same: raise errors.SameGroupError() # add dn to group entry's `member_attr` attribute modlist = [(_ldap.MOD_ADD, member_attr, [dn])] # update group entry try: with self.error_handler(): self.conn.modify_s(group_dn, modlist) except errors.DatabaseError: raise errors.AlreadyGroupMember() def remove_entry_from_group(self, dn, group_dn, member_attr='member'): """Remove entry from group.""" assert isinstance(dn, DN) assert isinstance(group_dn, DN) self.log.debug( "remove_entry_from_group: dn=%s group_dn=%s member_attr=%s", dn, group_dn, member_attr) # remove dn from group entry's `member_attr` attribute modlist = [(_ldap.MOD_DELETE, member_attr, [dn])] # update group entry try: with self.error_handler(): self.conn.modify_s(group_dn, modlist) except errors.MidairCollision: raise errors.NotGroupMember() def set_entry_active(self, dn, active): """Mark entry active/inactive.""" assert isinstance(dn, DN) assert isinstance(active, bool) # get the entry in question (dn, entry_attrs) = self.get_entry(dn, ['nsaccountlock']) # check nsAccountLock attribute account_lock_attr = entry_attrs.get('nsaccountlock', ['false']) account_lock_attr = account_lock_attr[0].lower() if active: if account_lock_attr == 'false': raise errors.AlreadyActive() else: if account_lock_attr == 'true': raise errors.AlreadyInactive() # LDAP expects string instead of Bool but it also requires it to be TRUE or FALSE, # not True or False as Python stringification does. Thus, we uppercase it. account_lock_attr = str(not active).upper() entry_attrs['nsaccountlock'] = account_lock_attr self.update_entry(dn, entry_attrs) def activate_entry(self, dn): """Mark entry active.""" assert isinstance(dn, DN) self.set_entry_active(dn, True) def deactivate_entry(self, dn): """Mark entry inactive.""" assert isinstance(dn, DN) self.set_entry_active(dn, False) def remove_principal_key(self, dn): """Remove a kerberos principal key.""" assert isinstance(dn, DN) # We need to do this directly using the LDAP library because we # don't have read access to krbprincipalkey so we need to delete # it in the blind. mod = [(_ldap.MOD_REPLACE, 'krbprincipalkey', None), (_ldap.MOD_REPLACE, 'krblastpwdchange', None)] with self.error_handler(): self.conn.modify_s(dn, mod) # CrudBackend methods def _get_normalized_entry_for_crud(self, dn, attrs_list=None): assert isinstance(dn, DN) (dn, entry_attrs) = self.get_entry(dn, attrs_list) return entry_attrs def create(self, **kw): """ Create a new entry and return it as one dict (DN included). Extends CrudBackend.create. """ assert 'dn' in kw dn = kw['dn'] assert isinstance(dn, DN) del kw['dn'] self.add_entry(dn, kw) return self._get_normalized_entry_for_crud(dn) def retrieve(self, primary_key, attributes): """ Get entry by primary_key (DN) as one dict (DN included). Extends CrudBackend.retrieve. """ return self._get_normalized_entry_for_crud(primary_key, attributes) def update(self, primary_key, **kw): """ Update entry's attributes and return it as one dict (DN included). Extends CrudBackend.update. """ self.update_entry(primary_key, kw) return self._get_normalized_entry_for_crud(primary_key) def delete(self, primary_key): """ Delete entry by primary_key (DN). Extends CrudBackend.delete. """ self.delete_entry(primary_key) def search(self, **kw): """ Return a list of entries (each entry is one dict, DN included) matching the specified criteria. Keyword arguments: filter -- search filter (default: '') attrs_list -- list of attributes to return, all if None (default None) base_dn -- dn of the entry at which to start the search (default '') scope -- search scope, see LDAP docs (default ldap2.SCOPE_SUBTREE) Extends CrudBackend.search. """ # get keyword arguments filter = kw.pop('filter', None) attrs_list = kw.pop('attrs_list', None) base_dn = kw.pop('base_dn', DN()) assert isinstance(base_dn, DN) scope = kw.pop('scope', self.SCOPE_SUBTREE) # generate filter filter_tmp = self.make_filter(kw) if filter: filter = self.combine_filters((filter, filter_tmp), self.MATCH_ALL) else: filter = filter_tmp if not filter: filter = '(objectClass=*)' # find entries and normalize the output for CRUD output = [] (entries, truncated) = self.find_entries( filter, attrs_list, base_dn, scope ) for (dn, entry_attrs) in entries: output.append(entry_attrs) if truncated: return (-1, output) return (len(output), output) api.register(ldap2) freeipa-3.3.4/ipaserver/plugins/join.py0000664000175000017500000001043612271663206017505 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2009 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 . """ Joining an IPA domain """ import krbV from ipalib import api from ipalib import Command, Str from ipalib import errors from ipalib import _ from ipaserver.install import installutils def get_realm(): """ Returns the default kerberos realm configured for this server. """ krbctx = krbV.default_context() return unicode(krbctx.default_realm) def validate_host(ugettext, cn): """ Require at least one dot in the hostname (to support localhost.localdomain) """ dots = len(cn.split('.')) if dots < 2: return 'Fully-qualified hostname required' return None class join(Command): """Join an IPA domain""" takes_args = ( Str('cn', validate_host, cli_name='hostname', doc=_("The hostname to register as"), default_from=lambda: unicode(installutils.get_fqdn()), autofill=True, #normalizer=lamda value: value.lower(), ), ) takes_options = ( Str('realm', doc=_("The IPA realm"), default_from=lambda: get_realm(), autofill=True, ), Str('nshardwareplatform?', cli_name='platform', doc=_('Hardware platform of the host (e.g. Lenovo T61)'), ), Str('nsosversion?', cli_name='os', doc=_('Operating System and version of the host (e.g. Fedora 9)'), ), ) has_output = tuple() use_output_validation = False def execute(self, hostname, **kw): """ Execute the machine join operation. Returns the entry as it will be created in LDAP. :param hostname: The name of the host joined :param kw: Keyword arguments for the other attributes. """ assert 'cn' not in kw ldap = self.api.Backend.ldap2 try: # First see if the host exists kw = {'fqdn': hostname, 'all': True} attrs_list = api.Command['host_show'](**kw)['result'] dn = attrs_list['dn'] # No error raised so far means that host entry exists self.log.info('Host entry for %s already exists, ' 'joining may fail on the client side ' 'if not forced', hostname) # If no principal name is set yet we need to try to add # one. if 'krbprincipalname' not in attrs_list: service = "host/%s@%s" % (hostname, api.env.realm) api.Command['host_mod'](hostname, krbprincipalname=service) self.log.info('No principal set, setting to %s', service) # It exists, can we write the password attributes? allowed = ldap.can_write(dn, 'krblastpwdchange') if not allowed: raise errors.ACIError(info=_("Insufficient 'write' privilege " "to the 'krbLastPwdChange' attribute of entry '%s'.") % dn) # Reload the attrs_list and dn so that we return update values kw = {'fqdn': hostname, 'all': True} attrs_list = api.Command['host_show'](**kw)['result'] dn = attrs_list['dn'] except errors.NotFound: attrs_list = api.Command['host_add'](hostname, force=True)['result'] dn = attrs_list['dn'] config = api.Command['config_show']()['result'] attrs_list['ipacertificatesubjectbase'] =\ config['ipacertificatesubjectbase'] return (dn, attrs_list) api.register(join) freeipa-3.3.4/ipaserver/plugins/xmlserver.py0000664000175000017500000000253212202434255020565 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # Rob Crittenden # # 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 . """ Loads WSGI server plugins. """ from ipalib import api if 'in_server' in api.env and api.env.in_server is True: from ipaserver.rpcserver import wsgi_dispatch, xmlserver, jsonserver_kerb, jsonserver_session, login_kerberos, login_password, change_password, xmlserver_session api.register(wsgi_dispatch) api.register(xmlserver) api.register(jsonserver_kerb) api.register(jsonserver_session) api.register(login_kerberos) api.register(login_password) api.register(change_password) api.register(xmlserver_session) freeipa-3.3.4/ipaserver/plugins/rabase.py0000664000175000017500000000771112271663206020005 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2009 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 . """ Backend plugin for RA activities. The `ra` plugin provides access to the CA to issue, retrieve, and revoke certificates via the following methods: * `ra.check_request_status()` - check certificate request status. * `ra.get_certificate()` - retrieve an existing certificate. * `ra.request_certificate()` - request a new certificate. * `ra.revoke_certificate()` - revoke a certificate. * `ra.take_certificate_off_hold()` - take a certificate off hold. """ from ipalib import api from ipalib import Backend from ipalib import errors from ipaserver.install import certs import os class rabase(Backend): """ Request Authority backend plugin. """ def __init__(self): if api.env.in_tree: self.sec_dir = api.env.dot_ipa + os.sep + 'alias' self.pwd_file = self.sec_dir + os.sep + '.pwd' else: self.sec_dir = "/etc/httpd/alias" self.pwd_file = "/etc/httpd/alias/pwdfile.txt" super(rabase, self).__init__() def check_request_status(self, request_id): """ Check status of a certificate signing request. :param request_id: request ID """ raise errors.NotImplementedError(name='%s.check_request_status' % self.name) def get_certificate(self, serial_number=None): """ Retrieve an existing certificate. :param serial_number: certificate serial number """ raise errors.NotImplementedError(name='%s.get_certificate' % self.name) def request_certificate(self, csr, request_type='pkcs10'): """ Submit certificate signing request. :param csr: The certificate signing request. :param request_type: The request type (defaults to ``'pkcs10'``). """ raise errors.NotImplementedError(name='%s.request_certificate' % self.name) def revoke_certificate(self, serial_number, revocation_reason=0): """ Revoke a certificate. The integer ``revocation_reason`` code must have one of these values: * ``0`` - unspecified * ``1`` - keyCompromise * ``2`` - cACompromise * ``3`` - affiliationChanged * ``4`` - superseded * ``5`` - cessationOfOperation * ``6`` - certificateHold * ``8`` - removeFromCRL * ``9`` - privilegeWithdrawn * ``10`` - aACompromise Note that reason code ``7`` is not used. See RFC 5280 for more details: http://www.ietf.org/rfc/rfc5280.txt :param serial_number: Certificate serial number. :param revocation_reason: Integer code of revocation reason. """ raise errors.NotImplementedError(name='%s.revoke_certificate' % self.name) def take_certificate_off_hold(self, serial_number): """ Take revoked certificate off hold. :param serial_number: Certificate serial number. """ raise errors.NotImplementedError(name='%s.take_certificate_off_hold' % self.name) def find(self, options): """ Search for certificates :param options: dictionary of search options """ raise errors.NotImplementedError(name='%s.find' % self.name) freeipa-3.3.4/ipaserver/plugins/dogtag.py0000664000175000017500000024200112271663206020006 0ustar mkosekmkosek# Authors: # Andrew Wnuk # Jason Gerard DeRose # Rob Crittenden # John Dennis # # Copyright (C) 2009 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 . ''' ============================================== Backend plugin for RA using Dogtag (e.g. CMS) ============================================== Overview of interacting with CMS: --------------------------------- CMS stands for "Certificate Management System". It has been released under a variety of names, the open source version is called "dogtag". CMS consists of a number of servlets which in rough terms can be thought of as RPC commands. A servlet is invoked by making an HTTP request to a specific URL and passing URL arguments. Normally CMS responds with an HTTP reponse consisting of HTML to be rendered by a web browser. This HTTP HTML response has both Javascript SCRIPT components and HTML rendering code. One of the Javascript SCRIPT blocks holds the data for the result. The rest of the response is derived from templates associated with the servlet which may be customized. The templates pull the result data from Javascript variables. One way to get the result data is to parse the HTML looking for the Javascript varible initializations. Simple string searchs are not a robust method. First of all one must be sure the string is only found in a Javascript SCRIPT block and not somewhere else in the HTML document. Some of the Javascript variable initializations are rather complex (e.g. lists of structures). It would be hard to correctly parse such complex and diverse Javascript. Existing Javascript parsers are not generally available. Finally, it's important to know the character encoding for strings. There is a somewhat complex set of precident rules for determining the current character encoding from the HTTP header, meta-equiv tags, mime Content-Type and charset attributes on HTML elements. All of this means trying to read the result data from a CMS HTML response is difficult to do robustly. However, CMS also supports returning the result data as a XML document (distinct from an XHTML document which would be essentially the same as described above). There are a wide variety of tools to robustly parse XML. Because XML is so well defined things like escapes, character encodings, etc. are automatically handled by the tools. Thus we never try to parse Javascript, instead we always ask CMS to return us an XML document by passing the URL argument xml="true". The body of the HTTP response is an XML document rather than HTML with embedded Javascript. To parse the XML documents we use the Python lxml package which is a Python binding around the libxml2 implementation. libxml2 is a very fast, standard compliant, feature full XML implementation. libxml2 is the XML library of choice for many projects. One of the features in lxml and libxml2 that is particularly valuable to us is the XPath implementation. We make heavy use of XPath to find data in the XML documents we're parsing. Parse Results vs. IPA command results: -------------------------------------- CMS results can be parsed from either HTML or XML. CMS unfortunately is not consistent with how it names items or how it utilizes data types. IPA has strict rules about data types. Also IPA would like to see a more consistent view CMS data. Therefore we split the task of parsing CMS results out from the IPA command code. The parse functions normalize the result data by using a consistent set of names and data types. The IPA command only deals with the normalized parse results. This also allow us to use different parsers if need be (i.e. if we had to parse Javascript for some reason). The parse functions attempt to parse as must information from the CMS result as is possible. It puts the parse result into a dict whose normalized key/value pairs are easy to access. IPA commands do not need to return all the parsed results, it can pick and choose what it wants to return in the IPA command result from the parse result. It also rest assured the values in the parse result will be the correct data type. Thus the general sequence of steps for an IPA command talking to CMS are: #. Receive IPA arguments from IPA command #. Formulate URL with arguments for CMS #. Make request to CMS server #. Extract XML document from HTML body returned by CMS #. Parse XML document using matching parse routine which returns response dict #. Extract relevant items from parse result and insert into command result #. Return command result Serial Numbers: --------------- Serial numbers are integral values of any magnitude because they are based on ASN.1 integers. CMS uses the Java BigInteger to represent these. Fortunately Python also has support for big integers via the Python long() object. Any BigIntegers we receive from CMS as a string can be parsed into a Python long without loss of information. However Python has a neat trick. It normally represents integers via the int object which internally uses the native C long type. If you create an int object by passing the int constructor a string it will check the magnitude of the value. If it would fit in a C long then it returns you an int object. However if the value is too big for a C long type then it returns you a Python long object instead. This is a very nice property because it's much more efficient to use C long types when possible (e.g. Python int), but when necessary you'll get a Python long() object to handle large magnitude values. Python also nicely handles type promotion transparently between int and long objects. For example if you multiply two int objects you may get back a long object if necessary. In general Python int and long objects may be freely mixed without the programmer needing to be aware of which type of intergral object is being operated on. The leads to the following rule, always parse a string representing an integral value using the int() constructor even if it might have large magnitude because Python will return either an int or a long automatically. By the same token don't test for type of an object being int exclusively because it could either be an int or a long object. Internally we should always being using int or long object to hold integral values. This is because we should be able to compare them correctly, be free from concerns about having the know the radix of the string, perform arithmetic operations, and convert to string representation (with correct radix) when necessary. In other words internally we should never handle integral values as strings. However, the XMLRPC transport cannot properly handle a Python long object. The XMLRPC encoder upon seeing a Python long will test to see if the value fits within the range of an 32-bit integer, if so it passes the integer parameter otherwise it raises an Overflow exception. The XMLRPC specification does permit 64-bit integers (e.g. i8) and the Python XMLRPC module could allow long values within the 64-bit range to be passed if it were patched, however this only moves the problem, it does not solve passing big integers through XMLRPC. Thus we must always pass big integers as a strings through the XMLRPC interface. But upon receiving that value from XMLRPC we should convert it back into an int or long object. Recall also that Python will automatically perform a conversion to string if you output the int or long object in a string context. Radix Issues: ------------- CMS uses the following conventions: Serial numbers are always returned as hexadecimal strings without a radix prefix. When CMS takes a serial number as input it accepts the value in either decimal or hexadecimal utilizing the radix prefix (e.g. 0x) to determine how to parse the value. IPA has adopted the convention that all integral values in the user interface will use base 10 decimal radix. Basic rules on handling these values 1. Reading a serial number from CMS requires conversion from hexadecimal by converting it into a Python int or long object, use the int constructor: >>> serial_number = int(serial_number, 16) 2. Big integers passed to XMLRPC must be decimal unicode strings >>> unicode(serial_number) 3. Big integers received from XMLRPC must be converted back to int or long objects from the decimal string representation. >>> serial_number = int(serial_number) Xpath pattern matching on node names: ------------------------------------- There are many excellent tutorial on how to use xpath to find items in an XML document, as such there is no need to repeat this information here. However, most xpath tutorials make the assumption the node names you're searching for are fixed. For example: doc.xpath('//book/chapter[*]/section[2]') Selects the second section of every chapter of the book. In this example the node names 'book', 'chapter', 'section' are fixed. But what if the XML document embedded the chapter number in the node name, for example 'chapter1', 'chapter2', etc.? (If you're thinking this would be incredibly lame, you're right, but sadly people do things like this). Thus in this case you can't use the node name 'chapter' in the xpath location step because it's not fixed and hence won't match 'chapter1', 'chapter2', etc. The solution to this seems obvious, use some type of pattern matching on the node name. Unfortunately this advanced use of xpath is seldom discussed in tutorials and it's not obvious how to do it. Here are some hints. Use the built-in xpath string functions. Most of the examples illustrate the string function being passed the text *contents* of the node via '.' or string(.). However we don't want to pass the contents of the node, instead we want to pass the node name. To do this use the name() function. One way we could solve the chapter problem above is by using a predicate which says if the node name begins with 'chapter' it's a match. Here is how you can do that. >>> doc.xpath("//book/*[starts-with(name(), 'chapter')]/section[2]") The built-in starts-with() returns true if its first argument starts with its second argument. Thus the example above says if the node name of the second location step begins with 'chapter' consider it a match and the search proceeds to the next location step, which in this example is any node named 'section'. But what if we would like to utilize the power of regular expressions to perform the test against the node name? In this case we can use the EXSLT regular expression extension. EXSLT extensions are accessed by using XML namespaces. The regular expression name space identifier is 're:' In lxml we need to pass a set of namespaces to XPath object constructor in order to allow it to bind to those namespaces during its evaluation. Then we just use the EXSLT regular expression match() function on the node name. Here is how this is done: >>> regexpNS = "http://exslt.org/regular-expressions" >>> find = etree.XPath("//book/*[re:match(name(), '^chapter(_\d+)$')]/section[2]", ... namespaces={'re':regexpNS} >>> find(doc) What is happening here is that etree.XPath() has returned us an evaluator function which we bind to the name 'find'. We've passed it a set of namespaces as a dict via the 'namespaces' keyword parameter of etree.XPath(). The predicate for the second location step uses the 're:' namespace to find the function name 'match'. The re:match() takes a string to search as its first argument and a regular expression pattern as its second argument. In this example the string to seach is the node name of the location step because we called the built-in node() function of XPath. The regular expression pattern we've passed says it's a match if the string begins with 'chapter' is followed by any number of digits and nothing else follows. ''' from lxml import etree import urllib2 import datetime import time from ipapython.dn import DN import ipapython.dogtag from ipapython import ipautil # These are general status return values used when # CMSServlet.outputError() is invoked. CMS_SUCCESS = 0 CMS_FAILURE = 1 CMS_AUTH_FAILURE = 2 # CMS (Certificate Management System) status return values # These are requestStatus return values used with templates CMS_STATUS_UNAUTHORIZED = 1 CMS_STATUS_SUCCESS = 2 CMS_STATUS_PENDING = 3 CMS_STATUS_SVC_PENDING = 4 CMS_STATUS_REJECTED = 5 CMS_STATUS_ERROR = 6 CMS_STATUS_EXCEPTION = 7 def cms_request_status_to_string(request_status): ''' :param request_status: The integral request status value :return: String name of request status ''' return { 1 : 'UNAUTHORIZED', 2 : 'SUCCESS', 3 : 'PENDING', 4 : 'SVC_PENDING', 5 : 'REJECTED', 6 : 'ERROR', 7 : 'EXCEPTION', }.get(request_status, "unknown(%d)" % request_status) def cms_error_code_to_string(error_code): ''' :param error_code: The integral error code value :return: String name of the error code ''' return { 0 : 'SUCCESS', 1 : 'FAILURE', 2 : 'AUTH_FAILURE', }.get(error_code, "unknown(%d)" % error_code) def parse_and_set_boolean_xml(node, response, response_name): ''' :param node: xml node object containing value to parse for boolean result :param response: response dict to set boolean result in :param response_name: name of the respone value to set :except ValueError: Read the value out of a xml text node and interpret it as a boolean value. The text values are stripped of whitespace and converted to lower case prior to interpretation. If the value is recognized the response dict is updated using the request_name as the key and the value is set to the bool value of either True or False depending on the interpretation of the text value. If the text value is not recognized a ValueError exception is thrown. Text values which result in True: - true - yes - on Text values which result in False: - false - no - off ''' value = node.text.strip().lower() if value == 'true' or value == 'yes': value = True elif value == 'false' or value == 'no': value = False else: raise ValueError('expected true|false|yes|no|on|off for "%s", but got "%s"' % \ (response_name, value)) response[response_name] = value def get_error_code_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: error code as an integer or None if not found Returns the error code when the servlet replied with CMSServlet.outputError() The possible error code values are: - CMS_SUCCESS = 0 - CMS_FAILURE = 1 - CMS_AUTH_FAILURE = 2 However, profileSubmit sometimes also returns these values: - EXCEPTION = 1 - DEFERRED = 2 - REJECTED = 3 ''' error_code = doc.xpath('//XMLResponse/Status[1]') if len(error_code) == 1: error_code = int(error_code[0].text) else: # If error code wasn't present, but error string was # then it's an error. error_string = doc.xpath('//XMLResponse/Error[1]') if len(error_string) == 1: error_code = CMS_FAILURE else: # no status and no error string, assume success error_code = CMS_SUCCESS return error_code def get_request_status_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: request status as an integer Returns the request status from a CMS operation. May be one of: - CMS_STATUS_UNAUTHORIZED = 1 - CMS_STATUS_SUCCESS = 2 - CMS_STATUS_PENDING = 3 - CMS_STATUS_SVC_PENDING = 4 - CMS_STATUS_REJECTED = 5 - CMS_STATUS_ERROR = 6 - CMS_STATUS_EXCEPTION = 7 CMS will often fail to return requestStatus when the status is SUCCESS. Therefore if we fail to find a requestStatus field we default the result to CMS_STATUS_SUCCESS. ''' request_status = doc.xpath('//xml/fixed/requestStatus[1]') if len(request_status) == 1: request_status = int(request_status[0].text) else: # When a request is successful CMS often omits the requestStatus request_status = CMS_STATUS_SUCCESS # However, if an error string was returned it's an error no # matter what CMS returned as requestStatus. # Just to make life interesting CMS sometimes returns an empty error string # when nothing wrong occurred. error_detail = doc.xpath('//xml/fixed/errorDetails[1]') if len(error_detail) == 1 and len(error_detail[0].text.strip()) > 0: # There was a non-empty error string, if the status was something # other than error or exception then force it to be an error. if not (request_status in (CMS_STATUS_ERROR, CMS_STATUS_EXCEPTION)): request_status = CMS_STATUS_ERROR return request_status def parse_error_template_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict CMS currently returns errors via XML as either a "template" document (generated by CMSServlet.outputXML() or a "response" document (generated by CMSServlet.outputError()). This routine is used to parse a "template" style error or exception document. This routine should be use when the CMS requestStatus is ERROR or EXCEPTION. It is capable of parsing both. A CMS ERROR occurs when a known anticipated error condition occurs (e.g. asking for an item which does not exist). A CMS EXCEPTION occurs when an exception is thrown in the CMS server and it's not caught and converted into an ERROR. Think of EXCEPTIONS as the "catch all" error situation. ERROR's and EXCEPTIONS's both have error message strings associated with them. For an ERROR it's errorDetails, for an EXCEPTION it's unexpectedError. In addition an EXCEPTION may include an array of additional error strings in it's errorDescription field. After parsing the results are returned in a result dict. The following table illustrates the mapping from the CMS data item to what may be found in the result dict. If a CMS data item is absent it will also be absent in the result dict. +----------------+---------------+------------------+---------------+ |cms name |cms type |result name |result type | +================+===============+==================+===============+ |requestStatus |int |request_status |int | +----------------+---------------+------------------+---------------+ |errorDetails |string |error_string [1]_ |unicode | +----------------+---------------+------------------+---------------+ |unexpectedError |string |error_string [1]_ |unicode | +----------------+---------------+------------------+---------------+ |errorDescription|[string] |error_descriptions|[unicode] | +----------------+---------------+------------------+---------------+ |authority |string |authority |unicode | +----------------+---------------+------------------+---------------+ .. [1] errorDetails is the error message string when the requestStatus is ERROR. unexpectedError is the error message string when the requestStatus is EXCEPTION. This routine recognizes both ERROR's and EXCEPTION's and depending on which is found folds the error message into the error_string result value. ''' response = {} response['request_status'] = CMS_STATUS_ERROR # assume error request_status = doc.xpath('//xml/fixed/requestStatus[1]') if len(request_status) == 1: request_status = int(request_status[0].text) response['request_status'] = request_status error_descriptions = [] for description in doc.xpath('//xml/records[*]/record/errorDescription'): error_descriptions.append(etree.tostring(description, method='text', encoding=unicode).strip()) if len(error_descriptions) > 0: response['error_descriptions'] = error_descriptions authority = doc.xpath('//xml/fixed/authorityName[1]') if len(authority) == 1: authority = etree.tostring(authority[0], method='text', encoding=unicode).strip() response['authority'] = authority # Should never get both errorDetail and unexpectedError error_detail = doc.xpath('//xml/fixed/errorDetails[1]') if len(error_detail) == 1: error_detail = etree.tostring(error_detail[0], method='text', encoding=unicode).strip() response['error_string'] = error_detail unexpected_error = doc.xpath('//xml/fixed/unexpectedError[1]') if len(unexpected_error) == 1: unexpected_error = etree.tostring(unexpected_error[0], method='text', encoding=unicode).strip() response['error_string'] = unexpected_error return response def parse_error_response_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict CMS currently returns errors via XML as either a "template" document (generated by CMSServlet.outputXML() or a "response" document (generated by CMSServlet.outputError()). This routine is used to parse a "response" style error document. +---------------+---------------+---------------+---------------+ |cms name |cms type |result name |result type | +===============+===============+===============+===============+ |Status |int |error_code |int [1]_ | +---------------+---------------+---------------+---------------+ |Error |string |error_string |unicode | +---------------+---------------+---------------+---------------+ |RequestID |string |request_id |string | +---------------+---------------+---------------+---------------+ .. [1] error code may be one of: - CMS_SUCCESS = 0 - CMS_FAILURE = 1 - CMS_AUTH_FAILURE = 2 However, profileSubmit sometimes also returns these values: - EXCEPTION = 1 - DEFERRED = 2 - REJECTED = 3 ''' response = {} response['error_code'] = CMS_FAILURE # assume error error_code = doc.xpath('//XMLResponse/Status[1]') if len(error_code) == 1: error_code = int(error_code[0].text) response['error_code'] = error_code error_string = doc.xpath('//XMLResponse/Error[1]') if len(error_string) == 1: error_string = etree.tostring(error_string[0], method='text', encoding=unicode).strip() response['error_string'] = error_string request_id = doc.xpath('//XMLResponse/RequestId[1]') if len(request_id) == 1: request_id = etree.tostring(request_id[0], method='text', encoding=unicode).strip() response['request_id'] = request_id return response def parse_profile_submit_result_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict :except ValueError: CMS returns an error code and an array of request records. This function returns a response dict with the following format: {'error_code' : int, 'requests' : [{}]} The mapping of fields and data types is illustrated in the following table. If the error_code is not SUCCESS then the response dict will have the contents described in `parse_error_response_xml`. +--------------------+----------------+------------------------+---------------+ |cms name |cms type |result name |result type | +====================+================+========================+===============+ |Status |int |error_code |int | +--------------------+----------------+------------------------+---------------+ |Requests[].Id |string |requests[].request_id |unicode | +--------------------+----------------+------------------------+---------------+ |Requests[].SubjectDN|string |requests[].subject |unicode | +--------------------+----------------+------------------------+---------------+ |Requests[].serialno |BigInteger |requests[].serial_number|int|long | +--------------------+----------------+------------------------+---------------+ |Requests[].b64 |string |requests[].certificate |unicode [1]_ | +--------------------+----------------+------------------------+---------------+ |Requests[].pkcs7 |string | | | +--------------------+----------------+------------------------+---------------+ .. [1] Base64 encoded ''' error_code = get_error_code_xml(doc) if error_code != CMS_SUCCESS: response = parse_error_response_xml(doc) return response response = {} response['error_code'] = error_code requests = [] response['requests'] = requests for request in doc.xpath('//XMLResponse/Requests[*]/Request'): response_request = {} requests.append(response_request) request_id = request.xpath('Id[1]') if len(request_id) == 1: request_id = etree.tostring(request_id[0], method='text', encoding=unicode).strip() response_request['request_id'] = request_id subject_dn = request.xpath('SubjectDN[1]') if len(subject_dn) == 1: subject_dn = etree.tostring(subject_dn[0], method='text', encoding=unicode).strip() response_request['subject'] = subject_dn serial_number = request.xpath('serialno[1]') if len(serial_number) == 1: serial_number = int(serial_number[0].text, 16) # parse as hex response_request['serial_number'] = serial_number response['serial_number_hex'] = u'0x%X' % serial_number certificate = request.xpath('b64[1]') if len(certificate) == 1: certificate = etree.tostring(certificate[0], method='text', encoding=unicode).strip() response_request['certificate'] = certificate return response def parse_check_request_result_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict :except ValueError: After parsing the results are returned in a result dict. The following table illustrates the mapping from the CMS data item to what may be found in the result dict. If a CMS data item is absent it will also be absent in the result dict. If the requestStatus is not SUCCESS then the response dict will have the contents described in `parse_error_template_xml`. +-------------------------+---------------+-------------------+-----------------+ |cms name |cms type |result name |result type | +=========================+===============+===================+=================+ |authority |string |authority |unicode | +-------------------------+---------------+-------------------+-----------------+ |requestId |string |request_id |string | +-------------------------+---------------+-------------------+-----------------+ |staus |string |cert_request_status|unicode [1]_ | +-------------------------+---------------+-------------------+-----------------+ |createdOn |long, timestamp|created_on |datetime.datetime| +-------------------------+---------------+-------------------+-----------------+ |updatedOn |long, timestamp|updated_on |datetime.datetime| +-------------------------+---------------+-------------------+-----------------+ |requestNotes |string |request_notes |unicode | +-------------------------+---------------+-------------------+-----------------+ |pkcs7ChainBase64 |string |pkcs7_chain |unicode [2]_ | +-------------------------+---------------+-------------------+-----------------+ |cmcFullEnrollmentResponse|string |full_response |unicode [2]_ | +-------------------------+---------------+-------------------+-----------------+ |records[].serialNumber |BigInteger |serial_numbers |[int|long] | +-------------------------+---------------+-------------------+-----------------+ .. [1] cert_request_status may be one of: - "begin" - "pending" - "approved" - "svc_pending" - "canceled" - "rejected" - "complete" .. [2] Base64 encoded ''' request_status = get_request_status_xml(doc) if request_status != CMS_STATUS_SUCCESS: response = parse_error_template_xml(doc) return response response = {} response['request_status'] = request_status cert_request_status = doc.xpath('//xml/header/status[1]') if len(cert_request_status) == 1: cert_request_status = etree.tostring(cert_request_status[0], method='text', encoding=unicode).strip() response['cert_request_status'] = cert_request_status request_id = doc.xpath('//xml/header/requestId[1]') if len(request_id) == 1: request_id = etree.tostring(request_id[0], method='text', encoding=unicode).strip() response['request_id'] = request_id authority = doc.xpath('//xml/header/authority[1]') if len(authority) == 1: authority = etree.tostring(authority[0], method='text', encoding=unicode).strip() response['authority'] = authority updated_on = doc.xpath('//xml/header/updatedOn[1]') if len(updated_on) == 1: updated_on = datetime.datetime.utcfromtimestamp(int(updated_on[0].text)) response['updated_on'] = updated_on created_on = doc.xpath('//xml/header/createdOn[1]') if len(created_on) == 1: created_on = datetime.datetime.utcfromtimestamp(int(created_on[0].text)) response['created_on'] = created_on request_notes = doc.xpath('//xml/header/requestNotes[1]') if len(request_notes) == 1: request_notes = etree.tostring(request_notes[0], method='text', encoding=unicode).strip() response['request_notes'] = request_notes pkcs7_chain = doc.xpath('//xml/header/pkcs7ChainBase64[1]') if len(pkcs7_chain) == 1: pkcs7_chain = etree.tostring(pkcs7_chain[0], method='text', encoding=unicode).strip() response['pkcs7_chain'] = pkcs7_chain full_response = doc.xpath('//xml/header/cmcFullEnrollmentResponse[1]') if len(full_response) == 1: full_response = etree.tostring(full_response[0], method='text', encoding=unicode).strip() response['full_response'] = full_response serial_numbers = [] response['serial_numbers'] = serial_numbers for serial_number in doc.xpath('//xml/records[*]/record/serialNumber'): serial_number = int(serial_number.text, 16) # parse as hex serial_numbers.append(serial_number) return response def parse_display_cert_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict :except ValueError: After parsing the results are returned in a result dict. The following table illustrates the mapping from the CMS data item to what may be found in the result dict. If a CMS data item is absent it will also be absent in the result dict. If the requestStatus is not SUCCESS then the response dict will have the contents described in `parse_error_template_xml`. +----------------+---------------+-----------------+---------------+ |cms name |cms type |result name |result type | +================+===============+=================+===============+ |emailCert |Boolean |email_cert |bool | +----------------+---------------+-----------------+---------------+ |noCertImport |Boolean |no_cert_import |bool | +----------------+---------------+-----------------+---------------+ |revocationReason|int |revocation_reason|int [1]_ | +----------------+---------------+-----------------+---------------+ |certPrettyPrint |string |cert_pretty |unicode | +----------------+---------------+-----------------+---------------+ |authorityid |string |authority |unicode | +----------------+---------------+-----------------+---------------+ |certFingerprint |string |fingerprint |unicode | +----------------+---------------+-----------------+---------------+ |certChainBase64 |string |certificate |unicode [2]_ | +----------------+---------------+-----------------+---------------+ |serialNumber |string |serial_number |int|long | +----------------+---------------+-----------------+---------------+ |pkcs7ChainBase64|string |pkcs7_chain |unicode [2]_ | +----------------+---------------+-----------------+---------------+ .. [1] revocation reason may be one of: - 0 = UNSPECIFIED - 1 = KEY_COMPROMISE - 2 = CA_COMPROMISE - 3 = AFFILIATION_CHANGED - 4 = SUPERSEDED - 5 = CESSATION_OF_OPERATION - 6 = CERTIFICATE_HOLD - 8 = REMOVE_FROM_CRL - 9 = PRIVILEGE_WITHDRAWN - 10 = AA_COMPROMISE .. [2] Base64 encoded ''' request_status = get_request_status_xml(doc) if request_status != CMS_STATUS_SUCCESS: response = parse_error_template_xml(doc) return response response = {} response['request_status'] = request_status email_cert = doc.xpath('//xml/header/emailCert[1]') if len(email_cert) == 1: parse_and_set_boolean_xml(email_cert[0], response, 'email_cert') no_cert_import = doc.xpath('//xml/header/noCertImport[1]') if len(no_cert_import) == 1: parse_and_set_boolean_xml(no_cert_import[0], response, 'no_cert_import') revocation_reason = doc.xpath('//xml/header/revocationReason[1]') if len(revocation_reason) == 1: revocation_reason = int(revocation_reason[0].text) response['revocation_reason'] = revocation_reason cert_pretty = doc.xpath('//xml/header/certPrettyPrint[1]') if len(cert_pretty) == 1: cert_pretty = etree.tostring(cert_pretty[0], method='text', encoding=unicode).strip() response['cert_pretty'] = cert_pretty authority = doc.xpath('//xml/header/authorityid[1]') if len(authority) == 1: authority = etree.tostring(authority[0], method='text', encoding=unicode).strip() response['authority'] = authority fingerprint = doc.xpath('//xml/header/certFingerprint[1]') if len(fingerprint) == 1: fingerprint = etree.tostring(fingerprint[0], method='text', encoding=unicode).strip() response['fingerprint'] = fingerprint certificate = doc.xpath('//xml/header/certChainBase64[1]') if len(certificate) == 1: certificate = etree.tostring(certificate[0], method='text', encoding=unicode).strip() response['certificate'] = certificate serial_number = doc.xpath('//xml/header/serialNumber[1]') if len(serial_number) == 1: serial_number = int(serial_number[0].text, 16) # parse as hex response['serial_number'] = serial_number response['serial_number_hex'] = u'0x%X' % serial_number pkcs7_chain = doc.xpath('//xml/header/pkcs7ChainBase64[1]') if len(pkcs7_chain) == 1: pkcs7_chain = etree.tostring(pkcs7_chain[0], method='text', encoding=unicode).strip() response['pkcs7_chain'] = pkcs7_chain return response def parse_revoke_cert_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict :except ValueError: After parsing the results are returned in a result dict. The following table illustrates the mapping from the CMS data item to what may be found in the result dict. If a CMS data item is absent it will also be absent in the result dict. If the requestStatus is not SUCCESS then the response dict will have the contents described in `parse_error_template_xml`. +----------------------+----------------+-----------------------+---------------+ |cms name |cms type |result name |result type | +======================+================+=======================+===============+ |dirEnabled |string [1]_ |dir_enabled |bool | +----------------------+----------------+-----------------------+---------------+ |certsUpdated |int |certs_updated |int | +----------------------+----------------+-----------------------+---------------+ |certsToUpdate |int |certs_to_update |int | +----------------------+----------------+-----------------------+---------------+ |error |string [2]_ |error_string |unicode | +----------------------+----------------+-----------------------+---------------+ |revoked |string [3]_ |revoked |unicode | +----------------------+----------------+-----------------------+---------------+ |totalRecordCount |int |total_record_count |int | +----------------------+----------------+-----------------------+---------------+ |updateCRL |string [1]_ [4]_|update_crl |bool | +----------------------+----------------+-----------------------+---------------+ |updateCRLSuccess |string [1]_ [4]_|update_crl_success |bool | +----------------------+----------------+-----------------------+---------------+ |updateCRLError |string [4]_ |update_crl_error |unicode | +----------------------+----------------+-----------------------+---------------+ |publishCRLSuccess |string [1]_[4]_ |publish_crl_success |bool | +----------------------+----------------+-----------------------+---------------+ |publishCRLError |string [4]_ |publish_crl_error |unicode | +----------------------+----------------+-----------------------+---------------+ |crlUpdateStatus |string [1]_ [5]_|crl_update_status |bool | +----------------------+----------------+-----------------------+---------------+ |crlUpdateError |string [5]_ |crl_update_error |unicode | +----------------------+----------------+-----------------------+---------------+ |crlPublishStatus |string [1]_ [5]_|crl_publish_status |bool | +----------------------+----------------+-----------------------+---------------+ |crlPublishError |string [5]_ |crl_publish_error |unicode | +----------------------+----------------+-----------------------+---------------+ |records[].serialNumber|BigInteger |records[].serial_number|int|long | +----------------------+----------------+-----------------------+---------------+ |records[].error |string [2]_ |records[].error_string |unicode | +----------------------+----------------+-----------------------+---------------+ .. [1] String value is either "yes" or "no" .. [2] Sometimes the error string is empty (null) .. [3] revoked may be one of: - "yes" - "no" - "begin" - "pending" - "approved" - "svc_pending" - "canceled" - "rejected" - "complete" .. [4] Only sent if CRL update information is available. If sent it's only value is "yes". If sent then the following values may also be sent, otherwise they will be absent: - updateCRLSuccess - updateCRLError - publishCRLSuccess - publishCRLError .. [5] The cms name varies depending on whether the issuing point is MasterCRL or not. If the issuing point is not the MasterCRL then the cms name will be appended with an underscore and the issuing point name. Thus for example the cms name crlUpdateStatus will be crlUpdateStatus if the issuing point is the MasterCRL. However if the issuing point is "foobar" then crlUpdateStatus will be crlUpdateStatus_foobar. When we return the response dict the key will always be the "base" name without the _issuing_point suffix. Thus crlUpdateStatus_foobar will appear in the response dict under the key 'crl_update_status' ''' request_status = get_request_status_xml(doc) if request_status != CMS_STATUS_SUCCESS: response = parse_error_template_xml(doc) return response response = {} response['request_status'] = request_status records = [] response['records'] = records dir_enabled = doc.xpath('//xml/header/dirEnabled[1]') if len(dir_enabled) == 1: parse_and_set_boolean_xml(dir_enabled[0], response, 'dir_enabled') certs_updated = doc.xpath('//xml/header/certsUpdated[1]') if len(certs_updated) == 1: certs_updated = int(certs_updated[0].text) response['certs_updated'] = certs_updated certs_to_update = doc.xpath('//xml/header/certsToUpdate[1]') if len(certs_to_update) == 1: certs_to_update = int(certs_to_update[0].text) response['certs_to_update'] = certs_to_update error_string = doc.xpath('//xml/header/error[1]') if len(error_string) == 1: error_string = etree.tostring(error_string[0], method='text', encoding=unicode).strip() response['error_string'] = error_string revoked = doc.xpath('//xml/header/revoked[1]') if len(revoked) == 1: revoked = etree.tostring(revoked[0], method='text', encoding=unicode).strip() response['revoked'] = revoked total_record_count = doc.xpath('//xml/header/totalRecordCount[1]') if len(total_record_count) == 1: total_record_count = int(total_record_count[0].text) response['total_record_count'] = total_record_count update_crl = doc.xpath('//xml/header/updateCRL[1]') if len(update_crl) == 1: parse_and_set_boolean_xml(update_crl[0], response, 'update_crl') update_crl_success = doc.xpath('//xml/header/updateCRLSuccess[1]') if len(update_crl_success) == 1: parse_and_set_boolean_xml(update_crl_success[0], response, 'update_crl_success') update_crl_error = doc.xpath('//xml/header/updateCRLError[1]') if len(update_crl_error) == 1: update_crl_error = etree.tostring(update_crl_error[0], method='text', encoding=unicode).strip() response['update_crl_error'] = update_crl_error publish_crl_success = doc.xpath('//xml/header/publishCRLSuccess[1]') if len(publish_crl_success) == 1: parse_and_set_boolean_xml(publish_crl_success[0], response, 'publish_crl_success') publish_crl_error = doc.xpath('//xml/header/publishCRLError[1]') if len(publish_crl_error) == 1: publish_crl_error = etree.tostring(publish_crl_error[0], method='text', encoding=unicode).strip() response['publish_crl_error'] = publish_crl_error crl_update_status = doc.xpath("//xml/header/*[starts-with(name(), 'crlUpdateStatus')][1]") if len(crl_update_status) == 1: parse_and_set_boolean_xml(crl_update_status[0], response, 'crl_update_status') crl_update_error = doc.xpath("//xml/header/*[starts-with(name(), 'crlUpdateError')][1]") if len(crl_update_error) == 1: crl_update_error = etree.tostring(crl_update_error[0], method='text', encoding=unicode).strip() response['crl_update_error'] = crl_update_error crl_publish_status = doc.xpath("//xml/header/*[starts-with(name(), 'crlPublishStatus')][1]") if len(crl_publish_status) == 1: parse_and_set_boolean_xml(crl_publish_status[0], response, 'crl_publish_status') crl_publish_error = doc.xpath("//xml/header/*[starts-with(name(), 'crlPublishError')][1]") if len(crl_publish_error) == 1: crl_publish_error = etree.tostring(crl_publish_error[0], method='text', encoding=unicode).strip() response['crl_publish_error'] = crl_publish_error for record in doc.xpath('//xml/records[*]/record'): response_record = {} records.append(response_record) serial_number = record.xpath('serialNumber[1]') if len(serial_number) == 1: serial_number = int(serial_number[0].text, 16) # parse as hex response_record['serial_number'] = serial_number response['serial_number_hex'] = u'0x%X' % serial_number error_string = record.xpath('error[1]') if len(error_string) == 1: error_string = etree.tostring(error_string[0], method='text', encoding=unicode).strip() response_record['error_string'] = error_string return response def parse_unrevoke_cert_xml(doc): ''' :param doc: The root node of the xml document to parse :returns: result dict :except ValueError: After parsing the results are returned in a result dict. The following table illustrates the mapping from the CMS data item to what may be found in the result dict. If a CMS data item is absent it will also be absent in the result dict. If the requestStatus is not SUCCESS then the response dict will have the contents described in `parse_error_template_xml`. +----------------------+----------------+-----------------------+---------------+ |cms name |cms type |result name |result type | +======================+================+=======================+===============+ |dirEnabled |string [1]_ |dir_enabled |bool | +----------------------+----------------+-----------------------+---------------+ |dirUpdated |string [1]_ |dir_updated |bool | +----------------------+----------------+-----------------------+---------------+ |error |string |error_string |unicode | +----------------------+----------------+-----------------------+---------------+ |unrevoked |string [3]_ |unrevoked |unicode | +----------------------+----------------+-----------------------+---------------+ |updateCRL |string [1]_ [4]_|update_crl |bool | +----------------------+----------------+-----------------------+---------------+ |updateCRLSuccess |string [1]_ [4]_|update_crl_success |bool | +----------------------+----------------+-----------------------+---------------+ |updateCRLError |string [4]_ |update_crl_error |unicode | +----------------------+----------------+-----------------------+---------------+ |publishCRLSuccess |string [1]_ [4]_|publish_crl_success |bool | +----------------------+----------------+-----------------------+---------------+ |publishCRLError |string [4]_ |publish_crl_error |unicode | +----------------------+----------------+-----------------------+---------------+ |crlUpdateStatus |string [1]_ [5]_|crl_update_status |bool | +----------------------+----------------+-----------------------+---------------+ |crlUpdateError |string [5]_ |crl_update_error |unicode | +----------------------+----------------+-----------------------+---------------+ |crlPublishStatus |string [1]_ [5]_|crl_publish_status |bool | +----------------------+----------------+-----------------------+---------------+ |crlPublishError |string [5]_ |crl_publish_error |unicode | +----------------------+----------------+-----------------------+---------------+ |serialNumber |BigInteger |serial_number |int|long | +----------------------+----------------+-----------------------+---------------+ .. [1] String value is either "yes" or "no" .. [3] unrevoked may be one of: - "yes" - "no" - "pending" .. [4] Only sent if CRL update information is available. If sent it's only value is "yes". If sent then the following values may also be sent, otherwise they will be absent: - updateCRLSuccess - updateCRLError - publishCRLSuccess - publishCRLError .. [5] The cms name varies depending on whether the issuing point is MasterCRL or not. If the issuing point is not the MasterCRL then the cms name will be appended with an underscore and the issuing point name. Thus for example the cms name crlUpdateStatus will be crlUpdateStatus if the issuing point is the MasterCRL. However if the issuing point is "foobar" then crlUpdateStatus will be crlUpdateStatus_foobar. When we return the response dict the key will always be the "base" name without the _issuing_point suffix. Thus crlUpdateStatus_foobar will appear in the response dict under the key 'crl_update_status' ''' request_status = get_request_status_xml(doc) if request_status != CMS_STATUS_SUCCESS: response = parse_error_template_xml(doc) return response response = {} response['request_status'] = request_status dir_enabled = doc.xpath('//xml/header/dirEnabled[1]') if len(dir_enabled) == 1: parse_and_set_boolean_xml(dir_enabled[0], response, 'dir_enabled') dir_updated = doc.xpath('//xml/header/dirUpdated[1]') if len(dir_updated) == 1: parse_and_set_boolean_xml(dir_updated[0], response, 'dir_updated') error_string = doc.xpath('//xml/header/error[1]') if len(error_string) == 1: error_string = etree.tostring(error_string[0], method='text', encoding=unicode).strip() response['error_string'] = error_string unrevoked = doc.xpath('//xml/header/unrevoked[1]') if len(unrevoked) == 1: unrevoked = etree.tostring(unrevoked[0], method='text', encoding=unicode).strip() response['unrevoked'] = unrevoked update_crl = doc.xpath('//xml/header/updateCRL[1]') if len(update_crl) == 1: parse_and_set_boolean_xml(update_crl[0], response, 'update_crl') update_crl_success = doc.xpath('//xml/header/updateCRLSuccess[1]') if len(update_crl_success) == 1: parse_and_set_boolean_xml(update_crl_success[0], response, 'update_crl_success') update_crl_error = doc.xpath('//xml/header/updateCRLError[1]') if len(update_crl_error) == 1: update_crl_error = etree.tostring(update_crl_error[0], method='text', encoding=unicode).strip() response['update_crl_error'] = update_crl_error publish_crl_success = doc.xpath('//xml/header/publishCRLSuccess[1]') if len(publish_crl_success) == 1: parse_and_set_boolean_xml(publish_crl_success[0], response, 'publish_crl_success') publish_crl_error = doc.xpath('//xml/header/publishCRLError[1]') if len(publish_crl_error) == 1: publish_crl_error = etree.tostring(publish_crl_error[0], method='text', encoding=unicode).strip() response['publish_crl_error'] = publish_crl_error crl_update_status = doc.xpath("//xml/header/*[starts-with(name(), 'crlUpdateStatus')][1]") if len(crl_update_status) == 1: parse_and_set_boolean_xml(crl_update_status[0], response, 'crl_update_status') crl_update_error = doc.xpath("//xml/header/*[starts-with(name(), 'crlUpdateError')][1]") if len(crl_update_error) == 1: crl_update_error = etree.tostring(crl_update_error[0], method='text', encoding=unicode).strip() response['crl_update_error'] = crl_update_error crl_publish_status = doc.xpath("//xml/header/*[starts-with(name(), 'crlPublishStatus')][1]") if len(crl_publish_status) == 1: parse_and_set_boolean_xml(crl_publish_status[0], response, 'crl_publish_status') crl_publish_error = doc.xpath("//xml/header/*[starts-with(name(), 'crlPublishError')][1]") if len(crl_publish_error) == 1: crl_publish_error = etree.tostring(crl_publish_error[0], method='text', encoding=unicode).strip() response['crl_publish_error'] = crl_publish_error serial_number = doc.xpath('//xml/header/serialNumber[1]') if len(serial_number) == 1: serial_number = int(serial_number[0].text, 16) # parse as hex response['serial_number'] = serial_number response['serial_number_hex'] = u'0x%X' % serial_number return response #------------------------------------------------------------------------------- from ipalib import api, SkipPluginModule if api.env.ra_plugin != 'dogtag': # In this case, abort loading this plugin module... raise SkipPluginModule(reason='dogtag not selected as RA plugin') import os, random from ipaserver.plugins import rabase from ipalib.errors import CertificateOperationError from ipalib.constants import TYPE_ERROR from ipalib.util import cachedproperty from ipapython import dogtag from ipalib import _ class ra(rabase.rabase): """ Request Authority backend plugin. """ def __init__(self): if api.env.in_tree: self.sec_dir = api.env.dot_ipa + os.sep + 'alias' self.pwd_file = self.sec_dir + os.sep + '.pwd' else: self.sec_dir = "/etc/httpd/alias" self.pwd_file = "/etc/httpd/alias/pwdfile.txt" self.noise_file = self.sec_dir + os.sep + '.noise' self.ipa_key_size = "2048" self.ipa_certificate_nickname = "ipaCert" self.ca_certificate_nickname = "caCert" try: f = open(self.pwd_file, "r") self.password = f.readline().strip() f.close() except IOError: self.password = '' super(ra, self).__init__() def raise_certificate_operation_error(self, func_name, err_msg=None, detail=None): """ :param func_name: function name where error occurred :param err_msg: diagnostic error message, if not supplied it will be 'Unable to communicate with CMS' :param detail: extra information that will be appended to err_msg inside a parenthesis Raise a CertificateOperationError and log the error message. """ if err_msg is None: err_msg = _('Unable to communicate with CMS') if detail is not None: err_msg = u'%s (%s)' % (err_msg, detail) self.error('%s.%s(): %s', self.fullname, func_name, err_msg) raise CertificateOperationError(error=err_msg) def _host_has_service(self, host, service='CA'): """ :param host: A host which might be a master for a service. :param service: The service for which the host might be a master. :return: (true, false) Check if a specified host is a master for a specified service. """ ldap2 = self.api.Backend.ldap2 base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) filter_attrs = { 'objectClass': 'ipaConfigObject', 'cn': service, 'ipaConfigString': 'enabledService', } filter = ldap2.make_filter(filter_attrs, rules='&') try: ent, trunc = ldap2.find_entries(filter=filter, base_dn=base_dn) if len(ent): return True except Exception, e: pass return False def _select_any_master(self, service='CA'): """ :param service: The service for which we're looking for a master. :return: host as str Select any host which is a master for a specified service. """ ldap2 = self.api.Backend.ldap2 base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) filter_attrs = { 'objectClass': 'ipaConfigObject', 'cn': service, 'ipaConfigString': 'enabledService', } filter = ldap2.make_filter(filter_attrs, rules='&') try: ent, trunc = ldap2.find_entries(filter=filter, base_dn=base_dn) if len(ent): entry = random.choice(ent) dn = entry[0] assert isinstance(dn, DN) return dn[1].value except Exception, e: pass return None @cachedproperty def ca_host(self): """ :return: host as str Select our CA host. """ if self._host_has_service(host=api.env.ca_host): return api.env.ca_host if api.env.host != api.env.ca_host: if self._host_has_service(host=api.env.host): return api.env.host host = self._select_any_master() if host: return host else: return api.env.ca_host def _request(self, url, port, **kw): """ :param url: The URL to post to. :param kw: Keyword arguments to encode into POST body. :return: (http_status, http_reason_phrase, http_headers, http_body) as (integer, unicode, dict, str) Perform an HTTP request. """ return dogtag.http_request(self.ca_host, port, url, **kw) def _sslget(self, url, port, **kw): """ :param url: The URL to post to. :param kw: Keyword arguments to encode into POST body. :return: (http_status, http_reason_phrase, http_headers, http_body) as (integer, unicode, dict, str) Perform an HTTPS request """ return dogtag.https_request(self.ca_host, port, url, self.sec_dir, self.password, self.ipa_certificate_nickname, **kw) def get_parse_result_xml(self, xml_text, parse_func): ''' :param xml_text: The XML text to parse :param parse_func: The XML parsing function to apply to the parsed DOM tree. :return: parsed result dict Utility routine which parses the input text into an XML DOM tree and then invokes the parsing function on the DOM tree in order to get the parsing result as a dict of key/value pairs. ''' parser = etree.XMLParser() doc = etree.fromstring(xml_text, parser) result = parse_func(doc) self.debug("%s() xml_text:\n%s\nparse_result:\n%s" % (parse_func.__name__, xml_text, result)) return result def check_request_status(self, request_id): """ :param request_id: request ID Check status of a certificate signing request. The command returns a dict with these possible key/value pairs. Some key/value pairs may be absent. +-------------------+---------------+---------------+ |result name |result type |comments | +===================+===============+===============+ |serial_number |unicode [1]_ | | +-------------------+---------------+---------------+ |request_id |unicode | | +-------------------+---------------+---------------+ |cert_request_status|unicode [2]_ | | +-------------------+---------------+---------------+ .. [1] Passed through XMLRPC as decimal string. Can convert to optimal integer type (int or long) via int(serial_number) .. [2] cert_request_status may be one of: - "begin" - "pending" - "approved" - "svc_pending" - "canceled" - "rejected" - "complete" """ self.debug('%s.check_request_status()', self.fullname) # Call CMS http_status, http_reason_phrase, http_headers, http_body = \ self._request('/ca/ee/ca/checkRequest', self.env.ca_port, requestId=request_id, xml='true') # Parse and handle errors if (http_status != 200): self.raise_certificate_operation_error('check_request_status', detail=http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_check_request_result_xml) request_status = parse_result['request_status'] if request_status != CMS_STATUS_SUCCESS: self.raise_certificate_operation_error('check_request_status', cms_request_status_to_string(request_status), parse_result.get('error_string')) # Return command result cmd_result = {} if parse_result.has_key('serial_numbers') and len(parse_result['serial_numbers']) > 0: # see module documentation concerning serial numbers and XMLRPC cmd_result['serial_number'] = unicode(parse_result['serial_numbers'][0]) if parse_result.has_key('request_id'): cmd_result['request_id'] = parse_result['request_id'] if parse_result.has_key('cert_request_status'): cmd_result['cert_request_status'] = parse_result['cert_request_status'] return cmd_result def get_certificate(self, serial_number=None): """ Retrieve an existing certificate. :param serial_number: Certificate serial number. Must be a string value because serial numbers may be of any magnitue and XMLRPC cannot handle integers larger than 64-bit. The string value should be decimal, but may optionally be prefixed with a hex radix prefix if the integal value is represented as hexadecimal. If no radix prefix is supplied the string will be interpreted as decimal. The command returns a dict with these possible key/value pairs. Some key/value pairs may be absent. +-----------------+---------------+---------------+ |result name |result type |comments | +=================+===============+===============+ |certificate |unicode [1]_ | | +-----------------+---------------+---------------+ |serial_number |unicode [2]_ | | +-----------------+---------------+---------------+ |revocation_reason|int [3]_ | | +-----------------+---------------+---------------+ .. [1] Base64 encoded .. [2] Passed through XMLRPC as decimal string. Can convert to optimal integer type (int or long) via int(serial_number) .. [3] revocation reason may be one of: - 0 = UNSPECIFIED - 1 = KEY_COMPROMISE - 2 = CA_COMPROMISE - 3 = AFFILIATION_CHANGED - 4 = SUPERSEDED - 5 = CESSATION_OF_OPERATION - 6 = CERTIFICATE_HOLD - 8 = REMOVE_FROM_CRL - 9 = PRIVILEGE_WITHDRAWN - 10 = AA_COMPROMISE """ self.debug('%s.get_certificate()', self.fullname) # Convert serial number to integral type from string to properly handle # radix issues. Note: the int object constructor will properly handle large # magnitude integral values by returning a Python long type when necessary. serial_number = int(serial_number, 0) # Call CMS http_status, http_reason_phrase, http_headers, http_body = \ self._sslget('/ca/agent/ca/displayBySerial', self.env.ca_agent_port, serialNumber=str(serial_number), xml='true') # Parse and handle errors if (http_status != 200): self.raise_certificate_operation_error('get_certificate', detail=http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_display_cert_xml) request_status = parse_result['request_status'] if request_status != CMS_STATUS_SUCCESS: self.raise_certificate_operation_error('get_certificate', cms_request_status_to_string(request_status), parse_result.get('error_string')) # Return command result cmd_result = {} if parse_result.has_key('certificate'): cmd_result['certificate'] = parse_result['certificate'] if parse_result.has_key('serial_number'): # see module documentation concerning serial numbers and XMLRPC cmd_result['serial_number'] = unicode(parse_result['serial_number']) cmd_result['serial_number_hex'] = u'0x%X' % int(cmd_result['serial_number']) if parse_result.has_key('revocation_reason'): cmd_result['revocation_reason'] = parse_result['revocation_reason'] return cmd_result def request_certificate(self, csr, request_type='pkcs10'): """ :param csr: The certificate signing request. :param request_type: The request type (defaults to ``'pkcs10'``). Submit certificate signing request. The command returns a dict with these possible key/value pairs. Some key/value pairs may be absent. +---------------+---------------+---------------+ |result name |result type |comments | +===============+===============+===============+ |serial_number |unicode [1]_ | | +---------------+---------------+---------------+ |certificate |unicode [2]_ | | +---------------+---------------+---------------+ |request_id |unicode | | +---------------+---------------+---------------+ |subject |unicode | | +---------------+---------------+---------------+ .. [1] Passed through XMLRPC as decimal string. Can convert to optimal integer type (int or long) via int(serial_number) .. [2] Base64 encoded """ self.debug('%s.request_certificate()', self.fullname) # Call CMS http_status, http_reason_phrase, http_headers, http_body = \ self._sslget('/ca/eeca/ca/profileSubmitSSLClient', self.env.ca_ee_port, profileId='caIPAserviceCert', cert_request_type=request_type, cert_request=csr, xml='true') # Parse and handle errors if (http_status != 200): self.raise_certificate_operation_error('request_certificate', detail=http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_profile_submit_result_xml) # Note different status return, it's not request_status, it's error_code error_code = parse_result['error_code'] if error_code != CMS_SUCCESS: self.raise_certificate_operation_error('request_certificate', cms_error_code_to_string(error_code), parse_result.get('error_string')) # Return command result cmd_result = {} # FIXME: should we return all the requests instead of just the first one? if len(parse_result['requests']) < 1: return cmd_result request = parse_result['requests'][0] if request.has_key('serial_number'): # see module documentation concerning serial numbers and XMLRPC cmd_result['serial_number'] = unicode(request['serial_number']) cmd_result['serial_number_hex'] = u'0x%X' % request['serial_number'] if request.has_key('certificate'): cmd_result['certificate'] = request['certificate'] if request.has_key('request_id'): cmd_result['request_id'] = request['request_id'] if request.has_key('subject'): cmd_result['subject'] = request['subject'] return cmd_result def revoke_certificate(self, serial_number, revocation_reason=0): """ :param serial_number: Certificate serial number. Must be a string value because serial numbers may be of any magnitue and XMLRPC cannot handle integers larger than 64-bit. The string value should be decimal, but may optionally be prefixed with a hex radix prefix if the integal value is represented as hexadecimal. If no radix prefix is supplied the string will be interpreted as decimal. :param revocation_reason: Integer code of revocation reason. Revoke a certificate. The command returns a dict with these possible key/value pairs. Some key/value pairs may be absent. +---------------+---------------+---------------+ |result name |result type |comments | +===============+===============+===============+ |revoked |bool | | +---------------+---------------+---------------+ """ self.debug('%s.revoke_certificate()', self.fullname) if type(revocation_reason) is not int: raise TypeError(TYPE_ERROR % ('revocation_reason', int, revocation_reason, type(revocation_reason))) # Convert serial number to integral type from string to properly handle # radix issues. Note: the int object constructor will properly handle large # magnitude integral values by returning a Python long type when necessary. serial_number = int(serial_number, 0) # Call CMS http_status, http_reason_phrase, http_headers, http_body = \ self._sslget('/ca/agent/ca/doRevoke', self.env.ca_agent_port, op='revoke', revocationReason=revocation_reason, revokeAll='(certRecordId=%s)' % str(serial_number), totalRecordCount=1, xml='true') # Parse and handle errors if (http_status != 200): self.raise_certificate_operation_error('revoke_certificate', detail=http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_revoke_cert_xml) request_status = parse_result['request_status'] if request_status != CMS_STATUS_SUCCESS: self.raise_certificate_operation_error('revoke_certificate', cms_request_status_to_string(request_status), parse_result.get('error_string')) # Return command result cmd_result = {} if parse_result.get('revoked') == 'yes': cmd_result['revoked'] = True else: cmd_result['revoked'] = False return cmd_result def take_certificate_off_hold(self, serial_number): """ :param serial_number: Certificate serial number. Must be a string value because serial numbers may be of any magnitue and XMLRPC cannot handle integers larger than 64-bit. The string value should be decimal, but may optionally be prefixed with a hex radix prefix if the integal value is represented as hexadecimal. If no radix prefix is supplied the string will be interpreted as decimal. Take revoked certificate off hold. The command returns a dict with these possible key/value pairs. Some key/value pairs may be absent. +---------------+---------------+---------------+ |result name |result type |comments | +===============+===============+===============+ |unrevoked |bool | | +---------------+---------------+---------------+ |error_string |unicode | | +---------------+---------------+---------------+ """ self.debug('%s.take_certificate_off_hold()', self.fullname) # Convert serial number to integral type from string to properly handle # radix issues. Note: the int object constructor will properly handle large # magnitude integral values by returning a Python long type when necessary. serial_number = int(serial_number, 0) # Call CMS http_status, http_reason_phrase, http_headers, http_body = \ self._sslget('/ca/agent/ca/doUnrevoke', self.env.ca_agent_port, serialNumber=str(serial_number), xml='true') # Parse and handle errors if (http_status != 200): self.raise_certificate_operation_error('take_certificate_off_hold', detail=http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_unrevoke_cert_xml) request_status = parse_result['request_status'] if request_status != CMS_STATUS_SUCCESS: self.raise_certificate_operation_error('take_certificate_off_hold', cms_request_status_to_string(request_status), parse_result.get('error_string')) # Return command result cmd_result = {} if parse_result.has_key('error_string'): cmd_result['error_string'] = parse_result['error_string'] if parse_result.get('unrevoked') == 'yes': cmd_result['unrevoked'] = True else: cmd_result['unrevoked'] = False return cmd_result def find(self, options): """ Search for certificates :param options: dictionary of search options """ def convert_time(value): """ Convert time to milliseconds to pass to dogtag """ ts = time.strptime(value, '%Y-%m-%d') return int(time.mktime(ts) * 1000) self.debug('%s.find()', self.fullname) # Create the root element page = etree.Element('CertSearchRequest') # Make a new document tree doc = etree.ElementTree(page) # This matches the default configuration of the pki tool. booloptions = {'serialNumberRangeInUse': True, 'subjectInUse': False, 'matchExactly': False, 'revokedByInUse': False, 'revokedOnInUse': False, 'revocationReasonInUse': False, 'issuedByInUse': False, 'issuedOnInUse': False, 'validNotBeforeInUse': False, 'validNotAfterInUse': False, 'validityLengthInUse': False, 'certTypeInUse': False} if options.get('exactly', False): booloptions['matchExactly'] = True if 'subject' in options: node = etree.SubElement(page, 'commonName') node.text = options['subject'] booloptions['subjectInUse'] = True if 'revocation_reason' in options: node = etree.SubElement(page, 'revocationReason') node.text = unicode(options['revocation_reason']) booloptions['revocationReasonInUse'] = True if 'min_serial_number' in options: node = etree.SubElement(page, 'serialFrom') node.text = unicode(options['min_serial_number']) if 'max_serial_number' in options: node = etree.SubElement(page, 'serialTo') node.text = unicode(options['max_serial_number']) # date_types is a tuple that consists of: # 1. attribute name passed from IPA API # 2. attribute name used by REST API # 3. boolean to set in the REST API date_types = ( ('validnotbefore_from', 'validNotBeforeFrom', 'validNotBeforeInUse'), ('validnotbefore_to', 'validNotBeforeTo', 'validNotBeforeInUse'), ('validnotafter_from', 'validNotAfterFrom', 'validNotAfterInUse'), ('validnotafter_to', 'validNotAfterTo', 'validNotAfterInUse'), ('issuedon_from', 'issuedOnFrom','issuedOnInUse'), ('issuedon_to', 'issuedOnTo','issuedOnInUse'), ('revokedon_from', 'revokedOnFrom','revokedOnInUse'), ('revokedon_to', 'revokedOnTo','revokedOnInUse'), ) for (attr, dattr, battr) in date_types: if attr in options: epoch = convert_time(options[attr]) node = etree.SubElement(page, dattr) node.text = unicode(epoch) booloptions[battr] = True # Add the boolean options to our XML document for opt in booloptions: e = etree.SubElement(page, opt) e.text = str(booloptions[opt]).lower() payload = etree.tostring(doc, pretty_print=False, xml_declaration=True, encoding='UTF-8') self.debug('%s.find(): request: %s', self.fullname, payload) url = 'http://%s/ca/rest/certs/search?size=%d' % (ipautil.format_netloc(self.ca_host, ipapython.dogtag.configured_constants().UNSECURE_PORT), options.get('sizelimit', 100)) opener = urllib2.build_opener() opener.addheaders = [('Accept-Encoding', 'gzip, deflate'), ('User-Agent', 'IPA')] req = urllib2.Request(url=url, data=payload, headers={'Content-Type': 'application/xml'}) try: response = opener.open(req) except urllib2.HTTPError, e: self.debug('HTTP Response code: %d' % e.getcode()) if e.getcode() == 501: self.raise_certificate_operation_error('find', detail=_('find not supported on CAs upgraded from 9 to 10')) self.raise_certificate_operation_error('find', detail=e.msg) except urllib2.URLError, e: self.raise_certificate_operation_error('find', detail=e.reason) data = response.readlines() self.debug('%s.find(): response: %s', self.fullname, data) parser = etree.XMLParser() try: doc = etree.fromstring(data[0], parser) except etree.XMLSyntaxError, e: self.raise_certificate_operation_error('find', detail=e.msg) # Grab all the certificates certs = doc.xpath('//CertDataInfo') results = [] for cert in certs: response_request = {} response_request['serial_number'] = int(cert.get('id'), 16) # parse as hex response_request['serial_number_hex'] = u'0x%X' % response_request['serial_number'] dn = cert.xpath('SubjectDN') if len(dn) == 1: response_request['subject'] = unicode(dn[0].text) status = cert.xpath('Status') if len(status) == 1: response_request['status'] = unicode(status[0].text) results.append(response_request) return results api.register(ra) freeipa-3.3.4/ipaserver/advise/0000775000175000017500000000000012271663206015762 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/advise/__init__.py0000664000175000017500000000146512271663206020101 0ustar mkosekmkosek# Authors: Tomas Babej # # Copyright (C) 2013 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 . # """ Base subpackage for ipa-advise related code. """ freeipa-3.3.4/ipaserver/advise/plugins/0000775000175000017500000000000012271663206017443 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/advise/plugins/__init__.py0000664000175000017500000000147012271663206021556 0ustar mkosekmkosek# Authors: Tomas Babej # # Copyright (C) 2013 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 . # """ Provides a separate api for ipa-advise plugins. """ freeipa-3.3.4/ipaserver/advise/plugins/fedora_authconfig.py0000664000175000017500000000273012271663206023466 0ustar mkosekmkosek# Authors: Tomas Babej # # Copyright (C) 2013 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 . # from ipalib import api from ipalib.frontend import Advice class config_fedora_authconfig(Advice): """ Provides client configuration instructions using authconfig. """ description = 'Authconfig instructions for configuring Fedora 18/19 '\ 'client with IPA server without use of SSSD.' def get_info(self): self.log.debug("Hostname obtained via api.env.host") self.log.comment("Run the following command as a root:") template = "/sbin/authconfig --enableldap --ldapserver={server} "\ "--enablerfc2307bis --enablekrb5" advice = template.format(server=api.env.host) self.log.command(advice) api.register(config_fedora_authconfig) freeipa-3.3.4/ipaserver/advise/plugins/legacy_clients.py0000664000175000017500000003652312271663206023013 0ustar mkosekmkosek# Authors: Ana Krivokapic # # Copyright (C) 2013 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 . # import os from ipalib import api from ipalib.frontend import Advice from ipapython.ipautil import template_file, SHARE_DIR class config_base_legacy_client(Advice): def get_uri_and_base(self): uri = 'ldap://%s' % api.env.host base = 'cn=compat,%s' % api.env.basedn return uri, base def check_compat_plugin(self): compat_is_enabled = api.Command['compat_is_enabled']()['result'] if not compat_is_enabled: self.log.comment( 'Schema Compatibility plugin has not been configured ' 'on this server. To configure it, run ' '"ipa-adtrust-install --enable-compat"\n' ) def configure_ca_cert(self): self.log.comment('Please note that this script assumes ' '/etc/openldap/cacerts as the default CA certificate ' 'location. If this value is different on your system ' 'the script needs to be modified accordingly.\n') cacertdir_rehash = ('https://fedorahosted.org/authconfig/browser/' 'cacertdir_rehash?format=txt') self.log.comment('Download the CA certificate of the IPA server') self.log.command('mkdir -p -m 755 /etc/openldap/cacerts') self.log.command('wget http://%s/ipa/config/ca.crt -O ' '/etc/openldap/cacerts/ipa.crt\n' % api.env.host) self.log.comment('Generate hashes for the openldap library') self.log.command('command -v cacertdir_rehash') self.log.command('if [ $? -ne 0 ] ; then') self.log.command(' wget "%s" -O cacertdir_rehash ;' % cacertdir_rehash) self.log.command(' chmod 755 ./cacertdir_rehash ;') self.log.command(' ./cacertdir_rehash /etc/openldap/cacerts/ ;') self.log.command('else') self.log.command(' cacertdir_rehash /etc/openldap/cacerts/ ;') self.log.command('fi\n') def configure_and_start_sssd(self): uri, base = self.get_uri_and_base() template = os.path.join( SHARE_DIR, 'advise', 'legacy', 'sssd.conf.template' ) sssd_conf = template_file(template, dict(URI=uri, BASE=base)) self.log.comment('Configure SSSD') self.log.command('cat > /etc/sssd/sssd.conf << EOF \n' '%s\nEOF' % sssd_conf) self.log.command('chmod 0600 /etc/sssd/sssd.conf\n') self.log.comment('Start SSSD') self.log.command('service sssd start') class config_redhat_sssd_before_1_9(config_base_legacy_client): """ Legacy client configuration for Red Hat based systems, using SSSD. """ description = ('Instructions for configuring a system with an old version ' 'of SSSD (1.5-1.8) as a FreeIPA client. This set of ' 'instructions is targeted for platforms that include ' 'the authconfig utility, which are all Red Hat based ' 'platforms.') def get_info(self): self.check_compat_plugin() self.log.comment('Install required packages via yum') self.log.command('yum install -y sssd authconfig wget openssl\n') self.configure_ca_cert() self.log.comment('Use the authconfig to configure nsswitch.conf ' 'and the PAM stack') self.log.command('authconfig --updateall --enablesssd ' '--enablesssdauth\n') self.configure_and_start_sssd() def configure_ca_cert(self): self.log.comment('NOTE: IPA certificate uses the SHA-256 hash ' 'function. SHA-256 was introduced in RHEL5.2. ' 'Therefore, clients older than RHEL5.2 will not be ' 'able to interoperate with IPA server 3.x.') super(config_redhat_sssd_before_1_9, self).configure_ca_cert() api.register(config_redhat_sssd_before_1_9) class config_generic_linux_sssd_before_1_9(config_base_legacy_client): """ Legacy client configuration for non Red Hat based linux systems, using SSSD. """ description = ('Instructions for configuring a system with an old version ' 'of SSSD (1.5-1.8) as a FreeIPA client. This set of ' 'instructions is targeted for linux systems that do not ' 'include the authconfig utility.') def get_info(self): self.check_compat_plugin() with open(os.path.join( SHARE_DIR, 'advise', 'legacy', 'pam.conf.sssd.template')) as fd: pam_conf = fd.read() self.log.comment('Install required packages using your system\'s ' 'package manager. E.g:') self.log.command('apt-get -y install sssd wget openssl\n') self.configure_ca_cert() self.log.comment('Configure nsswitch.conf. Append sss to the lines ' 'beginning with passwd and group. ') self.log.command('grep "^passwd.*sss" /etc/nsswitch.conf') self.log.command('if [ $? -ne 0 ] ; then sed -i ' '\'/^passwd/s|$| sss|\' /etc/nsswitch.conf ; fi') self.log.command('grep "^group.*sss" /etc/nsswitch.conf') self.log.command('if [ $? -ne 0 ] ; then sed -i ' '\'/^group/s|$| sss|\' /etc/nsswitch.conf ; fi\n') self.log.comment('Configure PAM. Configuring the PAM stack differs on ' 'particular distributions. The resulting PAM stack ' 'should look like this:') self.log.command('cat > /etc/pam.conf << EOF \n' '%s\nEOF\n' % pam_conf) self.configure_and_start_sssd() def configure_ca_cert(self): super(config_generic_linux_sssd_before_1_9, self).configure_ca_cert() self.log.comment('Configure ldap.conf. Set the value of ' 'TLS_CACERTDIR to /etc/openldap/cacerts. Make sure ' 'that the location of ldap.conf file matches your ' 'system\'s configuration.') self.log.command('echo "TLS_CACERTDIR /etc/openldap/cacerts" >> ' '/etc/ldap/ldap.conf\n') api.register(config_generic_linux_sssd_before_1_9) class config_redhat_nss_pam_ldapd(config_base_legacy_client): """ Legacy client configuration for Red Hat based systems, using nss-pam-ldapd. """ description = ('Instructions for configuring a system with nss-pam-ldapd ' 'as a FreeIPA client. This set of instructions is targeted ' 'for platforms that include the authconfig utility, which ' 'are all Red Hat based platforms.') def get_info(self): uri, base = self.get_uri_and_base() self.check_compat_plugin() self.log.comment('Install required packages via yum') self.log.command('yum install -y wget openssl nss-pam-ldapd pam_ldap ' 'authconfig\n') self.configure_ca_cert() self.log.comment('Use the authconfig to configure nsswitch.conf ' 'and the PAM stack') self.log.command('authconfig --updateall --enableldap ' '--enableldapauth --ldapserver=%s --ldapbasedn=%s\n' % (uri, base)) def configure_ca_cert(self): self.log.comment('NOTE: IPA certificate uses the SHA-256 hash ' 'function. SHA-256 was introduced in RHEL5.2. ' 'Therefore, clients older than RHEL5.2 will not be ' 'able to interoperate with IPA server 3.x.') super(config_redhat_nss_pam_ldapd, self).configure_ca_cert() api.register(config_redhat_nss_pam_ldapd) class config_generic_linux_nss_pam_ldapd(config_base_legacy_client): """ Legacy client configuration for non Red Hat based linux systems, using nss-pam-ldapd. """ description = ('Instructions for configuring a system with nss-pam-ldapd. ' 'This set of instructions is targeted for linux systems ' 'that do not include the authconfig utility.') def get_info(self): uri, base = self.get_uri_and_base() self.check_compat_plugin() with open(os.path.join( SHARE_DIR, 'advise', 'legacy', 'pam.conf.nss_pam_ldapd.template')) as fd: pam_conf = fd.read() nslcd_conf = 'uri %s\nbase %s' % (uri, base) self.log.comment('Install required packages using your system\'s ' 'package manager. E.g:') self.log.command('apt-get -y install wget openssl libnss-ldapd ' 'libpam-ldapd nslcd\n') self.configure_ca_cert() self.log.comment('Configure nsswitch.conf. Append ldap to the lines ' 'beginning with passwd and group. ') self.log.command('grep "^passwd.*ldap" /etc/nsswitch.conf') self.log.command('if [ $? -ne 0 ] ; then sed -i ' '\'/^passwd/s|$| ldap|\' /etc/nsswitch.conf ; fi') self.log.command('grep "^group.*ldap" /etc/nsswitch.conf') self.log.command('if [ $? -ne 0 ] ; then sed -i ' '\'/^group/s|$| ldap|\' /etc/nsswitch.conf ; fi\n') self.log.comment('Configure PAM. Configuring the PAM stack differs on ' 'particular distributions. The resulting PAM stack ' 'should look like this:') self.log.command('cat > /etc/pam.conf << EOF \n' '%s\nEOF\n' % pam_conf) self.log.comment('Configure nslcd.conf:') self.log.command('cat > /etc/nslcd.conf << EOF \n' '%s\nEOF\n' % nslcd_conf) self.log.comment('Configure pam_ldap.conf:') self.log.command('cat > /etc/pam_ldap.conf << EOF \n' '%s\nEOF\n' % nslcd_conf) self.log.comment('Stop nscd and restart nslcd') self.log.command('service nscd stop && service nslcd restart') def configure_ca_cert(self): super(config_generic_linux_nss_pam_ldapd, self).configure_ca_cert() self.log.comment('Configure ldap.conf. Set the value of ' 'TLS_CACERTDIR to /etc/openldap/cacerts. Make sure ' 'that the location of ldap.conf file matches your ' 'system\'s configuration.') self.log.command('echo "TLS_CACERTDIR /etc/openldap/cacerts" >> ' '/etc/ldap/ldap.conf\n') api.register(config_generic_linux_nss_pam_ldapd) class config_freebsd_nss_pam_ldapd(config_base_legacy_client): """ Legacy client configuration for FreeBSD, using nss-pam-ldapd. """ description = ('Instructions for configuring a FreeBSD system with ' 'nss-pam-ldapd. ') def get_info(self): uri, base = self.get_uri_and_base() cacrt = '/usr/local/etc/ipa.crt' self.check_compat_plugin() with open(os.path.join( SHARE_DIR, 'advise', 'legacy', 'pam_conf_sshd.template')) as fd: pam_conf = fd.read() self.log.comment('Install required packages') self.log.command('pkg_add -r nss-pam-ldapd curl\n') self.configure_ca_cert(cacrt) self.log.comment('Configure nsswitch.conf') self.log.command('sed -i \'\' -e \'s/^passwd:/passwd: files ldap/\' ' '/etc/nsswitch.conf') self.log.command('sed -i \'\' -e \'s/^group:/group: files ldap/\' ' '/etc/nsswitch.conf\n') self.log.comment('Configure PAM stack for the sshd service') self.log.command('cat > /etc/pam.d/sshd << EOF \n' '%s\nEOF\n' % pam_conf) self.log.comment('Add automated start of nslcd to /etc/rc.conf') self.log.command('echo \'nslcd_enable="YES"\nnslcd_debug="NO"\' >> ' '/etc/rc.conf') self.log.comment('Configure nslcd.conf:') self.log.command('echo "uid nslcd\n' 'gid nslcd\n' 'uri %s\n' 'base %s\n' 'scope sub\n' 'base group cn=groups,%s\n' 'base passwd cn=users,%s\n' 'base shadow cn=users,%s\n' 'ssl start_tls\n' 'tls_cacertfile %s\n" > /usr/local/etc/nslcd.conf' % ((uri,) + (base,)*4 + (cacrt,))) self.log.comment('Configure ldap.conf:') self.log.command('echo "uri %s\nbase %s\nssl start_tls\ntls_cacert %s"' '> /usr/local/etc/ldap.conf' % (uri, base, cacrt)) self.log.comment('Restart nslcd') self.log.command('/usr/local/etc/rc.d/nslcd restart') def configure_ca_cert(self, cacrt): self.log.comment('Download the CA certificate of the IPA server') self.log.command('curl -k https://%s/ipa/config/ca.crt > ' '%s' % (api.env.host, cacrt)) api.register(config_freebsd_nss_pam_ldapd) class config_redhat_nss_ldap(config_base_legacy_client): """ Legacy client configuration for Red Hat based systems, using nss-ldap. """ description = ('Instructions for configuring a system with nss-ldap ' 'as a FreeIPA client. This set of instructions is targeted ' 'for platforms that include the authconfig utility, which ' 'are all Red Hat based platforms.') def get_info(self): uri, base = self.get_uri_and_base() self.check_compat_plugin() self.log.comment('Install required packages via yum') self.log.command('yum install -y wget openssl nss_ldap ' 'authconfig\n') self.configure_ca_cert() self.log.comment('Use the authconfig to configure nsswitch.conf ' 'and the PAM stack') self.log.command('authconfig --updateall --enableldap ' '--enableldapauth --ldapserver=%s --ldapbasedn=%s\n' % (uri, base)) def configure_ca_cert(self): self.log.comment('NOTE: IPA certificate uses the SHA-256 hash ' 'function. SHA-256 was introduced in RHEL5.2. ' 'Therefore, clients older than RHEL5.2 will not be ' 'able to interoperate with IPA server 3.x.') super(config_redhat_nss_ldap, self).configure_ca_cert() api.register(config_redhat_nss_ldap) freeipa-3.3.4/ipaserver/advise/base.py0000664000175000017500000001436012271663206017252 0ustar mkosekmkosek# Authors: Tomas Babej # # Copyright (C) 2013 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 . # import os from ipalib import api from ipalib.errors import ValidationError from ipapython import admintool from textwrap import wrap """ To add configuration instructions for a new use case, define a new class that inherits from Advice class. You should create a plugin file for it in ipaserver/advise/plugins folder. The class can run any arbitrary code or IPA command via api.Command['command']() calls. It needs to override get_info() method, which returns the formatted advice string. >>> class sample_advice(Advice): >>> description = 'Instructions for machine with SSSD 1.0 setup.' Description provided shows itself as a header and in the list of all advices currently available via ipa-advise. Optionally, you can require root privileges for your plugin: >>> require_root = True The following method should be implemented in your plugin: >>> def get_info(): >>> self.log.debug('Entering execute() method') >>> self.log.comment('Providing useful advice just for you') >>> self.log.command('yum update sssd -y') As you can see, Advice's log has 3 different levels. Debug lines are printed out with '# DEBUG:' prefix if --verbose had been used. Comment lines utilize '# ' prefix and command lines are printed raw. Please note that comments are automatically wrapped after 70 characters. Use wrapped=False option to force the unwrapped line in the comment. >>> self.log.comment("This line should not be wrapped", wrapped=False) As a result, you can redirect the advice's output directly to a script file. # ipa-advise sample-advice > script.sh # ./script.sh Important! Do not forget to register the class to the API. >>> api.register(sample_advice) """ class IpaAdvise(admintool.AdminTool): """ Admin tool that given systems's configuration provides instructions how to configure the systems for various use cases. """ command_name = 'ipa-advise' usage = "%prog ADVICE" description = "Provides configuration advice for various use cases. To "\ "see the list of possible ADVICEs, run ipa-advise without "\ "any arguments." def __init__(self, options, args): super(IpaAdvise, self).__init__(options, args) @classmethod def add_options(cls, parser): super(IpaAdvise, cls).add_options(parser) def validate_options(self): super(IpaAdvise, self).validate_options(needs_root=False) if len(self.args) > 1: raise self.option_parser.error("You can only provide one " "positional argument.") def log_success(self): pass def print_config_list(self): self.print_header('List of available advices') max_keyword_len = max((len(keyword) for keyword in api.Advice)) for keyword in api.Advice: advice = getattr(api.Advice, keyword, '') description = getattr(advice, 'description', '') keyword = keyword.replace('_', '-') # Compute the number of spaces needed for the table to be aligned offset = max_keyword_len - len(keyword) prefix = " {key} {off}: ".format(key=keyword, off=' ' * offset) wrapped_description = wrap(description, 80 - len(prefix)) # Print the first line with the prefix (keyword) print prefix + wrapped_description[0] # Print the rest wrapped behind the colon for line in wrapped_description[1:]: print "{off}{line}".format(off=' ' * len(prefix), line=line) def print_header(self, header, print_shell=False): header_size = len(header) prefix = '' if print_shell: prefix = '# ' print '#!/bin/sh' # Do not print out empty header if header_size > 0: print(prefix + '-' * 70) for line in wrap(header, 70): print(prefix + line) print(prefix + '-' * 70) def print_advice(self, keyword): advice = getattr(api.Advice, keyword, None) # Ensure that Configuration class for given --setup option value exists if advice is None: raise ValidationError( name="advice", error="No instructions are available for '{con}'. " "See the list of available configuration " "by invoking the ipa-advise command with no argument." .format(con=keyword.replace('_', '-'))) # Check whether root privileges are needed if advice.require_root and os.getegid() != 0: raise admintool.ScriptError( 'Must be root to get advice for {adv}' .format(adv=keyword.replace('_', '-')), 1) # Print out nicely formatted header self.print_header(advice.description, print_shell=True) # Set options so that plugin can use verbose/quiet options advice.set_options(self.options) # Print out the actual advice api.Backend.xmlclient.connect() advice.get_info() api.Backend.xmlclient.disconnect() for line in advice.log.content: print line def run(self): super(IpaAdvise, self).run() api.bootstrap(in_server=False, context='advise') api.finalize() # With no argument, print the list out and exit if not self.args: self.print_config_list() return else: keyword = self.args[0].replace('-', '_') self.print_advice(keyword) freeipa-3.3.4/ipaserver/install/0000775000175000017500000000000012271663206016155 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/install/adtrustinstance.py0000664000175000017500000010631112271663206021744 0ustar mkosekmkosek# Authors: Sumit Bose # # Copyright (C) 2011 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 . # import os import errno import ldap import tempfile import uuid import string import struct import re from ipaserver.install import service from ipaserver.install import installutils from ipaserver.install.dsinstance import realm_to_serverid from ipaserver.install.bindinstance import get_rr, add_rr, del_rr, \ dns_zone_exists from ipalib import errors, api from ipalib.util import normalize_zone from ipapython.dn import DN from ipapython import sysrestore from ipapython import ipautil from ipapython.ipa_log_manager import * from ipapython import services as ipaservices import ipaclient.ipachangeconf ALLOWED_NETBIOS_CHARS = string.ascii_uppercase + string.digits SELINUX_WARNING = """ WARNING: could not set selinux boolean(s) %(var)s to true. The adtrust service may not function correctly until this boolean is successfully change with the command: /usr/sbin/setsebool -P %(var)s true Try updating the policycoreutils and selinux-policy packages. """ UPGRADE_ERROR = """ Entry %(dn)s does not exist. This means upgrade from IPA 2.x to 3.x did not went well and required S4U2Proxy configuration was not set up properly. Please run ipa-ldap-updater manually and re-run ipa-adtrust-instal again afterwards. """ def check_inst(): for smbfile in ['/usr/sbin/smbd', '/usr/bin/net']: if not os.path.exists(smbfile): print "%s was not found on this system" % smbfile print "Please install the 'samba' packages and " \ "start the installation again" return False #TODO: Add check for needed samba4 libraries return True def ipa_smb_conf_exists(): try: conf_fd = open('/etc/samba/smb.conf', 'r') except IOError, err: if err.errno == errno.ENOENT: return False lines = conf_fd.readlines() conf_fd.close() for line in lines: if line.startswith('### Added by IPA Installer ###'): return True return False def check_netbios_name(s): # NetBIOS names may not be longer than 15 allowed characters if not s or len(s) > 15 or \ ''.join([c for c in s if c not in ALLOWED_NETBIOS_CHARS]): return False return True def make_netbios_name(s): return ''.join([c for c in s.split('.')[0].upper() \ if c in ALLOWED_NETBIOS_CHARS])[:15] class ADTRUSTInstance(service.Service): ATTR_SID = "ipaNTSecurityIdentifier" ATTR_FLAT_NAME = "ipaNTFlatName" ATTR_GUID = "ipaNTDomainGUID" ATTR_FALLBACK_GROUP = "ipaNTFallbackPrimaryGroup" OBJC_USER = "ipaNTUserAttrs" OBJC_GROUP = "ipaNTGroupAttrs" OBJC_DOMAIN = "ipaNTDomainAttrs" FALLBACK_GROUP_NAME = u'Default SMB Group' def __init__(self, fstore=None): self.ip_address = None self.netbios_name = None self.reset_netbios_name = None self.no_msdcs = None self.add_sids = None self.smbd_user = None self.smb_dn_pwd = None self.trust_dn = None self.smb_dom_dn = None self.sub_dict = None self.rid_base = None self.secondary_rid_base = None self.fqdn = None self.host_netbios_name = None self.realm = None self.domain_name = None service.Service.__init__(self, "smb", service_desc="CIFS", dm_password=None, ldapi=True) if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') self.__setup_default_attributes() def __setup_default_attributes(self): """ This method setups default attributes that are either constants, or based on api.env attributes, such as realm, hostname or domain name. """ # Constants self.smb_conf = "/etc/samba/smb.conf" self.samba_keytab = "/etc/samba/samba.keytab" self.selinux_booleans = ["samba_portmapper"] self.cifs_hosts = [] # Values obtained from API.env self.fqdn = self.fqdn or api.env.host self.host_netbios_name = make_netbios_name(self.fqdn) self.realm = self.realm or api.env.realm self.domain_name = self.domain_name or api.env.domain self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm self.suffix = ipautil.realm_to_suffix(self.realm) self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \ realm_to_serverid(self.realm) # DN definitions self.trust_dn = DN(api.env.container_trusts, self.suffix) self.smb_dn = DN(('cn', 'adtrust agents'), ('cn', 'sysaccounts'), ('cn', 'etc'), self.suffix) self.smb_dom_dn = DN(('cn', self.domain_name), api.env.container_cifsdomains, self.suffix) self.cifs_agent = DN(('krbprincipalname', self.cifs_principal.lower()), api.env.container_service, self.suffix) def __gen_sid_string(self): sub_ids = struct.unpack(" size: self.print_msg("Primary and secondary RID base are too close. " "They have to differ at least by %d." % size) raise RuntimeError("RID bases too close.\n") # Modify the range # If the RID bases would cause overlap with some other range, # this will be detected by ipa-range-check DS plugin try: self.admin_conn.modify_s(local_range.dn, [(ldap.MOD_ADD, "ipaBaseRID", str(self.rid_base)), (ldap.MOD_ADD, "ipaSecondaryBaseRID", str(self.secondary_rid_base))]) except ldap.CONSTRAINT_VIOLATION, e: self.print_msg("Failed to add RID bases to the local range " "object:\n %s" % e[0]['info']) raise RuntimeError("Constraint violation.\n") except errors.NotFound as e: root_logger.critical("ID range of the local domain not found, " "define it and run again.") raise e def __reset_netbios_name(self): """ Set the NetBIOS domain name to a new value. """ self.print_msg("Reset NetBIOS domain name") try: self.admin_conn.modify_s(self.smb_dom_dn, [(ldap.MOD_REPLACE, self.ATTR_FLAT_NAME, self.netbios_name)]) except ldap.LDAPError: self.print_msg("Failed to reset the NetBIOS domain name") def __create_samba_domain_object(self): try: self.admin_conn.get_entry(self.smb_dom_dn) if self.reset_netbios_name: self.__reset_netbios_name() else : self.print_msg("Samba domain object already exists") return except errors.NotFound: pass for new_dn in (self.trust_dn, \ DN(('cn', 'ad'), self.trust_dn), \ DN(api.env.container_cifsdomains, self.suffix)): try: self.admin_conn.get_entry(new_dn) except errors.NotFound: try: name = new_dn[1].attr except Exception, e: self.print_msg('Cannot extract RDN attribute value from "%s": %s' % \ (new_dn, e)) return entry = self.admin_conn.make_entry( new_dn, objectclass=['nsContainer'], cn=[name]) self.admin_conn.add_entry(entry) entry = self.admin_conn.make_entry( self.smb_dom_dn, { 'objectclass': [self.OBJC_DOMAIN, "nsContainer"], 'cn': [self.domain_name], self.ATTR_FLAT_NAME: [self.netbios_name], self.ATTR_SID: [self.__gen_sid_string()], self.ATTR_GUID: [str(uuid.uuid4())], } ) #TODO: which MAY attributes do we want to set ? self.admin_conn.add_entry(entry) def __write_smb_conf(self): conf_fd = open(self.smb_conf, "w") conf_fd.write('### Added by IPA Installer ###\n') conf_fd.write('[global]\n') conf_fd.write('config backend = registry\n') conf_fd.close() def __add_plugin_conf(self, name, plugin_cn, ldif_file): """ Add directory server plugin configuration if it not already exists. """ try: plugin_dn = DN(('cn', plugin_cn), ('cn', 'plugins'), ('cn', 'config')) self.admin_conn.get_entry(plugin_dn) self.print_msg('%s plugin already configured, nothing to do' % name) except errors.NotFound: try: self._ldap_mod(ldif_file, self.sub_dict) except Exception: pass def __add_cldap_module(self): """ Add cldap directory server plugin configuration if it not already exists. """ self.__add_plugin_conf('CLDAP', 'ipa_cldap', 'ipa-cldap-conf.ldif') def __add_sidgen_module(self): """ Add sidgen directory server plugin configuration and the related task if they not already exist. """ self.__add_plugin_conf('Sidgen', 'IPA SIDGEN', 'ipa-sidgen-conf.ldif') self.__add_plugin_conf('Sidgen task', 'ipa-sidgen-task', 'ipa-sidgen-task-conf.ldif') def __add_sids(self): """ Add SIDs for existing users and groups """ try: self._ldap_mod("ipa-sidgen-task-run.ldif", self.sub_dict) except: pass def __add_extdom_module(self): """ Add directory server configuration for the extdom extended operation if it not already exists. """ self.__add_plugin_conf('Extdom', 'ipa_extdom_extop', 'ipa-extdom-extop-conf.ldif') def __add_s4u2proxy_target(self): """ Add CIFS principal to S4U2Proxy target """ targets_dn = DN(('cn', 'ipa-cifs-delegation-targets'), ('cn', 's4u2proxy'), ('cn', 'etc'), self.suffix) try: current = self.admin_conn.get_entry(targets_dn) members = current.get('memberPrincipal', []) if not(self.cifs_principal in members): current["memberPrincipal"] = members + [self.cifs_principal] self.admin_conn.update_entry(targets_dn, current) else: self.print_msg('cifs principal already targeted, nothing to do.') except errors.NotFound: self.print_msg(UPGRADE_ERROR % dict(dn=targets_dn)) def __write_smb_registry(self): template = os.path.join(ipautil.SHARE_DIR, "smb.conf.template") conf = ipautil.template_file(template, self.sub_dict) [tmp_fd, tmp_name] = tempfile.mkstemp() os.write(tmp_fd, conf) os.close(tmp_fd) args = ["/usr/bin/net", "conf", "import", tmp_name] try: ipautil.run(args) finally: os.remove(tmp_name) def __setup_principal(self): try: api.Command.service_add(unicode(self.cifs_principal)) # Add the principal to the 'adtrust agents' group # as 389-ds only operates with GroupOfNames, we have to use # the principal's proper dn as defined in self.cifs_agent try: current = self.admin_conn.get_entry(self.smb_dn) members = current.get('member', []) if not(self.cifs_agent in members): current["member"] = members + [self.cifs_agent] self.admin_conn.update_entry(self.smb_dn, current) except errors.NotFound: entry = self.admin_conn.make_entry( self.smb_dn, objectclass=["top", "GroupOfNames"], cn=[self.smb_dn['cn']], member=[self.cifs_agent], ) self.admin_conn.add_entry(entry) except Exception: # CIFS principal already exists, it is not the first time # adtrustinstance is managed # That's fine, we we'll re-extract the key again. pass self.clean_samba_keytab() try: ipautil.run(["ipa-getkeytab", "--server", self.fqdn, "--principal", self.cifs_principal, "-k", self.samba_keytab]) except ipautil.CalledProcessError: root_logger.critical("Failed to add key for %s" % self.cifs_principal) def clean_samba_keytab(self): if os.path.exists(self.samba_keytab): try: ipautil.run(["ipa-rmkeytab", "--principal", self.cifs_principal, "-k", self.samba_keytab]) except ipautil.CalledProcessError, e: if e.returncode != 5: root_logger.critical("Failed to remove old key for %s" % self.cifs_principal) def srv_rec(self, host, port, prio): return "%(prio)d 100 %(port)d %(host)s" % dict(host=host,prio=prio,port=port) def __add_dns_service_records(self): """ Add DNS service records for Windows if DNS is enabled and the DNS zone is managed. If there are already service records for LDAP and Kerberos their values are used. Otherwise default values are used. """ zone = self.domain_name host, host_domain = self.fqdn.split(".", 1) if normalize_zone(zone) == normalize_zone(host_domain): host_in_rr = host else: host_in_rr = normalize_zone(self.fqdn) priority = 0 ipa_srv_rec = ( ("_ldap._tcp", [self.srv_rec(host_in_rr, 389, priority)], 389), ("_kerberos._tcp", [self.srv_rec(host_in_rr, 88, priority)], 88), ("_kerberos._udp", [self.srv_rec(host_in_rr, 88, priority)], 88), ) win_srv_suffix = (".Default-First-Site-Name._sites.dc._msdcs", ".dc._msdcs") err_msg = None if self.no_msdcs: err_msg = '--no-msdcs was given, special DNS service records ' \ 'are not added to local DNS server' else: ret = api.Command['dns_is_enabled']() if not ret['result']: err_msg = "DNS management was not enabled at install time." else: if not dns_zone_exists(zone): err_msg = "DNS zone %s cannot be managed " \ "as it is not defined in IPA" % zone if err_msg: self.print_msg(err_msg) self.print_msg("Add the following service records to your DNS " \ "server for DNS zone %s: " % zone) for srv in ipa_srv_rec: for suff in win_srv_suffix: self.print_msg(" - %s%s" % (srv[0], suff)) return for (srv, rdata, port) in ipa_srv_rec: cifs_rdata = list() for fqdn in self.cifs_hosts: cifs_srv = self.srv_rec(fqdn, port, priority) cifs_rdata.append(cifs_srv) cifs_rdata.extend(rdata) for suff in win_srv_suffix: win_srv = srv+suff win_rdata = get_rr(zone, win_srv, "SRV") if win_rdata: for rec in win_rdata: del_rr(zone, win_srv, "SRV", rec) for rec in cifs_rdata: add_rr(zone, win_srv, "SRV", rec) def __configure_selinux_for_smbd(self): selinux = False try: if (os.path.exists('/usr/sbin/selinuxenabled')): ipautil.run(["/usr/sbin/selinuxenabled"]) selinux = True except ipautil.CalledProcessError: # selinuxenabled returns 1 if not enabled pass if selinux: # Don't assume all booleans are available sebools = [] for var in self.selinux_booleans: try: (stdout, stderr, returncode) = ipautil.run(["/usr/sbin/getsebool", var]) if stdout and not stderr and returncode == 0: self.backup_state(var, stdout.split()[2]) sebools.append(var) except: pass if sebools: bools = [var + "=true" for var in sebools] args = ["/usr/sbin/setsebool", "-P"] args.extend(bools); try: ipautil.run(args) except: self.print_msg(SELINUX_WARNING % dict(var=','.join(sebools))) def __mod_krb5_conf(self): """ Set dns_lookup_kdc to true and master_kdc in /etc/krb5.conf """ if not self.fqdn or not self.realm: self.print_msg("Cannot modify /etc/krb5.conf") krbconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer") krbconf.setOptionAssignment((" = ", " ")) krbconf.setSectionNameDelimiters(("[", "]")) krbconf.setSubSectionDelimiters(("{", "}")) krbconf.setIndent(("", " ", " ")) libopts = [{'name':'dns_lookup_kdc', 'type':'option', 'action':'set', 'value':'true'}] master_kdc = self.fqdn + ":88" kropts = [{'name':'master_kdc', 'type':'option', 'action':'set', 'value':master_kdc}] ropts = [{'name':self.realm, 'type':'subsection', 'action':'set', 'value':kropts}] opts = [{'name':'libdefaults', 'type':'section', 'action':'set', 'value':libopts}, {'name':'realms', 'type':'section', 'action':'set', 'value':ropts}] krbconf.changeConf("/etc/krb5.conf", opts) def __update_krb5_conf(self): """ Update /etc/krb5.conf if needed """ try: krb5conf = open("/etc/krb5.conf", 'r') except IOError, e: self.print_msg("Cannot open /etc/krb5.conf (%s)\n" % str(e)) return has_dns_lookup_kdc_true = False for line in krb5conf: if re.match("^\s*dns_lookup_kdc\s*=\s*[Tt][Rr][Uu][Ee]\s*$", line): has_dns_lookup_kdc_true = True break krb5conf.close() if not has_dns_lookup_kdc_true: self.__mod_krb5_conf() else: self.print_msg("'dns_lookup_kdc' already set to 'true', " "nothing to do.") def __check_replica(self): try: cifs_services = DN(api.env.container_service, self.suffix) # Search for cifs services which also belong to adtrust agents, these are our DCs res = self.admin_conn.get_entries(cifs_services, ldap.SCOPE_ONELEVEL, "(&(krbprincipalname=cifs/*@%s)(memberof=%s))" % (self.realm, str(self.smb_dn))) if len(res) > 1: # there are other CIFS services defined, we are not alone for entry in res: managedBy = entry.single_value('managedBy', None) if managedBy: fqdn = DN(managedBy)['fqdn'] if fqdn != unicode(self.fqdn): # this is CIFS service of a different host in our # REALM, we need to remember it to announce via # SRV records for _msdcs self.cifs_hosts.append(fqdn.split(".")[0]) except Exception, e: root_logger.critical("Checking replicas for cifs principals failed with error '%s'" % e) def __enable_compat_tree(self): try: compat_plugin_dn = DN("cn=Schema Compatibility,cn=plugins,cn=config") lookup_nsswitch_name = "schema-compat-lookup-nsswitch" for config in (("cn=users", "user"), ("cn=groups", "group")): entry_dn = DN(config[0], compat_plugin_dn) current = self.admin_conn.get_entry(entry_dn) lookup_nsswitch = current.get(lookup_nsswitch_name, []) if not(config[1] in lookup_nsswitch): current[lookup_nsswitch_name] = [config[1]] self.admin_conn.update_entry(entry_dn, current) except Exception, e: root_logger.critical("Enabling nsswitch support in slapi-nis failed with error '%s'" % e) def __start(self): try: self.start() ipaservices.service('winbind').start() except: root_logger.critical("CIFS services failed to start") def __stop(self): self.backup_state("running", self.is_running()) try: ipaservices.service('winbind').stop() self.stop() except: pass def __restart_dirsrv(self): try: ipaservices.knownservices.dirsrv.restart() except: pass def __enable(self): self.backup_state("enabled", self.is_enabled()) # 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) except (ldap.ALREADY_EXISTS, errors.DuplicateEntry), e: root_logger.info("ADTRUST Service startup entry already exists.") try: self.ldap_enable('EXTID', self.fqdn, self.dm_password, \ self.suffix) except (ldap.ALREADY_EXISTS, errors.DuplicateEntry), e: root_logger.info("EXTID Service startup entry already exists.") def __setup_sub_dict(self): self.sub_dict = dict(REALM = self.realm, SUFFIX = self.suffix, NETBIOS_NAME = self.netbios_name, HOST_NETBIOS_NAME = self.host_netbios_name, SMB_DN = self.smb_dn, LDAPI_SOCKET = self.ldapi_socket, FQDN = self.fqdn) def setup(self, fqdn, ip_address, realm_name, domain_name, netbios_name, reset_netbios_name, rid_base, secondary_rid_base, no_msdcs=False, add_sids=False, smbd_user="samba", enable_compat=False): self.fqdn = fqdn self.ip_address = ip_address self.realm = realm_name self.domain_name = domain_name self.netbios_name = netbios_name self.reset_netbios_name = reset_netbios_name self.rid_base = rid_base self.secondary_rid_base = secondary_rid_base self.no_msdcs = no_msdcs self.add_sids = add_sids self.enable_compat = enable_compat self.smbd_user = smbd_user # Setup constants and attributes derived from the values above self.__setup_default_attributes() self.__setup_sub_dict() def find_local_id_range(self): self.ldap_connect() if self.admin_conn.get_entries( DN(api.env.container_ranges, self.suffix), ldap.SCOPE_ONELEVEL, "(objectclass=ipaDomainIDRange)"): return try: entry = self.admin_conn.get_entry( DN(('cn', 'admins'), api.env.container_group, self.suffix)) except errors.NotFound: raise ValueError("No local ID range and no admins group found.\n" \ "Add local ID range manually and try again!") base_id = int(entry.single_value('gidNumber')) id_range_size = 200000 id_filter = "(&" \ "(|(objectclass=posixAccount)" \ "(objectclass=posixGroup)" \ "(objectclass=ipaIDObject))" \ "(|(uidNumber<=%d)(uidNumber>=%d)" \ "(gidNumber<=%d)(gidNumner>=%d)))" % \ ((base_id - 1), (base_id + id_range_size), (base_id - 1), (base_id + id_range_size)) if self.admin_conn.get_entries(DN(('cn', 'accounts'), self.suffix), ldap.SCOPE_SUBTREE, id_filter): raise ValueError("There are objects with IDs out of the expected" \ "range.\nAdd local ID range manually and try " \ "again!") entry = self.admin_conn.make_entry( DN( ('cn', ('%s_id_range' % self.realm)), api.env.container_ranges, self.suffix), objectclass=['ipaDomainIDRange'], cn=['%s_id_range' % self.realm], ipaBaseID=[str(base_id)], ipaIDRangeSize=[str(id_range_size)], ) self.admin_conn.add_entry(entry) def create_instance(self): self.ldap_connect() self.step("stopping smbd", self.__stop) self.step("creating samba domain object", \ self.__create_samba_domain_object) self.step("creating samba config registry", self.__write_smb_registry) self.step("writing samba config file", self.__write_smb_conf) self.step("adding cifs Kerberos principal", self.__setup_principal) self.step("check for cifs services defined on other replicas", self.__check_replica) self.step("adding cifs principal to S4U2Proxy targets", self.__add_s4u2proxy_target) self.step("adding admin(group) SIDs", self.__add_admin_sids) self.step("adding RID bases", self.__add_rid_bases) self.step("updating Kerberos config", self.__update_krb5_conf) self.step("activating CLDAP plugin", self.__add_cldap_module) self.step("activating sidgen plugin and task", self.__add_sidgen_module) self.step("activating extdom plugin", self.__add_extdom_module) self.step("configuring smbd to start on boot", self.__enable) self.step("adding special DNS service records", \ self.__add_dns_service_records) if self.enable_compat: self.step("enabling trusted domains support for older clients via Schema Compatibility plugin", self.__enable_compat_tree) self.step("restarting Directory Server to take MS PAC and LDAP plugins changes into account", \ self.__restart_dirsrv) self.step("adding fallback group", self.__add_fallback_group) self.step("setting SELinux booleans", \ self.__configure_selinux_for_smbd) self.step("starting CIFS services", self.__start) if self.add_sids: self.step("adding SIDs to existing users and groups", self.__add_sids) self.start_creation(show_service_name=False) def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) # Call restore_state so that we do not leave mess in the statestore # Otherwise this does nothing self.restore_state("running") self.restore_state("enabled") # Always try to stop and disable smb service, since we do not leave # working configuration after uninstall try: self.stop() self.disable() except: pass # Since we do not guarantee restoring back to working samba state, # we should not restore smb.conf # Restore the state of affected selinux booleans for var in self.selinux_booleans: sebool_state = self.restore_state(var) if not sebool_state is None: try: ipautil.run(["/usr/sbin/setsebool", "-P", var, sebool_state]) except: self.print_msg(SELINUX_WARNING % dict(var=var)) # Remove samba's credentials cache krb5cc_samba = '/var/run/samba/krb5cc_samba' installutils.remove_file(krb5cc_samba) # Remove samba's configuration file installutils.remove_file(self.smb_conf) # Remove samba's persistent and temporary tdb files tdb_files = [tdb_file for tdb_file in os.listdir("/var/lib/samba/") if tdb_file.endswith(".tdb")] for tdb_file in tdb_files: installutils.remove_file(tdb_file) # Remove our keys from samba's keytab self.clean_samba_keytab() freeipa-3.3.4/ipaserver/install/__init__.py0000664000175000017500000000144312271663206020270 0ustar mkosekmkosek# Authors: Karl MacMillan # see inline # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # freeipa-3.3.4/ipaserver/install/replication.py0000664000175000017500000016251312271663206021050 0ustar mkosekmkosek# Authors: Karl MacMillan # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import time import datetime import sys import os import ldap from ipalib import api, errors from ipapython import services as ipaservices from ipapython.ipa_log_manager import * from ipapython import ipautil, dogtag, ipaldap from ipapython.dn import DN CACERT = "/etc/ipa/ca.crt" # the default container used by AD for user entries WIN_USER_CONTAINER = DN(('cn', 'Users')) # the default container used by IPA for user entries IPA_USER_CONTAINER = DN(('cn', 'users'), ('cn', 'accounts')) PORT = 636 TIMEOUT = 120 REPL_MAN_DN = DN(('cn', 'replication manager'), ('cn', 'config')) DNA_DN = DN(('cn', 'Posix IDs'), ('cn', 'Distributed Numeric Assignment Plugin'), ('cn', 'plugins'), ('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 # List of attributes that are not updated on empty replication STRIP_ATTRS = ('modifiersName', 'modifyTimestamp', 'internalModifiersName', 'internalModifyTimestamp') def replica_conn_check(master_host, host_name, realm, check_ca, dogtag_master_ds_port, admin_password=None): """ Check the ports used by the replica both locally and remotely to be sure that replication will work. Does not return a value, will sys.exit() on failure. """ print "Run connection check to master" args = ["/usr/sbin/ipa-replica-conncheck", "--master", master_host, "--auto-master-check", "--realm", realm, "--principal", "admin", "--hostname", host_name] nolog=tuple() if admin_password: args.extend(["--password", admin_password]) nolog=(admin_password,) if check_ca and dogtag_master_ds_port == dogtag.Dogtag9Constants.DS_PORT: args.append('--check-ca') (stdin, stderr, returncode) = ipautil.run( args, raiseonerr=False, capture_output=False, nolog=nolog) if returncode != 0: sys.exit("Connection check failed!" + "\nPlease fix your network settings according to error messages above." + "\nIf the check results are not valid it can be skipped with --skip-conncheck parameter.") else: print "Connection check OK" def enable_replication_version_checking(hostname, realm, dirman_passwd): """ Check the replication version checking plugin. If it is not enabled then enable it and restart 389-ds. If it is enabled the do nothing. """ conn = ipaldap.IPAdmin(hostname, realm=realm, ldapi=True) if dirman_passwd: conn.do_simple_bind(bindpw=dirman_passwd) else: conn.do_sasl_gssapi_bind() entry = conn.get_entry(DN(('cn', 'IPA Version Replication'), ('cn', 'plugins'), ('cn', 'config'))) if entry.single_value('nsslapd-pluginenabled', None) == 'off': conn.modify_s(entry.dn, [(ldap.MOD_REPLACE, 'nsslapd-pluginenabled', 'on')]) conn.unbind() serverid = "-".join(realm.split(".")) ipaservices.knownservices.dirsrv.restart(instance_name=serverid) else: conn.unbind() def wait_for_task(conn, dn): """Check task status Task is complete when the nsTaskExitCode attr is set. :return: the task's return code """ assert isinstance(dn, DN) attrlist = [ 'nsTaskLog', 'nsTaskStatus', 'nsTaskExitCode', 'nsTaskCurrentItem', 'nsTaskTotalItems'] while True: entry = conn.get_entry(dn, attrlist) if entry.single_value('nsTaskExitCode', None): exit_code = int(entry.single_value('nsTaskExitCode')) break time.sleep(1) return exit_code def wait_for_entry(connection, entry, timeout=7200, attr='', quiet=True): """Wait for entry and/or attr to show up""" filter = "(objectclass=*)" attrlist = [] if attr: filter = "(%s=*)" % attr attrlist.append(attr) timeout += int(time.time()) dn = entry.dn if not quiet: sys.stdout.write("Waiting for %s %s:%s " % (connection, dn, attr)) sys.stdout.flush() entry = None while not entry and int(time.time()) < timeout: try: [entry] = connection.get_entries( dn, ldap.SCOPE_BASE, filter, attrlist) except errors.NotFound: pass # no entry yet except Exception, e: # badness print "\nError reading entry", dn, e break if not entry: if not quiet: sys.stdout.write(".") sys.stdout.flush() time.sleep(1) if not entry and int(time.time()) > timeout: print "\nwait_for_entry timeout for %s for %s" % (connection, dn) elif entry and not quiet: print "\nThe waited for entry is:", entry elif not entry: print "\nError: could not read entry %s from %s" % (dn, connection) class ReplicationManager(object): """Manage replication agreements between DS servers, and sync agreements with Windows servers""" def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=False, conn=None): self.hostname = hostname self.port = port self.dirman_passwd = dirman_passwd self.realm = realm self.starttls = starttls self.suffix = ipautil.realm_to_suffix(realm) self.need_memberof_fixup = False # The caller is allowed to pass in an existing IPAdmin connection. # Open a new one if not provided if conn is None: # If we are passed a password we'll use it as the DM password # otherwise we'll do a GSSAPI bind. if starttls: self.conn = ipaldap.IPAdmin( hostname, port=port, cacert=CACERT, protocol='ldap', start_tls=True) else: self.conn = ipaldap.IPAdmin(hostname, port=port, cacert=CACERT) if dirman_passwd: self.conn.do_simple_bind(bindpw=dirman_passwd) else: self.conn.do_sasl_gssapi_bind() else: self.conn = conn self.repl_man_passwd = dirman_passwd # these are likely constant, but you could change them # at runtime if you really want self.repl_man_dn = REPL_MAN_DN self.repl_man_cn = "replication manager" def _get_replica_id(self, conn, master_conn): """ Returns the replica ID which is unique for each backend. conn is the connection we are trying to get the replica ID for. master_conn is the master we are going to replicate with. """ # First see if there is already one set dn = self.replica_dn() assert isinstance(dn, DN) try: replica = conn.get_entry(dn) except errors.NotFound: pass else: if replica.single_value('nsDS5ReplicaId', None): return int(replica.single_value('nsDS5ReplicaId')) # Ok, either the entry doesn't exist or the attribute isn't set # so get it from the other master retval = -1 dn = DN(('cn','replication'),('cn','etc'), self.suffix) try: replica = master_conn.get_entry(dn) except errors.NotFound: root_logger.debug("Unable to retrieve nsDS5ReplicaId from remote server") raise else: if replica.single_value('nsDS5ReplicaId', None) is None: root_logger.debug("Unable to retrieve nsDS5ReplicaId from remote server") raise RuntimeError("Unable to retrieve nsDS5ReplicaId from remote server") # Now update the value on the master retval = int(replica.single_value('nsDS5ReplicaId')) mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaId', str(retval + 1))] try: master_conn.modify_s(dn, mod) except Exception, e: root_logger.debug("Problem updating nsDS5ReplicaID %s" % e) raise return retval def get_agreement_filter(self, agreement_types=None, host=None): """ Get an LDAP replication agreement filter with a possibility to filter the agreements by their type and a host """ if agreement_types is None: agreement_types = (IPA_REPLICA, WINSYNC) elif not isinstance(agreement_types, (list, tuple)): agreement_types = (agreement_types,) agreement_types_filters = [] if IPA_REPLICA in agreement_types: agreement_types_filters.append('(&(objectclass=nsds5ReplicationAgreement)(nsDS5ReplicaRoot=%s))' % self.suffix) if WINSYNC in agreement_types: agreement_types_filters.append('(objectclass=nsDSWindowsReplicationAgreement)') if len(agreement_types_filters) > 1: agreement_filter = '(|%s)' % ''.join(agreement_types_filters) else: agreement_filter = ''.join(agreement_types_filters) if host is not None: agreement_filter = '(&%s(nsDS5ReplicaHost=%s))' % (agreement_filter, host) return agreement_filter def find_replication_agreements(self): """ The replication agreements are stored in cn="$SUFFIX",cn=mapping tree,cn=config FIXME: Rather than failing with a read error if a user tries to read this it simply returns zero entries. We need to use GER to determine if we are allowed to read this to return a proper response. For now just return "No entries" even if the user may not be allowed to see them. """ filt = self.get_agreement_filter() try: ents = self.conn.get_entries( DN(('cn', 'mapping tree'), ('cn', 'config')), ldap.SCOPE_SUBTREE, filt) except errors.NotFound: ents = [] return ents def find_ipa_replication_agreements(self): """ The replication agreements are stored in cn="$SUFFIX",cn=mapping tree,cn=config Return the list of hosts we have replication agreements. """ filt = self.get_agreement_filter(IPA_REPLICA) try: ents = self.conn.get_entries( DN(('cn', 'mapping tree'), ('cn', 'config')), ldap.SCOPE_SUBTREE, filt) except errors.NotFound: ents = [] return ents def get_replication_agreement(self, hostname): """ The replication agreements are stored in cn="$SUFFIX",cn=mapping tree,cn=config Get the replication agreement for a specific host. Returns None if not found. """ filt = self.get_agreement_filter(host=hostname) try: entries = self.conn.get_entries( DN(('cn', 'mapping tree'), ('cn', 'config')), ldap.SCOPE_SUBTREE, filt) except errors.NotFound: return None if len(entries) == 0: return None else: return entries[0] # There can be only one def add_replication_manager(self, conn, dn, pw): """ Create a pseudo user to use for replication. """ assert isinstance(dn, DN) rdn_attr = dn[0].attr rdn_val = dn[0].value ent = conn.make_entry( dn, { 'objectclass': ["top", "person"], rdn_attr: [rdn_val], 'userpassword': [pw], 'sn': ["replication manager pseudo user"], } ) try: conn.add_entry(ent) except errors.DuplicateEntry: conn.modify_s(dn, [(ldap.MOD_REPLACE, "userpassword", pw)]) pass def delete_replication_manager(self, conn, dn=REPL_MAN_DN): assert isinstance(dn, DN) try: conn.delete_entry(dn) except errors.NotFound: pass def get_replica_type(self, master=True): if master: return "3" else: return "2" def replica_dn(self): return DN(('cn','replica'),('cn',self.suffix),('cn','mapping tree'),('cn','config')) def replica_config(self, conn, replica_id, replica_binddn): assert isinstance(replica_binddn, DN) dn = self.replica_dn() assert isinstance(dn, DN) try: entry = conn.get_entry(dn) managers = entry.get('nsDS5ReplicaBindDN') for m in managers: if replica_binddn == DN(m): return # Add the new replication manager mod = [(ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn)] conn.modify_s(dn, mod) # replication is already configured return except errors.NotFound: pass replica_type = self.get_replica_type() entry = conn.make_entry( dn, objectclass=["top", "nsds5replica", "extensibleobject"], cn=["replica"], nsds5replicaroot=[str(self.suffix)], nsds5replicaid=[str(replica_id)], nsds5replicatype=[replica_type], nsds5flags=["1"], nsds5replicabinddn=[replica_binddn], nsds5replicalegacyconsumer=["off"], ) conn.add_entry(entry) def setup_changelog(self, conn): ent = conn.get_entry( DN( ('cn', 'config'), ('cn', 'ldbm database'), ('cn', 'plugins'), ('cn', 'config')), ['nsslapd-directory']) dbdir = os.path.dirname(ent.single_value('nsslapd-directory', None)) entry = conn.make_entry( DN(('cn', 'changelog5'), ('cn', 'config')), { 'objectclass': ["top", "extensibleobject"], 'cn': ["changelog5"], 'nsslapd-changelogdir': [os.path.join(dbdir, "cldb")], } ) try: conn.add_entry(entry) except errors.DuplicateEntry: return def setup_chaining_backend(self, conn): chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config')) benamebase = "chaindb" urls = [self.to_ldap_url(conn)] cn = "" benum = 1 done = False while not done: try: cn = benamebase + str(benum) # e.g. localdb1 dn = DN(('cn', cn), chaindn) entry = conn.make_entry( dn, { 'objectclass': [ 'top', 'extensibleObject', 'nsBackendInstance'], 'cn': [cn], 'nsslapd-suffix': [str(self.suffix)], 'nsfarmserverurl': urls, 'nsmultiplexorbinddn': [self.repl_man_dn], 'nsmultiplexorcredentials': [self.repl_man_passwd], } ) self.conn.add_entry(entry) done = True except errors.DuplicateEntry: benum += 1 except errors.ExecutionError, e: print "Could not add backend entry " + dn, e raise return cn def to_ldap_url(self, conn): return "ldap://%s/" % ipautil.format_netloc(conn.host, conn.port) def setup_chaining_farm(self, conn): try: conn.modify_s(self.suffix, [(ldap.MOD_ADD, 'aci', [ "(targetattr = \"*\")(version 3.0; acl \"Proxied authorization for database links\"; allow (proxy) userdn = \"ldap:///%s\";)" % self.repl_man_dn ])]) except ldap.TYPE_OR_VALUE_EXISTS: root_logger.debug("proxy aci already exists in suffix %s on %s" % (self.suffix, conn.host)) def get_mapping_tree_entry(self): try: entries = self.conn.get_entries( DN(('cn', 'mapping tree'), ('cn', 'config')), ldap.SCOPE_ONELEVEL, "(cn=\"%s\")" % (self.suffix)) # TODO: Check we got only one entry return entries[0] except errors.NotFound: root_logger.debug( "failed to find mapping tree entry for %s", self.suffix) raise def enable_chain_on_update(self, bename): mtent = self.get_mapping_tree_entry() dn = mtent.dn plgent = self.conn.get_entry( DN(('cn', 'Multimaster Replication Plugin'), ('cn', 'plugins'), ('cn', 'config')), ['nsslapd-pluginPath']) path = plgent.single_value('nsslapd-pluginPath', None) mod = [(ldap.MOD_REPLACE, 'nsslapd-state', 'backend'), (ldap.MOD_ADD, 'nsslapd-backend', bename), (ldap.MOD_ADD, 'nsslapd-distribution-plugin', path), (ldap.MOD_ADD, 'nsslapd-distribution-funct', 'repl_chain_on_update')] try: self.conn.modify_s(dn, mod) except ldap.TYPE_OR_VALUE_EXISTS: root_logger.debug("chainOnUpdate already enabled for %s" % self.suffix) def setup_chain_on_update(self, other_conn): chainbe = self.setup_chaining_backend(other_conn) self.enable_chain_on_update(chainbe) def add_passsync_user(self, conn, password): pass_dn = DN(('uid', 'passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'), self.suffix) print "The user for the Windows PassSync service is %s" % pass_dn try: conn.get_entry(pass_dn) print "Windows PassSync entry exists, not resetting password" return except errors.NotFound: pass # The user doesn't exist, add it entry = conn.make_entry( pass_dn, objectclass=["account", "simplesecurityobject"], uid=["passsync"], userPassword=[password], ) conn.add_entry(entry) # Add it to the list of users allowed to bypass password policy extop_dn = DN(('cn', 'ipa_pwd_extop'), ('cn', 'plugins'), ('cn', 'config')) entry = conn.get_entry(extop_dn) pass_mgrs = entry.get('passSyncManagersDNs') if not pass_mgrs: pass_mgrs = [] if not isinstance(pass_mgrs, list): pass_mgrs = [pass_mgrs] pass_mgrs.append(pass_dn) mod = [(ldap.MOD_REPLACE, 'passSyncManagersDNs', pass_mgrs)] conn.modify_s(extop_dn, mod) # And finally grant it permission to write passwords mod = [(ldap.MOD_ADD, 'aci', ['(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Windows PassSync service can write passwords"; allow (write) userdn="ldap:///%s";)' % pass_dn])] try: conn.modify_s(self.suffix, mod) except ldap.TYPE_OR_VALUE_EXISTS: root_logger.debug("passsync aci already exists in suffix %s on %s" % (self.suffix, conn.host)) def setup_winsync_agmt(self, entry, win_subtree=None): if win_subtree is None: win_subtree = DN(WIN_USER_CONTAINER, self.ad_suffix) ds_subtree = DN(IPA_USER_CONTAINER, self.suffix) windomain = ipautil.suffix_to_realm(self.suffix) entry["objectclass"] = ["nsDSWindowsReplicationAgreement"] entry["nsds7WindowsReplicaSubtree"] = [win_subtree] entry["nsds7DirectoryReplicaSubtree"] = [ds_subtree] # for now, just sync users and ignore groups entry["nsds7NewWinUserSyncEnabled"] = ['true'] entry["nsds7NewWinGroupSyncEnabled"] = ['false'] entry["nsds7WindowsDomain"] = [windomain] def agreement_dn(self, hostname, master=None): """ IPA agreement use the same dn on both sides, dogtag does not. master is not used for IPA agreements but for dogtag it will tell which side we want. """ cn = "meTo%s" % (hostname) dn = DN(('cn', cn), self.replica_dn()) return (cn, dn) def setup_agreement(self, a_conn, b_hostname, port=389, repl_man_dn=None, repl_man_passwd=None, iswinsync=False, win_subtree=None, isgssapi=False, master=None): """ master is used to determine which side of the agreement we are creating. This is only needed for dogtag replication agreements which use a different name on each side. If master is None then isn't a dogtag replication agreement. """ if repl_man_dn is not None: assert isinstance(repl_man_dn, DN) cn, dn = self.agreement_dn(b_hostname, master=master) try: a_conn.get_entry(dn) return except errors.NotFound: pass entry = a_conn.make_entry( dn, objectclass=["nsds5replicationagreement"], cn=[cn], nsds5replicahost=[b_hostname], nsds5replicaport=[str(port)], nsds5replicatimeout=[str(TIMEOUT)], nsds5replicaroot=[str(self.suffix)], description=["me to %s" % b_hostname], ) if master is None: entry['nsDS5ReplicatedAttributeList'] = [ '(objectclass=*) $ EXCLUDE %s' % " ".join(EXCLUDES)] if isgssapi: entry['nsds5replicatransportinfo'] = ['LDAP'] entry['nsds5replicabindmethod'] = ['SASL/GSSAPI'] else: entry['nsds5replicabinddn'] = [repl_man_dn] entry['nsds5replicacredentials'] = [repl_man_passwd] entry['nsds5replicatransportinfo'] = ['TLS'] entry['nsds5replicabindmethod'] = ['simple'] if iswinsync: self.setup_winsync_agmt(entry, win_subtree) else: entry['nsds5ReplicaStripAttrs'] = [" ".join(STRIP_ATTRS)] a_conn.add_entry(entry) try: mod = [(ldap.MOD_ADD, 'nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE %s' % " ".join(TOTAL_EXCLUDES))] a_conn.modify_s(dn, mod) except ldap.LDAPError, e: # Apparently there are problems set the total list # Probably the master is an old 389-ds server, tell the caller # that we will have to set the memberof fixup task self.need_memberof_fixup = True wait_for_entry(a_conn, entry) def needs_memberof_fixup(self): return self.need_memberof_fixup def get_replica_principal_dns(self, a, b, retries): """ Get the DNs of the ldap principals we are going to convert to using GSSAPI replication. Arguments a and b are LDAP connections. retries is the number of attempts that should be made to find the entries. It could be that replication is slow. If successful this returns a tuple (dn_a, dn_b). If either of the DNs doesn't exist after the retries are exhausted an exception is raised. """ filter_a = '(krbprincipalname=ldap/%s@%s)' % (a.host, self.realm) filter_b = '(krbprincipalname=ldap/%s@%s)' % (b.host, self.realm) a_entry = None b_entry = None error_message = '' while (retries > 0 ): root_logger.info('Getting ldap service principals for conversion: %s and %s' % (filter_a, filter_b)) try: a_entry = b.get_entries(self.suffix, ldap.SCOPE_SUBTREE, filter=filter_a) except errors.NotFound: pass try: b_entry = a.get_entries(self.suffix, ldap.SCOPE_SUBTREE, filter=filter_b) except errors.NotFound: pass if a_entry and b_entry: root_logger.debug('Found both principals.') break # One or both is missing, force sync again if not a_entry: root_logger.debug('Unable to find entry for %s on %s' % (filter_a, str(b))) self.force_sync(a, b.host) cn, dn = self.agreement_dn(b.host) haserror, error_message = self.wait_for_repl_update(a, dn, 60) if not b_entry: root_logger.debug('Unable to find entry for %s on %s' % (filter_b, str(a))) self.force_sync(b, a.host) cn, dn = self.agreement_dn(a.host) haserror, error_message = self.wait_for_repl_update(b, dn, 60) retries -= 1 if not a_entry or not b_entry: error = 'One of the ldap service principals is missing. ' \ 'Replication agreement cannot be converted.' if error_message: error += '\nReplication error message: %s' % error_message raise RuntimeError(error) return (a_entry[0].dn, b_entry[0].dn) def setup_krb_princs_as_replica_binddns(self, a, b): """ Search the appropriate principal names so we can get the correct DNs to store in the replication agreements. Then modify the replica object to allow these DNs to act as replication agents. """ rep_dn = self.replica_dn() assert isinstance(rep_dn, DN) (a_dn, b_dn) = self.get_replica_principal_dns(a, b, retries=100) assert isinstance(a_dn, DN) assert isinstance(b_dn, DN) # Add kerberos principal DNs as valid bindDNs for replication try: mod = [(ldap.MOD_ADD, "nsds5replicabinddn", b_dn)] a.modify_s(rep_dn, mod) except ldap.TYPE_OR_VALUE_EXISTS: pass try: mod = [(ldap.MOD_ADD, "nsds5replicabinddn", a_dn)] b.modify_s(rep_dn, mod) except ldap.TYPE_OR_VALUE_EXISTS: pass def gssapi_update_agreements(self, a, b): self.setup_krb_princs_as_replica_binddns(a, b) #change replication agreements to connect to other host using GSSAPI mod = [(ldap.MOD_REPLACE, "nsds5replicatransportinfo", "LDAP"), (ldap.MOD_REPLACE, "nsds5replicabindmethod", "SASL/GSSAPI"), (ldap.MOD_DELETE, "nsds5replicabinddn", None), (ldap.MOD_DELETE, "nsds5replicacredentials", None)] cn, a_ag_dn = self.agreement_dn(b.host) a.modify_s(a_ag_dn, mod) cn, b_ag_dn = self.agreement_dn(a.host) b.modify_s(b_ag_dn, mod) # Finally remove the temporary replication manager user try: a.delete_entry(self.repl_man_dn) except errors.NotFound: pass try: b.delete_entry(self.repl_man_dn) except errors.NotFound: pass def delete_agreement(self, hostname, dn=None): """ Delete a replication agreement. @hostname: the hostname of the agreement to remove @dn: optional dn of the agreement to remove For IPA agreements we can easily calculate the DN of the agreement to remove. Dogtag agreements are another matter, its agreement names depend entirely on where it is created. In this case it is better to pass the DN in directly. """ if dn is None: cn, dn = self.agreement_dn(hostname) return self.conn.delete_entry(dn) def delete_referral(self, hostname): dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config')) # TODO: should we detect proto/port somehow ? mod = [(ldap.MOD_DELETE, 'nsslapd-referral', 'ldap://%s/%s' % (ipautil.format_netloc(hostname, 389), self.suffix))] try: self.conn.modify_s(dn, mod) except Exception, e: root_logger.debug("Failed to remove referral value: %s" % str(e)) def check_repl_init(self, conn, agmtdn, start): done = False hasError = 0 attrlist = ['cn', 'nsds5BeginReplicaRefresh', 'nsds5replicaUpdateInProgress', 'nsds5ReplicaLastInitStatus', 'nsds5ReplicaLastInitStart', 'nsds5ReplicaLastInitEnd'] entry = conn.get_entry(agmtdn, attrlist) if not entry: print "Error reading status from agreement", agmtdn hasError = 1 else: refresh = entry.single_value('nsds5BeginReplicaRefresh', None) inprogress = entry.single_value('nsds5replicaUpdateInProgress', None) status = entry.single_value('nsds5ReplicaLastInitStatus', None) if not refresh: # done - check status if not status: print "No status yet" elif status.find("replica busy") > -1: print "[%s] reports: Replica Busy! Status: [%s]" % (conn.host, status) done = True hasError = 2 elif status.find("Total update succeeded") > -1: print "\nUpdate succeeded" done = True elif inprogress.lower() == 'true': print "\nUpdate in progress yet not in progress" else: print "\n[%s] reports: Update failed! Status: [%s]" % (conn.host, status) hasError = 1 done = True else: now = datetime.datetime.now() d = now - start sys.stdout.write('\r') sys.stdout.write("Update in progress, %d seconds elapsed" % int(d.total_seconds())) sys.stdout.flush() return done, hasError def check_repl_update(self, conn, agmtdn): done = False hasError = 0 error_message = '' attrlist = ['cn', 'nsds5replicaUpdateInProgress', 'nsds5ReplicaLastUpdateStatus', 'nsds5ReplicaLastUpdateStart', 'nsds5ReplicaLastUpdateEnd'] entry = conn.get_entry(agmtdn, attrlist) if not entry: print "Error reading status from agreement", agmtdn hasError = 1 else: inprogress = entry.single_value('nsds5replicaUpdateInProgress', None) status = entry.single_value('nsds5ReplicaLastUpdateStatus', None) try: start = int(entry.single_value('nsds5ReplicaLastUpdateStart')) except (ValueError, TypeError, KeyError): start = 0 try: end = int(entry.single_value('nsds5ReplicaLastUpdateEnd')) except (ValueError, TypeError, KeyError): end = 0 # incremental update is done if inprogress is false and end >= start done = inprogress and inprogress.lower() == 'false' and start <= end root_logger.info("Replication Update in progress: %s: status: %s: start: %d: end: %d" % (inprogress, status, start, end)) if status: # always check for errors # status will usually be a number followed by a string # number != 0 means error rc, msg = status.split(' ', 1) if rc != '0': hasError = 1 error_message = msg done = True return done, hasError, error_message def wait_for_repl_init(self, conn, agmtdn): done = False haserror = 0 start = datetime.datetime.now() while not done and not haserror: time.sleep(1) # give it a few seconds to get going done, haserror = self.check_repl_init(conn, agmtdn, start) print "" return haserror def wait_for_repl_update(self, conn, agmtdn, maxtries=600): done = False haserror = 0 error_message = '' while not done and not haserror and maxtries > 0: time.sleep(1) # give it a few seconds to get going done, haserror, error_message = self.check_repl_update(conn, agmtdn) maxtries -= 1 if maxtries == 0: # too many tries print "Error: timeout: could not determine agreement status: please check your directory server logs for possible errors" haserror = 1 return haserror, error_message def start_replication(self, conn, hostname=None, master=None): print "Starting replication, please wait until this has completed." if hostname == None: hostname = self.conn.host cn, dn = self.agreement_dn(hostname, master) mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start')] conn.modify_s(dn, mod) return self.wait_for_repl_init(conn, dn) def basic_replication_setup(self, conn, replica_id, repldn, replpw): assert isinstance(repldn, DN) if replpw is not None: self.add_replication_manager(conn, repldn, replpw) self.replica_config(conn, replica_id, repldn) self.setup_changelog(conn) def setup_replication(self, r_hostname, r_port=389, r_sslport=636, r_binddn=None, r_bindpw=None, is_cs_replica=False, local_port=None): assert isinstance(r_binddn, DN) if local_port is None: local_port = r_port # note - there appears to be a bug in python-ldap - it does not # allow connections using two different CA certs r_conn = ipaldap.IPAdmin( r_hostname, port=r_port, cacert=CACERT, protocol='ldap', start_tls=True) if r_bindpw: r_conn.do_simple_bind(binddn=r_binddn, bindpw=r_bindpw) else: r_conn.do_sasl_gssapi_bind() #Setup the first half l_id = self._get_replica_id(self.conn, r_conn) self.basic_replication_setup(self.conn, l_id, self.repl_man_dn, self.repl_man_passwd) # Now setup the other half r_id = self._get_replica_id(r_conn, r_conn) self.basic_replication_setup(r_conn, r_id, self.repl_man_dn, self.repl_man_passwd) if is_cs_replica: self.setup_agreement(r_conn, self.conn.host, port=local_port, repl_man_dn=self.repl_man_dn, repl_man_passwd=self.repl_man_passwd, master=False) self.setup_agreement(self.conn, r_hostname, port=r_port, repl_man_dn=self.repl_man_dn, repl_man_passwd=self.repl_man_passwd, master=True) else: self.setup_agreement(r_conn, self.conn.host, port=local_port, repl_man_dn=self.repl_man_dn, repl_man_passwd=self.repl_man_passwd) self.setup_agreement(self.conn, r_hostname, port=r_port, repl_man_dn=self.repl_man_dn, repl_man_passwd=self.repl_man_passwd) #Finally start replication ret = self.start_replication(r_conn, master=False) if ret != 0: raise RuntimeError("Failed to start replication") def setup_winsync_replication(self, ad_dc_name, ad_binddn, ad_pwd, passsync_pw, ad_subtree, cacert=CACERT): self.ad_suffix = "" try: # Validate AD connection ad_conn = ldap.initialize('ldap://%s' % ipautil.format_netloc(ad_dc_name)) # the next one is to workaround bugs arounf opendalp libs+NSS db # we need to first specify the OPT_X_TLS_CACERTFILE and _after_ # that initialize the context to prevent TLS connection errors: # https://bugzilla.redhat.com/show_bug.cgi?id=800787 ad_conn.set_option(ldap.OPT_X_TLS_CACERTFILE, cacert) ad_conn.set_option(ldap.OPT_X_TLS_NEWCTX, 0) ad_conn.start_tls_s() ad_conn.simple_bind_s(str(ad_binddn), ad_pwd) res = ad_conn.search_s("", ldap.SCOPE_BASE, '(objectClass=*)', ['defaultNamingContext']) for dn,entry in res: if dn == "": self.ad_suffix = entry['defaultNamingContext'][0] root_logger.info("AD Suffix is: %s" % self.ad_suffix) if self.ad_suffix == "": raise RuntimeError("Failed to lookup AD's Ldap suffix") ad_conn.unbind_s() del ad_conn except Exception, e: root_logger.info("Failed to connect to AD server %s" % ad_dc_name) root_logger.info("The error was: %s" % e) raise RuntimeError("Failed to setup winsync replication") # Setup the only half. # there is no other side to get a replica ID from # So we generate one locally replica_id = self._get_replica_id(self.conn, self.conn) self.basic_replication_setup(self.conn, replica_id, self.repl_man_dn, self.repl_man_passwd) #now add a passync user allowed to access the AD server self.add_passsync_user(self.conn, passsync_pw) self.setup_agreement(self.conn, ad_dc_name, repl_man_dn=ad_binddn, repl_man_passwd=ad_pwd, iswinsync=True, win_subtree=ad_subtree) root_logger.info("Added new sync agreement, waiting for it to become ready . . .") cn, dn = self.agreement_dn(ad_dc_name) self.wait_for_repl_update(self.conn, dn, 300) root_logger.info("Agreement is ready, starting replication . . .") # Add winsync replica to the public DIT dn = DN(('cn',ad_dc_name),('cn','replicas'),('cn','ipa'),('cn','etc'), self.suffix) entry = self.conn.make_entry( dn, objectclass=["nsContainer", "ipaConfigObject"], cn=[ad_dc_name], ipaConfigString=["winsync:%s" % self.hostname], ) try: self.conn.add_entry(entry) except Exception, e: root_logger.info("Failed to create public entry for winsync replica") #Finally start replication ret = self.start_replication(self.conn, ad_dc_name) if ret != 0: raise RuntimeError("Failed to start replication") def convert_to_gssapi_replication(self, r_hostname, r_binddn, r_bindpw): r_conn = ipaldap.IPAdmin(r_hostname, port=PORT, cacert=CACERT) if r_bindpw: r_conn.do_simple_bind(binddn=r_binddn, bindpw=r_bindpw) else: r_conn.do_sasl_gssapi_bind() # First off make sure servers are in sync so that both KDCs # have all principals and their passwords and can release # the right tickets. We do this by force pushing all our changes self.force_sync(self.conn, r_hostname) cn, dn = self.agreement_dn(r_hostname) self.wait_for_repl_update(self.conn, dn, 300) # now in the opposite direction self.force_sync(r_conn, self.hostname) cn, dn = self.agreement_dn(self.hostname) self.wait_for_repl_update(r_conn, dn, 300) # now that directories are in sync, # change the agreements to use GSSAPI self.gssapi_update_agreements(self.conn, r_conn) def setup_gssapi_replication(self, r_hostname, r_binddn=None, r_bindpw=None): """ Directly sets up GSSAPI replication. Only usable to connect 2 existing replicas (needs existing kerberos principals) """ # note - there appears to be a bug in python-ldap - it does not # allow connections using two different CA certs r_conn = ipaldap.IPAdmin(r_hostname, port=PORT, cacert=CACERT) if r_bindpw: r_conn.do_simple_bind(binddn=r_binddn, bindpw=r_bindpw) else: r_conn.do_sasl_gssapi_bind() # Allow krb principals to act as replicas self.setup_krb_princs_as_replica_binddns(self.conn, r_conn) # Create mutual replication agreementsausiung SASL/GSSAPI self.setup_agreement(self.conn, r_hostname, isgssapi=True) self.setup_agreement(r_conn, self.conn.host, isgssapi=True) def initialize_replication(self, dn, conn): mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start'), (ldap.MOD_REPLACE, 'nsds5ReplicaEnabled', 'on')] try: conn.modify_s(dn, mod) except ldap.ALREADY_EXISTS: return def force_sync(self, conn, hostname): newschedule = '2358-2359 0' filter = self.get_agreement_filter(host=hostname) try: entries = conn.get_entries( DN(('cn', 'config')), ldap.SCOPE_SUBTREE, filter) except errors.NotFound: root_logger.error("Unable to find replication agreement for %s" % (hostname)) raise RuntimeError("Unable to proceed") if len(entries) > 1: root_logger.error("Found multiple agreements for %s" % hostname) root_logger.error("Using the first one only (%s)" % entries[0].dn) dn = entries[0].dn schedule = entries[0].single_value('nsds5replicaupdateschedule', None) # On the remote chance of a match. We force a synch to happen right # now by setting the schedule to something and quickly removing it. if schedule is not None: if newschedule == schedule: newschedule = '2358-2359 1' root_logger.info("Setting agreement %s schedule to %s to force synch" % (dn, newschedule)) mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaUpdateSchedule', [ newschedule ])] conn.modify_s(dn, mod) time.sleep(1) root_logger.info("Deleting schedule %s from agreement %s" % (newschedule, dn)) mod = [(ldap.MOD_DELETE, 'nsDS5ReplicaUpdateSchedule', None)] conn.modify_s(dn, mod) def get_agreement_type(self, hostname): cn, dn = self.agreement_dn(hostname) entry = self.conn.get_entry(dn) objectclass = entry.get("objectclass") for o in objectclass: if o.lower() == "nsdswindowsreplicationagreement": return WINSYNC return IPA_REPLICA def replica_cleanup(self, replica, realm, force=False): """ This function removes information about the replica in parts of the shared tree that expose it, so clients stop trying to use this replica. """ err = None if replica == self.hostname: raise RuntimeError("Can't cleanup self") # delete master kerberos key and all its svc principals try: entries = self.conn.get_entries( self.suffix, ldap.SCOPE_SUBTREE, filter='(krbprincipalname=*/%s@%s)' % (replica, realm)) if entries: entries.sort(key=len, reverse=True) for entry in entries: self.conn.delete_entry(entry) except errors.NotFound: pass except Exception, e: if not force: raise e else: err = e # remove replica memberPrincipal from s4u2proxy configuration dn1 = DN(('cn', 'ipa-http-delegation'), api.env.container_s4u2proxy, self.suffix) member_principal1 = "HTTP/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm) dn2 = DN(('cn', 'ipa-ldap-delegation-targets'), api.env.container_s4u2proxy, self.suffix) member_principal2 = "ldap/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm) dn3 = DN(('cn', 'ipa-cifs-delegation-targets'), api.env.container_s4u2proxy, self.suffix) member_principal3 = "cifs/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm) for (dn, member_principal) in ((dn1, member_principal1), (dn2, member_principal2), (dn3, member_principal3)): try: mod = [(ldap.MOD_DELETE, 'memberPrincipal', member_principal)] self.conn.modify_s(dn, mod) except (ldap.NO_SUCH_OBJECT, ldap.NO_SUCH_ATTRIBUTE): root_logger.debug("Replica (%s) memberPrincipal (%s) not found in %s" % \ (replica, member_principal, dn)) except Exception, e: if not force: raise e elif not err: err = e # delete master entry with all active services try: dn = DN(('cn', replica), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.suffix) entries = self.conn.get_entries(dn, ldap.SCOPE_SUBTREE) if entries: entries.sort(key=len, reverse=True) for entry in entries: self.conn.delete_entry(entry) except errors.NotFound: pass except Exception, e: if not force: raise e elif not err: err = e try: basedn = DN(('cn', 'etc'), self.suffix) filter = '(dnaHostname=%s)' % replica entries = self.conn.get_entries( basedn, ldap.SCOPE_SUBTREE, filter=filter) if len(entries) != 0: for entry in entries: self.conn.delete_entry(entry) except errors.NotFound: pass except Exception, e: if not force: raise e elif not err: err = e try: dn = DN(('cn', 'default'), ('ou', 'profile'), self.suffix) ret = self.conn.get_entry(dn) srvlist = ret.single_value('defaultServerList', '') srvlist = srvlist[0].split() if replica in srvlist: srvlist.remove(replica) attr = ' '.join(srvlist) mod = [(ldap.MOD_REPLACE, 'defaultServerList', attr)] self.conn.modify_s(dn, mod) except errors.NotFound: pass except ldap.NO_SUCH_ATTRIBUTE: pass except ldap.TYPE_OR_VALUE_EXISTS: pass except Exception, e: if force and err: raise err #pylint: disable=E0702 else: raise e if err: raise err #pylint: disable=E0702 def set_readonly(self, readonly, critical=False): """ Set the database readonly status. @readonly: boolean for read-only status @critical: boolean to raise an exception on failure, default False. """ dn = DN(('cn', 'userRoot'), ('cn', 'ldbm database'), ('cn', 'plugins'), ('cn', 'config')) mod = [(ldap.MOD_REPLACE, 'nsslapd-readonly', 'on' if readonly else 'off')] try: self.conn.modify_s(dn, mod) except ldap.INSUFFICIENT_ACCESS, e: # We can't modify the read-only status on the remote server. # This usually isn't a show-stopper. if critical: raise e root_logger.debug("No permission to modify replica read-only status, continuing anyway") def cleanallruv(self, replicaId): """ Create a CLEANALLRUV task and monitor it until it has completed. """ root_logger.debug("Creating CLEANALLRUV task for replica id %d" % replicaId) dn = DN(('cn', 'clean %d' % replicaId), ('cn', 'cleanallruv'),('cn', 'tasks'), ('cn', 'config')) e = self.conn.make_entry( dn, { 'objectclass': ['top', 'extensibleObject'], 'cn': ['clean %d' % replicaId], 'replica-base-dn': [api.env.basedn], 'replica-id': [replicaId], } ) try: self.conn.add_entry(e) except errors.DuplicateEntry: print "CLEANALLRUV task for replica id %d already exists." % replicaId else: print "Background task created to clean replication data. This may take a while." print "This may be safely interrupted with Ctrl+C" wait_for_task(self.conn, dn) def abortcleanallruv(self, replicaId): """ Create a task to abort a CLEANALLRUV operation. """ root_logger.debug("Creating task to abort a CLEANALLRUV operation for replica id %d" % replicaId) dn = DN(('cn', 'abort %d' % replicaId), ('cn', 'abort cleanallruv'),('cn', 'tasks'), ('cn', 'config')) e = self.conn.make_entry( dn, { 'replica-base-dn': [api.env.basedn], 'replica-id': [replicaId], 'objectclass': ['top', 'extensibleObject'], 'cn': ['abort %d' % replicaId], } ) try: self.conn.add_entry(e) except errors.DuplicateEntry: print "An abort CLEANALLRUV task for replica id %d already exists." % replicaId else: print "Background task created. This may take a while." print "This may be safely interrupted with Ctrl+C" wait_for_task(self.conn, dn) def get_DNA_range(self, hostname): """ Return the DNA range on this server as a tuple, (next, max), or (None, None) if no range has been assigned yet. Raises an exception on errors reading an entry. """ entry = self.conn.get_entry(DNA_DN) nextvalue = int(entry.single_value("dnaNextValue", 0)) maxvalue = int(entry.single_value("dnaMaxValue", 0)) sharedcfgdn = entry.single_value("dnaSharedCfgDN", None) if sharedcfgdn is not None: sharedcfgdn = DN(sharedcfgdn) shared_entry = self.conn.get_entry(sharedcfgdn) remaining = int(shared_entry.single_value("dnaRemainingValues", 0)) else: remaining = 0 if nextvalue == 0 and maxvalue == 0: return (None, None) # Check the magic values for an unconfigured DNA entry if maxvalue == 1100 and nextvalue == 1101 and remaining == 0: return (None, None) else: return (nextvalue, maxvalue) def get_DNA_next_range(self, hostname): """ Return the DNA "on-deck" range on this server as a tuple, (next, max), or (None, None) if no range has been assigned yet. Raises an exception on errors reading an entry. """ entry = self.conn.get_entry(DNA_DN) range = entry.single_value("dnaNextRange", None) if range is None: return (None, None) try: (next, max) = range.split('-') except ValueError: # Should not happen, malformed entry, return nothing. return (None, None) return (int(next), int(max)) def save_DNA_next_range(self, next_start, next_max): """ Save a DNA range into the on-deck value. This adds a dnaNextRange value to the DNA configuration. This attribute takes the form of start-next. Returns True on success. Returns False if the range is already defined. Raises an exception on failure. """ entry = self.conn.get_entry(DNA_DN) range = entry.single_value("dnaNextRange", None) if range is not None and next_start != 0 and next_max != 0: return False if next_start == 0 and next_max == 0: entry["dnaNextRange"] = None else: entry["dnaNextRange"] = "%s-%s" % (next_start, next_max) self.conn.update_entry(entry) return True def save_DNA_range(self, next_start, next_max): """ Save a DNA range. This is potentially very dangerous. Returns True on success. Raises an exception on failure. """ entry = self.conn.get_entry(DNA_DN) entry["dnaNextValue"] = next_start entry["dnaMaxValue"] = next_max self.conn.update_entry(entry) return True def disable_agreement(self, hostname): """ Disable the replication agreement to hostname. """ cn, dn = self.agreement_dn(hostname) entry = self.conn.get_entry(dn) entry['nsds5ReplicaEnabled'] = 'off' try: self.conn.update_entry(entry) except errors.EmptyModlist: pass def enable_agreement(self, hostname): """ Enable the replication agreement to hostname. Note: for replication to work it needs to be enabled both ways. """ cn, dn = self.agreement_dn(hostname) entry = self.conn.get_entry(dn) entry['nsds5ReplicaEnabled'] = 'on' try: self.conn.update_entry(entry) except errors.EmptyModlist: pass class CSReplicationManager(ReplicationManager): """ReplicationManager specific to CA agreements Note that in most cases we don't know if we're connecting to an old-style separate PKI DS, or to a host with a merged DB. Use the get_cs_replication_manager function to determine this and return an appropriate CSReplicationManager. """ def __init__(self, realm, hostname, dirman_passwd, port): super(CSReplicationManager, self).__init__( realm, hostname, dirman_passwd, port, starttls=True) self.suffix = DN(('o', 'ipaca')) self.hostnames = [] # set before calling or agreement_dn() will fail def agreement_dn(self, hostname, master=None): """ Construct a dogtag replication agreement name. This needs to be much more agressive than the IPA replication agreements because the name is different on each side. hostname is the local hostname, not the remote one, for both sides NOTE: The agreement number is hardcoded in dogtag as well TODO: configurable instance name """ dn = None cn = None if self.conn.port == 7389: instance_name = 'pki-ca' else: instance_name = dogtag.configured_constants(api).PKI_INSTANCE_NAME # if master is not None we know what dn to return: if master is not None: if master is True: name = "master" else: name = "clone" cn="%sAgreement1-%s-%s" % (name, hostname, instance_name) dn = DN(('cn', cn), self.replica_dn()) return (cn, dn) for host in self.hostnames: for master in ["master", "clone"]: try: cn="%sAgreement1-%s-%s" % (master, host, instance_name) dn = DN(('cn', cn), self.replica_dn()) self.conn.get_entry(dn) return (cn, dn) except errors.NotFound: dn = None cn = None raise errors.NotFound(reason='No agreement found for %s' % hostname) def delete_referral(self, hostname, port): dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config')) entry = self.conn.get_entry(dn) try: # TODO: should we detect proto somehow ? entry['nsslapd-referral'].remove('ldap://%s/%s' % (ipautil.format_netloc(hostname, port), self.suffix)) self.conn.update_entry(entry) except Exception, e: root_logger.debug("Failed to remove referral value: %s" % e) def has_ipaca(self): try: entry = self.conn.get_entry(self.suffix) except errors.NotFound: return False else: return True def get_cs_replication_manager(realm, host, dirman_passwd): """Get a CSReplicationManager for a remote host Detects if the host has a merged database, connects to appropriate port. """ # Try merged database port first. If it has the ipaca tree, return # corresponding replication manager # If we can't connect to it at all, we're not dealing with an IPA master # anyway; let the exception propagate up # Fall back to the old PKI-only DS port. Check that it has the ipaca tree # (IPA with merged DB theoretically leaves port 7389 free for anyone). # If it doesn't, raise exception. ports = [ dogtag.Dogtag10Constants.DS_PORT, dogtag.Dogtag9Constants.DS_PORT, ] for port in ports: root_logger.debug('Looking for PKI DS on %s:%s' % (host, port)) replication_manager = CSReplicationManager( realm, host, dirman_passwd, port) if replication_manager.has_ipaca(): root_logger.debug('PKI DS found on %s:%s' % (host, port)) return replication_manager else: root_logger.debug('PKI tree not found on %s:%s' % (host, port)) raise errors.NotFound(reason='Cannot reach PKI DS at %s on ports %s' % (host, ports)) freeipa-3.3.4/ipaserver/install/ipa_backup.py0000664000175000017500000004543212271663206020635 0ustar mkosekmkosek# Authors: Rob Crittenden # # Copyright (C) 2013 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 . # import os import sys import shutil import tempfile import time import pwd from optparse import OptionGroup from ConfigParser import SafeConfigParser from ipalib import api, errors from ipapython import version from ipapython.ipautil import run, write_tmp_file from ipapython import admintool from ipapython.config import IPAOptionParser from ipapython.dn import DN from ipaserver.install.dsinstance import realm_to_serverid, DS_USER from ipaserver.install.replication import wait_for_task from ipaserver.install import installutils from ipapython import services as ipaservices from ipapython import ipaldap from ipalib.session import ISO8601_DATETIME_FMT from ConfigParser import SafeConfigParser """ A test gpg can be generated list this: # cat >keygen < 2**32L: libpath = 'lib64' else: libpath = 'lib' return os.path.join('/usr', libpath, 'dirsrv', 'slapd-PKI-IPA') freeipa-3.3.4/ipaserver/install/httpinstance.py0000664000175000017500000004441612271663206021244 0ustar mkosekmkosek# Authors: Rob Crittenden # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import os import os.path import tempfile import pwd import shutil import stat import re import service import certs import installutils from ipapython import sysrestore from ipapython import ipautil from ipapython import services as ipaservices from ipapython import dogtag from ipapython.ipa_log_manager import * from ipaserver.install import sysupgrade from ipalib import api HTTPD_DIR = "/etc/httpd" SSL_CONF = HTTPD_DIR + "/conf.d/ssl.conf" NSS_CONF = HTTPD_DIR + "/conf.d/nss.conf" selinux_warning = """ WARNING: could not set selinux boolean(s) %(var)s to true. The web interface may not function correctly until this boolean is successfully change with the command: /usr/sbin/setsebool -P %(var)s true Try updating the policycoreutils and selinux-policy packages. """ def httpd_443_configured(): """ We now allow mod_ssl to be installed so don't automatically disable it. However it can't share the same listen port as mod_nss, so check for that. Returns True if something other than mod_nss is listening on 443. False otherwise. """ try: (stdout, stderr, rc) = ipautil.run(['/usr/sbin/httpd', '-t', '-D', 'DUMP_VHOSTS']) except ipautil.CalledProcessError, e: service.print_msg("WARNING: cannot check if port 443 is already configured") service.print_msg("httpd returned error when checking: %s" % e) return False port_line_re = re.compile(r'(?P
\S+):(?P\d+)') for line in stdout.splitlines(): m = port_line_re.match(line) if m and int(m.group('port')) == 443: service.print_msg("Apache is already configured with a listener on port 443:") service.print_msg(line) return True return False class WebGuiInstance(service.SimpleServiceInstance): def __init__(self): service.SimpleServiceInstance.__init__(self, "ipa_webgui") class HTTPInstance(service.Service): def __init__(self, fstore=None, cert_nickname='Server-Cert'): service.Service.__init__(self, "httpd", service_desc="the web interface") if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') self.cert_nickname = cert_nickname subject_base = ipautil.dn_attribute_property('_subject_base') def create_instance(self, realm, fqdn, domain_name, dm_password=None, autoconfig=True, pkcs12_info=None, subject_base=None, auto_redirect=True, ca_file=None): self.fqdn = fqdn self.realm = realm self.domain = domain_name self.dm_password = dm_password self.suffix = ipautil.realm_to_suffix(self.realm) self.pkcs12_info = pkcs12_info self.principal = "HTTP/%s@%s" % (self.fqdn, self.realm) self.dercert = None self.subject_base = subject_base self.sub_dict = dict( REALM=realm, FQDN=fqdn, DOMAIN=self.domain, AUTOREDIR='' if auto_redirect else '#', CRL_PUBLISH_PATH=dogtag.install_constants.CRL_PUBLISH_PATH, ) self.ca_file = ca_file # get a connection to the DS self.ldap_connect() self.step("setting mod_nss port to 443", self.__set_mod_nss_port) self.step("setting mod_nss password file", self.__set_mod_nss_passwordfile) self.step("enabling mod_nss renegotiate", self.enable_mod_nss_renegotiate) self.step("adding URL rewriting rules", self.__add_include) self.step("configuring httpd", self.__configure_http) self.step("setting up ssl", self.__setup_ssl) if autoconfig: self.step("setting up browser autoconfig", self.__setup_autoconfig) self.step("publish CA cert", self.__publish_ca_cert) self.step("creating a keytab for httpd", self.__create_http_keytab) self.step("clean up any existing httpd ccache", self.remove_httpd_ccache) self.step("configuring SELinux for httpd", self.configure_selinux_for_httpd) self.step("configure httpd ccache", self.configure_httpd_ccache) self.step("restarting httpd", self.__start) self.step("configuring httpd to start on boot", self.__enable) self.start_creation(runtime=60) def __start(self): self.backup_state("running", self.is_running()) self.restart() def __enable(self): self.backup_state("enabled", self.is_running()) # 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 self.ldap_enable('HTTP', self.fqdn, self.dm_password, self.suffix) def configure_selinux_for_httpd(self): def get_setsebool_args(changes): if len(changes) == 1: # workaround https://bugzilla.redhat.com/show_bug.cgi?id=825163 updates = changes.items()[0] else: updates = ["%s=%s" % update for update in changes.iteritems()] args = ["/usr/sbin/setsebool", "-P"] args.extend(updates) return args selinux = False try: if (os.path.exists('/usr/sbin/selinuxenabled')): ipautil.run(["/usr/sbin/selinuxenabled"]) selinux = True except ipautil.CalledProcessError: # selinuxenabled returns 1 if not enabled pass if selinux: # Don't assume all vars are available updated_vars = {} failed_vars = {} required_settings = (("httpd_can_network_connect", "on"), ("httpd_manage_ipa", "on")) for setting, state in required_settings: try: (stdout, stderr, returncode) = ipautil.run(["/usr/sbin/getsebool", setting]) original_state = stdout.split()[2] self.backup_state(setting, original_state) if original_state != state: updated_vars[setting] = state except ipautil.CalledProcessError, e: root_logger.debug("Cannot get SELinux boolean '%s': %s", setting, e) failed_vars[setting] = state # Allow apache to connect to the dogtag UI and the session cache # This can still fail even if selinux is enabled. Execute these # together so it is speedier. if updated_vars: args = get_setsebool_args(updated_vars) try: ipautil.run(args) except ipautil.CalledProcessError: failed_vars.update(updated_vars) if failed_vars: args = get_setsebool_args(failed_vars) names = [update[0] for update in updated_vars] message = ['WARNING: could not set the following SELinux boolean(s):'] for update in failed_vars.iteritems(): message.append(' %s -> %s' % update) message.append('The web interface may not function correctly until the booleans') message.append('are successfully changed with the command:') message.append(' '.join(args)) message.append('Try updating the policycoreutils and selinux-policy packages.') self.print_msg("\n".join(message)) def __create_http_keytab(self): installutils.kadmin_addprinc(self.principal) installutils.create_keytab("/etc/httpd/conf/ipa.keytab", self.principal) self.move_service(self.principal) self.add_cert_to_service() pent = pwd.getpwnam("apache") os.chown("/etc/httpd/conf/ipa.keytab", pent.pw_uid, pent.pw_gid) def remove_httpd_ccache(self): # Clean up existing ccache pent = pwd.getpwnam("apache") installutils.remove_file('/tmp/krb5cc_%d' % pent.pw_uid) def configure_httpd_ccache(self): pent = pwd.getpwnam("apache") ccache = '/tmp/krb5cc_%d' % pent.pw_uid filepath = '/etc/sysconfig/httpd' 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) replacevars = {'KRB5CCNAME': ccache} old_values = ipautil.backup_config_and_replace_variables( self.fstore, filepath, replacevars=replacevars) ipaservices.restore_context(filepath) def __configure_http(self): target_fname = '/etc/httpd/conf.d/ipa.conf' http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa.conf", self.sub_dict) self.fstore.backup_file("/etc/httpd/conf.d/ipa.conf") http_fd = open(target_fname, "w") http_fd.write(http_txt) http_fd.close() os.chmod(target_fname, 0644) target_fname = '/etc/httpd/conf.d/ipa-rewrite.conf' http_txt = ipautil.template_file(ipautil.SHARE_DIR + "ipa-rewrite.conf", self.sub_dict) self.fstore.backup_file("/etc/httpd/conf.d/ipa-rewrite.conf") http_fd = open(target_fname, "w") http_fd.write(http_txt) http_fd.close() os.chmod(target_fname, 0644) def change_mod_nss_port_to_http(self): # mod_ssl enforces SSLEngine on for vhost on 443 even though # the listener is mod_nss. This then crashes the httpd as mod_nss # listened port obviously does not match mod_ssl requirements. # # Change port to http to workaround the mod_ssl check, the SSL is # enforced in the vhost later, so it is benign. # # Remove when https://bugzilla.redhat.com/show_bug.cgi?id=1023168 # is fixed. if not sysupgrade.get_upgrade_state('nss.conf', 'listen_port_updated'): installutils.set_directive(NSS_CONF, 'Listen', '443 http', quotes=False) sysupgrade.set_upgrade_state('nss.conf', 'listen_port_updated', True) def __set_mod_nss_port(self): self.fstore.backup_file(NSS_CONF) if installutils.update_file(NSS_CONF, '8443', '443') != 0: print "Updating port in %s failed." % NSS_CONF self.change_mod_nss_port_to_http() def __set_mod_nss_nickname(self, nickname): installutils.set_directive(NSS_CONF, 'NSSNickname', nickname) def enable_mod_nss_renegotiate(self): installutils.set_directive(NSS_CONF, 'NSSRenegotiation', 'on', False) installutils.set_directive(NSS_CONF, 'NSSRequireSafeNegotiation', 'on', False) def __set_mod_nss_passwordfile(self): installutils.set_directive(NSS_CONF, 'NSSPassPhraseDialog', 'file:/etc/httpd/conf/password.conf') def __add_include(self): """This should run after __set_mod_nss_port so is already backed up""" if installutils.update_file(NSS_CONF, '', 'Include conf.d/ipa-rewrite.conf\n') != 0: print "Adding Include conf.d/ipa-rewrite to %s failed." % NSS_CONF def __setup_ssl(self): fqdn = self.fqdn ca_db = certs.CertDB(self.realm, host_name=fqdn, subject_base=self.subject_base) db = certs.CertDB(self.realm, subject_base=self.subject_base) if self.pkcs12_info: db.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd=None, ca_file=self.ca_file) server_certs = db.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0]) db.create_password_conf() # We only handle one server cert nickname = server_certs[0][0] self.dercert = db.get_cert_from_db(nickname, pem=False) if api.env.enable_ra: db.track_server_cert(nickname, self.principal, db.passwd_fname, 'restart_httpd') self.__set_mod_nss_nickname(nickname) else: db.create_password_conf() self.dercert = db.create_server_cert(self.cert_nickname, self.fqdn, ca_db) db.track_server_cert(self.cert_nickname, self.principal, db.passwd_fname, 'restart_httpd') db.create_signing_cert("Signing-Cert", "Object Signing Cert", ca_db) # Fix the database permissions os.chmod(certs.NSS_DIR + "/cert8.db", 0660) os.chmod(certs.NSS_DIR + "/key3.db", 0660) os.chmod(certs.NSS_DIR + "/secmod.db", 0660) os.chmod(certs.NSS_DIR + "/pwdfile.txt", 0660) pent = pwd.getpwnam("apache") os.chown(certs.NSS_DIR + "/cert8.db", 0, pent.pw_gid ) os.chown(certs.NSS_DIR + "/key3.db", 0, pent.pw_gid ) os.chown(certs.NSS_DIR + "/secmod.db", 0, pent.pw_gid ) os.chown(certs.NSS_DIR + "/pwdfile.txt", 0, pent.pw_gid ) # Fix SELinux permissions on the database ipaservices.restore_context(certs.NSS_DIR + "/cert8.db") ipaservices.restore_context(certs.NSS_DIR + "/key3.db") def __setup_autoconfig(self): target_fname = '/usr/share/ipa/html/preferences.html' ipautil.copy_template_file( ipautil.SHARE_DIR + "preferences.html.template", target_fname, self.sub_dict) os.chmod(target_fname, 0644) # The signing cert is generated in __setup_ssl db = certs.CertDB(self.realm, subject_base=self.subject_base) with open(db.passwd_fname) as pwdfile: pwd = pwdfile.read() # Setup configure.jar if db.has_nickname('Signing-Cert'): tmpdir = tempfile.mkdtemp(prefix="tmp-") target_fname = '/usr/share/ipa/html/configure.jar' shutil.copy("/usr/share/ipa/html/preferences.html", tmpdir) db.run_signtool(["-k", "Signing-Cert", "-Z", target_fname, "-e", ".html", "-p", pwd, tmpdir]) shutil.rmtree(tmpdir) os.chmod(target_fname, 0644) else: root_logger.warning('Object-signing certificate was not found; ' 'therefore, configure.jar was not created.') self.setup_firefox_extension(self.realm, self.domain, force=True) def setup_firefox_extension(self, realm, domain, force=False): """Set up the signed browser configuration extension If the extension is already set up, skip the installation unless ``force`` is true. """ target_fname = '/usr/share/ipa/html/krb.js' if os.path.exists(target_fname) and not force: root_logger.info( '%s exists, skipping install of Firefox extension', target_fname) return sub_dict = dict(REALM=realm, DOMAIN=domain) db = certs.CertDB(realm) with open(db.passwd_fname) as pwdfile: pwd = pwdfile.read() ipautil.copy_template_file(ipautil.SHARE_DIR + "krb.js.template", target_fname, sub_dict) os.chmod(target_fname, 0644) # Setup extension tmpdir = tempfile.mkdtemp(prefix="tmp-") extdir = tmpdir + "/ext" target_fname = "/usr/share/ipa/html/kerberosauth.xpi" shutil.copytree("/usr/share/ipa/ffextension", extdir) if db.has_nickname('Signing-Cert'): db.run_signtool(["-k", "Signing-Cert", "-p", pwd, "-X", "-Z", target_fname, extdir]) else: root_logger.warning('Object-signing certificate was not found. ' 'Creating unsigned Firefox configuration extension.') filenames = os.listdir(extdir) ipautil.run(['/usr/bin/zip', '-r', target_fname] + filenames, cwd=extdir) shutil.rmtree(tmpdir) os.chmod(target_fname, 0644) def __publish_ca_cert(self): ca_db = certs.CertDB(self.realm) ca_db.publish_ca_cert("/usr/share/ipa/html/ca.crt") def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring web server") running = self.restore_state("running") enabled = self.restore_state("enabled") if not running is None: self.stop() self.stop_tracking_certificates() if not enabled is None and not enabled: self.disable() for f in ["/etc/httpd/conf.d/ipa.conf", SSL_CONF, NSS_CONF]: try: self.fstore.restore_file(f) except ValueError, error: root_logger.debug(error) pass # Remove the configuration files we create installutils.remove_file("/etc/httpd/conf.d/ipa-rewrite.conf") installutils.remove_file("/etc/httpd/conf.d/ipa.conf") installutils.remove_file("/etc/httpd/conf.d/ipa-pki-proxy.conf") for var in ["httpd_can_network_connect", "httpd_manage_ipa"]: sebool_state = self.restore_state(var) if not sebool_state is None: try: ipautil.run(["/usr/sbin/setsebool", "-P", var, sebool_state]) except ipautil.CalledProcessError, e: self.print_msg("Cannot restore SELinux boolean '%s' back to '%s': %s" \ % (var, sebool_state, e)) if not running is None and running: self.start() def stop_tracking_certificates(self): db = certs.CertDB(api.env.realm) db.untrack_server_cert(self.cert_nickname) freeipa-3.3.4/ipaserver/install/plugins/0000775000175000017500000000000012271663206017636 5ustar mkosekmkosekfreeipa-3.3.4/ipaserver/install/plugins/__init__.py0000664000175000017500000000156112202434255021744 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2011 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 . """ Provide a separate api for updates. """ PRE_UPDATE = 1 POST_UPDATE = 2 FIRST = 1 MIDDLE = 2 LAST = 4 freeipa-3.3.4/ipaserver/install/plugins/fix_replica_agreements.py0000664000175000017500000001100212271663206024701 0ustar mkosekmkosek# Authors: # Rob Crittenden # # 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 . import os import pwd from ipapython import ipaldap from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PreUpdate from ipaserver.install import replication from ipalib import api EXCLUDE_TEMPLATE = '(objectclass=*) $ EXCLUDE %s' class update_replica_attribute_lists(PreUpdate): """ 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): # 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) # We need to update only IPA replica agreements, not winsync ipa_replicas = repl.find_ipa_replication_agreements() self.log.debug("Found %d agreement(s)", len(ipa_replicas)) for replica in ipa_replicas: self.log.debug(replica.single_value('description', None)) self._update_attr(repl, replica, 'nsDS5ReplicatedAttributeList', replication.EXCLUDES, template=EXCLUDE_TEMPLATE) self._update_attr(repl, replica, 'nsDS5ReplicatedAttributeListTotal', replication.TOTAL_EXCLUDES, template=EXCLUDE_TEMPLATE) self._update_attr(repl, replica, 'nsds5ReplicaStripAttrs', replication.STRIP_ATTRS) self.log.debug("Done updating agreements") return (False, False, []) # No restart, no apply now, no updates def _update_attr(self, repl, replica, attribute, values, template='%s'): """Add or update an attribute of a replication agreement If the attribute doesn't already exist, it is added and set to `template` with %s substituted by a space-separated `values`. If the attribute does exist, `values` missing from it are just appended to the end, also space-separated. :param repl: Replication manager :param replica: Replica agreement :param attribute: Attribute to add or update :param values: List of values the attribute should hold :param template: Template to use when adding attribute """ attrlist = replica.single_value(attribute, None) if attrlist is None: self.log.debug("Adding %s", attribute) # Need to add it altogether replica[attribute] = [template % " ".join(values)] try: repl.conn.update_entry(replica.dn, replica) self.log.debug("Updated") except Exception, e: self.log.error("Error caught updating replica: %s", str(e)) else: attrlist_normalized = attrlist.lower().split() missing = [a for a in values if a.lower() not in attrlist_normalized] if missing: self.log.debug("%s needs updating (missing: %s)", attribute, ', '.join(missing)) replica[attribute] = [ '%s %s' % (attrlist, ' '.join(missing))] try: repl.conn.update_entry(replica.dn, replica) self.log.debug("Updated %s", attribute) except Exception, e: self.log.error("Error caught updating %s: %s", attribute, str(e)) else: self.log.debug("%s: No update necessary" % attribute) api.register(update_replica_attribute_lists) freeipa-3.3.4/ipaserver/install/plugins/Makefile.am0000664000175000017500000000051612271663206021674 0ustar mkosekmkosekNULL = appdir = $(pythondir)/ipaserver/install app_PYTHON = \ __init__.py \ baseupdate.py \ fix_replica_agreements.py \ rename_managed.py \ dns.py \ updateclient.py \ update_services.py \ update_anonymous_aci.py \ update_pacs.py \ $(NULL) EXTRA_DIST = \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/ipaserver/install/plugins/updateclient.py0000664000175000017500000001260312271663206022673 0ustar mkosekmkosek# Authors: Rob Crittenden # # Copyright (C) 2011 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 . # 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 from ipapython.dn import DN class updateclient(backend.Executioner): """ Backend used for applying LDAP updates via plugins An update plugin can be executed before the file-based plugins or afterward. Each plugin returns three values: 1. restart: dirsrv needs to be restarted BEFORE this update is applied. 2. apply_now: when True the update is applied when the plugin returns. Otherwise the update is cached until all plugins of that update type are complete, then they are applied together. 3. updates: A dictionary of updates to be applied. updates is a dictionary keyed on dn. The value of an update is a dictionary with the following possible values: - dn: DN, equal to the dn attribute - updates: list of updates against the dn - default: list of the default entry to be added if it doesn't exist - deleteentry: list of dn's to be deleted (typically single dn) For example, this update file: dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX replace:krbPwdLockoutDuration:10::600 replace: krbPwdMaxFailure:3::6 Generates this update dictionary: dict('cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com': dict( 'dn': 'cn=global_policy,cn=EXAMPLE.COM,cn=kerberos,dc=example,dc=com', 'updates': ['replace:krbPwdLockoutDuration:10::600', 'replace:krbPwdMaxFailure:3::6'] ) ) Here is another example showing how a default entry is configured: dn: cn=Managed Entries,cn=etc,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: Managed Entries This generates: dict('cn=Managed Entries,cn=etc,dc=example,dc=com', dict( 'dn': 'cn=Managed Entries,cn=etc,dc=example,dc=com', 'default': ['objectClass:nsContainer', 'objectClass:top', 'cn:Managed Entries' ] ) ) Note that the variable substitution in both examples has been completed. A PRE_UPDATE plugin is executed before file-based updates. A POST_UPDATE plugin is executed after file-based updates. Plugins are executed automatically when ipa-ldap-updater is run in upgrade mode (--upgrade). They are not executed normally otherwise. To execute plugins as well use the --plugins flag. Either may make changes directly in LDAP or can return updates in update format. """ def create_context(self, dm_password): if dm_password: autobind = False else: autobind = True self.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password, autobind=autobind) def order(self, updatetype): """Return plugins of the given updatetype in sorted order. """ ordered = [plugin for plugin in api.Updater() if plugin.updatetype == updatetype] ordered.sort(key=lambda p: p.order) return ordered def update(self, updatetype, dm_password, ldapi, live_run): """ Execute all update plugins of type updatetype. """ self.create_context(dm_password) kw = dict(live_run=live_run) result = [] ld = LDAPUpdate(dm_password=dm_password, sub_dict={}, live_run=live_run, ldapi=ldapi) for update in self.order(updatetype): (restart, apply_now, res) = self.run(update.name, **kw) if restart: self.restart(dm_password, live_run) if apply_now: updates = {} for entry in res: updates.update(entry) ld.update_from_dict(updates) elif res: result.extend(res) self.destroy_context() return result def run(self, method, **kw): """ Execute the update plugin. """ return self.Updater[method](**kw) def restart(self, dm_password, live_run): dsrestart = DSRestart() socket_name = '/var/run/slapd-%s.socket' % \ api.env.realm.replace('.','-') if live_run: self.destroy_context() dsrestart.create_instance() wait_for_open_socket(socket_name) self.create_context(dm_password) else: self.log.warn("Test mode, skipping restart") api.register(updateclient) freeipa-3.3.4/ipaserver/install/plugins/upload_cacrt.py0000664000175000017500000000377612271663206022665 0ustar mkosekmkosek# Authors: # Alexander Bokovoy # # 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipaserver.install.dsinstance import realm_to_serverid, config_dirname from ipaserver.install import certs from ipalib import api from ipapython.dn import DN import base64 class update_upload_cacrt(PostUpdate): """ Upload public CA certificate to LDAP """ order=MIDDLE def execute(self, **options): ldap = self.obj.backend (cdn, ipa_config) = ldap.get_ipa_config() subject_base = ipa_config.get('ipacertificatesubjectbase', [None])[0] dirname = config_dirname(realm_to_serverid(api.env.realm)) certdb = certs.CertDB(api.env.realm, nssdir=dirname, subject_base=subject_base) dercert = certdb.get_cert_from_db(certdb.cacert_name, pem=False) updates = {} dn = DN(('cn', 'CACert'), ('cn', 'ipa'), ('cn','etc'), api.env.basedn) cacrt_entry = ['objectclass:nsContainer', 'objectclass:pkiCA', 'cn:CAcert', 'cACertificate;binary:%s' % dercert, ] updates[dn] = {'dn': dn, 'default': cacrt_entry} return (False, True, [updates]) api.register(update_upload_cacrt) freeipa-3.3.4/ipaserver/install/plugins/adtrust.py0000664000175000017500000001162612271663206021704 0ustar mkosekmkosek# Authors: # Martin Kosek # # 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors from ipapython.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. """ order=MIDDLE def execute(self, **options): ldap = self.obj.backend dn = DN(api.env.container_ranges, api.env.basedn) search_filter = "objectclass=ipaDomainIDRange" try: (entries, truncated) = ldap.find_entries(search_filter, [], dn) except errors.NotFound: pass else: root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin") return (False, False, []) dn = DN(('cn', 'admins'), api.env.container_group, api.env.basedn) try: (dn, admins_entry) = ldap.get_entry(dn, ['gidnumber']) except errors.NotFound: root_logger.error("default_range: No local ID range and no admins " "group found. Cannot create default ID range") return (False, False, []) 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_name, 'ipabaseid:%s' % id_range_base_id, 'ipaidrangesize:%s' % id_range_size, 'iparangetype:ipa-local', ] updates = {} dn = DN(('cn', '%s_id_range' % api.env.realm), api.env.container_ranges, api.env.basedn) 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 = 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) freeipa-3.3.4/ipaserver/install/plugins/update_anonymous_aci.py0000664000175000017500000000651412271663206024424 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2013 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 . from copy import deepcopy from ipaserver.install.plugins import FIRST, LAST from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors from ipalib.aci import ACI from ipalib.plugins import aci from ipapython.ipa_log_manager import * class update_anonymous_aci(PostUpdate): """ Update the Anonymous ACI to ensure that all secrets are protected. """ order = FIRST def execute(self, **options): aciname = u'Enable Anonymous access' aciprefix = u'none' ldap = self.obj.backend targetfilter = '(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenRadiusConfiguration)))' filter = None (dn, entry_attrs) = ldap.get_entry(api.env.basedn, ['aci']) acistrs = entry_attrs.get('aci', []) acilist = aci._convert_strings_to_acis(entry_attrs.get('aci', [])) try: rawaci = aci._find_aci_by_name(acilist, aciprefix, aciname) except errors.NotFound: root_logger.error('Anonymous ACI not found, cannot update it') return False, False, [] attrs = rawaci.target['targetattr']['expression'] rawfilter = rawaci.target.get('targetfilter', None) if rawfilter is not None: filter = rawfilter['expression'] update_attrs = deepcopy(attrs) needed_attrs = [] for attr in ('ipaNTTrustAuthOutgoing', 'ipaNTTrustAuthIncoming'): if attr not in attrs: needed_attrs.append(attr) update_attrs.extend(needed_attrs) if (len(attrs) == len(update_attrs) and filter == targetfilter): root_logger.debug("Anonymous ACI already update-to-date") return (False, False, []) for tmpaci in acistrs: candidate = ACI(tmpaci) if rawaci.isequal(candidate): acistrs.remove(tmpaci) break if len(attrs) != len(update_attrs): root_logger.debug("New Anonymous ACI attributes needed: %s", needed_attrs) rawaci.target['targetattr']['expression'] = update_attrs if filter != targetfilter: root_logger.debug("New Anonymous ACI targetfilter needed.") rawaci.set_target_filter(targetfilter) acistrs.append(unicode(rawaci)) entry_attrs['aci'] = acistrs try: ldap.update_entry(dn, entry_attrs) except Exception, e: root_logger.error("Failed to update Anonymous ACI: %s" % e) return (False, False, []) api.register(update_anonymous_aci) freeipa-3.3.4/ipaserver/install/plugins/update_pacs.py0000664000175000017500000000360512271663206022504 0ustar mkosekmkosek# Authors: # Tomas Babej # # Copyright (C) 2013 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors from ipapython.dn import DN class update_pacs(PostUpdate): """ Includes default nfs:None only if no nfs: PAC present in ipakrbauthzdata. """ order = MIDDLE def execute(self, **options): ldap = self.obj.backend try: dn = DN('cn=ipaConfig', 'cn=etc', api.env.basedn) entry = ldap.get_entry(dn, ['ipakrbauthzdata']) pacs = entry.get('ipakrbauthzdata', []) except errors.NotFound: self.log.warning('Error retrieving: %s' % str(dn)) return (False, False, []) nfs_pac_set = any(pac.startswith('nfs:') for pac in pacs) if not nfs_pac_set: self.log.debug('Adding nfs:NONE to default PAC types') updated_pacs = pacs + [u'nfs:NONE'] entry['ipakrbauthzdata'] = updated_pacs ldap.update_entry(entry) else: self.log.debug('PAC for nfs is already set, not adding nfs:NONE.') return (False, False, []) api.register(update_pacs) freeipa-3.3.4/ipaserver/install/plugins/rename_managed.py0000664000175000017500000001416012271663206023135 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2011 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 . from ipaserver.install.plugins import FIRST, LAST from ipaserver.install.plugins.baseupdate import PreUpdate, PostUpdate from ipalib import api, errors from ipapython import ipautil from ipapython.dn import DN, EditableDN def entry_to_update(entry): """ Convert an entry into a name/value pair list that looks like an update. An entry is a dict. An update is a list of name/value pairs. """ update = [] for attr in entry.keys(): if isinstance(entry[attr], list): for i in xrange(len(entry[attr])): update.append('%s:%s' % (str(attr), str(entry[attr][i]))) else: update.append('%s:%s' % (str(attr), str(entry[attr]))) return update class GenerateUpdateMixin(object): def generate_update(self, deletes=False): """ We need to separate the deletes that need to happen from the new entries that need to be added. """ ldap = self.obj.backend suffix = ipautil.realm_to_suffix(api.env.realm) searchfilter = '(objectclass=*)' definitions_managed_entries = [] old_template_container = DN(('cn', 'etc'), suffix) new_template_container = DN(('cn', 'Templates'), ('cn', 'Managed Entries'), ('cn', 'etc'), suffix) old_definition_container = DN(('cn', 'managed entries'), ('cn', 'plugins'), ('cn', 'config'), suffix) new_definition_container = DN(('cn', 'Definitions'), ('cn', 'Managed Entries'), ('cn', 'etc'), suffix) definitions_dn = DN(('cn', 'Definitions')) update_list = [] restart = False # If the old entries don't exist the server has already been updated. try: definitions_managed_entries, truncated = ldap.find_entries( searchfilter, ['*'], old_definition_container, ldap.SCOPE_ONELEVEL) except errors.NotFound, e: return (False, update_list) for entry in definitions_managed_entries: assert isinstance(entry.dn, DN) if deletes: old_dn = entry.data['managedtemplate'][0] assert isinstance(old_dn, DN) try: (old_dn, entry) = ldap.get_entry(old_dn, ['*']) except errors.NotFound, e: pass else: # Compute the new dn by replacing the old container with the new container new_dn = EditableDN(old_dn) if new_dn.replace(old_template_container, new_template_container) != 1: self.error("unable to replace '%s' with '%s' in '%s'", old_template_container, new_template_container, old_dn) continue new_dn = DN(new_dn) # The old attributes become defaults for the new entry new_update = {'dn': new_dn, 'default': entry_to_update(entry)} # Delete the old entry old_update = {'dn': old_dn, 'deleteentry': None} # Add the delete and replacement updates to the list of all updates update_list.append({old_dn: old_update, new_dn: new_update}) else: # Update the template dn by replacing the old containter with the new container old_dn = entry.data['managedtemplate'][0] new_dn = EditableDN(old_dn) if new_dn.replace(old_template_container, new_template_container) != 1: self.error("unable to replace '%s' with '%s' in '%s'", old_template_container, new_template_container, old_dn) continue new_dn = DN(new_dn) entry.data['managedtemplate'] = new_dn # Edit the dn, then convert it back to an immutable DN old_dn = entry.dn new_dn = EditableDN(old_dn) if new_dn.replace(old_definition_container, new_definition_container) != 1: self.error("unable to replace '%s' with '%s' in '%s'", old_definition_container, new_definition_container, old_dn) continue new_dn = DN(new_dn) # The old attributes become defaults for the new entry new_update = {'dn': new_dn, 'default': entry_to_update(entry.data)} # Add the replacement update to the collection of all updates update_list.append({new_dn: new_update}) if len(update_list) > 0: restart = True update_list.sort(reverse=True) return (restart, update_list) class update_managed_post_first(PreUpdate, GenerateUpdateMixin): """ Update managed entries """ order=FIRST def execute(self, **options): # Never need to restart with the pre-update changes (ignore, update_list) = self.generate_update(False) return (False, True, update_list) api.register(update_managed_post_first) class update_managed_post(PostUpdate, GenerateUpdateMixin): """ Update managed entries """ order=LAST def execute(self, **options): (restart, update_list) = self.generate_update(True) return (restart, True, update_list) api.register(update_managed_post) freeipa-3.3.4/ipaserver/install/plugins/dns.py0000664000175000017500000002015612271663206021000 0ustar mkosekmkosek# Authors: # Martin Kosek # # 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors, util from ipapython.dn import DN from ipalib.plugins.dns import dns_container_exists from ipapython.ipa_log_manager import * class update_dnszones(PostUpdate): """ Update all zones to meet requirements in the new FreeIPA versions 1) AllowQuery and AllowTransfer Set AllowQuery and AllowTransfer ACLs in all zones that may be configured in an upgraded FreeIPA instance. Upgrading to new version of bind-dyndb-ldap and having these ACLs empty would result in a leak of potentially sensitive DNS information as zone transfers are enabled for all hosts if not disabled in named.conf or LDAP. This plugin disables the zone transfer by default so that it needs to be explicitly enabled by FreeIPA Administrator. 2) Update policy SSH public key support includes a feature to automatically add/update client SSH fingerprints in SSHFP records. However, the update won't work for zones created before this support was added as they don't allow clients to update SSHFP records in their update policies. This module extends the original policy to allow the SSHFP updates. """ order=MIDDLE def execute(self, **options): ldap = self.obj.backend try: zones = api.Command.dnszone_find(all=True)['result'] except errors.NotFound: self.log.info('No DNS zone to update found') return (False, False, []) for zone in zones: update = {} if not zone.get('idnsallowquery'): # allow query from any client by default update['idnsallowquery'] = u'any;' if not zone.get('idnsallowtransfer'): # do not open zone transfers by default update['idnsallowtransfer'] = u'none;' old_policy = util.get_dns_forward_zone_update_policy(api.env.realm, ('A', 'AAAA')) if zone.get('idnsupdatepolicy', [''])[0] == old_policy: update['idnsupdatepolicy'] = util.get_dns_forward_zone_update_policy(\ api.env.realm) if update: api.Command.dnszone_mod(zone[u'idnsname'][0], **update) return (False, False, []) api.register(update_dnszones) class update_dns_permissions(PostUpdate): """ New DNS permissions need to be added only for updated machines with enabled DNS. LDIF loaded by DNS installer would fail because of duplicate entries otherwise. """ _write_dns_perm_dn = DN(('cn', 'Write DNS Configuration'), api.env.container_permission, api.env.basedn) _write_dns_perm_entry = ['objectClass:groupofnames', 'objectClass:top', 'cn:Write DNS Configuration', 'description:Write DNS Configuration', 'member:%s' % DN(('cn', 'DNS Administrators'), ('cn', 'privileges'), ('cn', 'pbac'), api.env.basedn), 'member:%s' % DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'), api.env.basedn)] _read_dns_perm_dn = DN(('cn', 'Read DNS Entries'), api.env.container_permission, api.env.basedn) _read_dns_perm_entry = ['objectClass:top', 'objectClass:groupofnames', 'objectClass:ipapermission', 'cn:Read DNS Entries', 'description:Read DNS entries', 'ipapermissiontype:SYSTEM', 'member:%s' % DN(('cn', 'DNS Administrators'), ('cn', 'privileges'), ('cn', 'pbac'), api.env.basedn), 'member:%s' % DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'), api.env.basedn),] _write_dns_aci_dn = DN(api.env.basedn) _write_dns_aci_entry = ['add:aci:\'(targetattr = "idnsforwardpolicy || idnsforwarders || idnsallowsyncptr || idnszonerefresh || idnspersistentsearch")(target = "ldap:///cn=dns,%(realm)s")(version 3.0;acl "permission:Write DNS Configuration";allow (write) groupdn = "ldap:///cn=Write DNS Configuration,cn=permissions,cn=pbac,%(realm)s";)\'' % dict(realm=api.env.basedn)] _read_dns_aci_dn = DN(api.env.container_dns, api.env.basedn) _read_dns_aci_entry = ['add:aci:\'(targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,%(realm)s" or userattr = "parent[0,1].managedby#GROUPDN";)\'' % dict(realm=api.env.basedn) ] def execute(self, **options): ldap = self.obj.backend if not dns_container_exists(ldap): return (False, False, []) dnsupdates = {} # add default and updated entries for dn, container, entry in ((self._write_dns_perm_dn, 'default', self._write_dns_perm_entry), (self._read_dns_perm_dn, 'default', self._read_dns_perm_entry), (self._write_dns_aci_dn, 'updates', self._write_dns_aci_entry), (self._read_dns_aci_dn, 'updates', self._read_dns_aci_entry)): dnsupdates[dn] = {'dn': dn, container: entry} return (False, True, [dnsupdates]) api.register(update_dns_permissions) class update_dns_limits(PostUpdate): """ bind-dyndb-ldap persistent search queries LDAP for all DNS records. The LDAP connection must have no size or time limits to work properly. This plugin updates limits of the existing DNS service principal to match there requirements. """ limit_attributes = ['nsTimeLimit', 'nsSizeLimit', 'nsIdleTimeout', 'nsLookThroughLimit'] limit_value = '-1' def execute(self, **options): ldap = self.obj.backend if not dns_container_exists(ldap): return (False, False, []) dns_principal = 'DNS/%s@%s' % (self.env.host, self.env.realm) dns_service_dn = DN(('krbprincipalname', dns_principal), self.env.container_service, self.env.basedn) try: (dn, entry) = ldap.get_entry(dns_service_dn, self.limit_attributes) except errors.NotFound: # this host may not have DNS service set root_logger.debug("DNS: service %s not found, no need to update limits" % dns_service_dn) return (False, False, []) if all(entry.get(limit.lower(), [None])[0] == self.limit_value for limit in self.limit_attributes): root_logger.debug("DNS: limits for service %s already set" % dns_service_dn) # service is already updated return (False, False, []) limit_updates = [] for limit in self.limit_attributes: limit_updates.append('only:%s:%s' % (limit, self.limit_value)) dnsupdates = {} dnsupdates[dns_service_dn] = {'dn': dns_service_dn, 'updates': limit_updates} root_logger.debug("DNS: limits for service %s will be updated" % dns_service_dn) return (False, True, [dnsupdates]) api.register(update_dns_limits) freeipa-3.3.4/ipaserver/install/plugins/baseupdate.py0000664000175000017500000000460112271663206022326 0ustar mkosekmkosek# Authors: # Rob Crittenden # # Copyright (C) 2011 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 . from ipalib import api from ipalib import Updater, Object from ipaserver.install import service from ipaserver.install.plugins import PRE_UPDATE, POST_UPDATE, MIDDLE class DSRestart(service.Service): """ Restart the 389-ds service. """ def __init__(self): """ This class is present to provide ldapupdate the means to restart 389-ds. """ 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) self.start_creation(start_message="Restarting Directory server " "to apply updates", show_service_name=False) class update(Object): """ Generic object used to register all updates into a single namespace. """ backend_name = 'ldap2' api.register(update) class PreUpdate(Updater): """ Base class for updates that run prior to file processing. """ updatetype = PRE_UPDATE order = MIDDLE def __init__(self): super(PreUpdate, self).__init__() class PostUpdate(Updater): """ Base class for updates that run after file processing. """ updatetype = POST_UPDATE order = MIDDLE def __init__(self): super(PostUpdate, self).__init__() freeipa-3.3.4/ipaserver/install/plugins/update_services.py0000664000175000017500000001012412202434255023365 0ustar mkosekmkosek# Authors: # Martin Kosek # # 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors from ipapython.dn import DN from ipapython.ipa_log_manager import * class update_service_principalalias(PostUpdate): """ Update all services which do not have ipakrbprincipalalias attribute used for case-insensitive principal searches filled. This applies for all services created prior IPA 3.0. """ order = MIDDLE def execute(self, **options): ldap = self.obj.backend base_dn = DN(api.env.container_service, api.env.basedn) search_filter = ("(&(objectclass=krbprincipal)(objectclass=ipaservice)" "(!(objectclass=ipakrbprincipal)))") root_logger.debug("update_service_principalalias: search for affected " "services") while True: # run the search in loop to avoid issues when LDAP limits are hit # during update try: (entries, truncated) = ldap.find_entries(search_filter, ['objectclass', 'krbprincipalname'], base_dn, time_limit=0, size_limit=0) except errors.NotFound: root_logger.debug("update_service_principalalias: no service " "to update found") return (False, False, []) except errors.ExecutionError, e: root_logger.error("update_service_principalalias: cannot " "retrieve list of affected services: %s", e) return (False, False, []) if not entries: # no entry was returned, rather break than continue cycling root_logger.debug("update_service_principalalias: no service " "was returned") return (False, False, []) root_logger.debug("update_service_principalalias: found %d " "services to update, truncated: %s", len(entries), truncated) error = False for dn, entry in entries: update = {} update['objectclass'] = (entry['objectclass'] + ['ipakrbprincipal']) update['ipakrbprincipalalias'] = entry['krbprincipalname'] try: ldap.update_entry(dn, update) except (errors.EmptyModlist, errors.NotFound): pass except errors.ExecutionError, e: root_logger.debug("update_service_principalalias: cannot " "update service: %s", e) error = True if error: # exit loop to avoid infinite cycles root_logger.error("update_service_principalalias: error(s)" "detected during service update") return (False, False, []) elif not truncated: # all affected entries updated, exit the loop root_logger.debug("update_service_principalalias: all affected" " services updated") return (False, False, []) return (False, False, []) api.register(update_service_principalalias) freeipa-3.3.4/ipaserver/install/plugins/update_idranges.py0000664000175000017500000001107212271663206023347 0ustar mkosekmkosek# Authors: # Tomas Babej # # Copyright (C) 2013 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 . from ipaserver.install.plugins import MIDDLE from ipaserver.install.plugins.baseupdate import PostUpdate from ipalib import api, errors from ipapython.dn import DN from ipapython.ipa_log_manager import * class update_idrange_type(PostUpdate): """ Update all ID ranges that do not have ipaRangeType attribute filled. This applies to all ID ranges prior to IPA 3.3. """ order = MIDDLE def execute(self, **options): ldap = self.obj.backend base_dn = DN(api.env.container_ranges, api.env.basedn) search_filter = ("(&(objectClass=ipaIDrange)(!(ipaRangeType=*)))") root_logger.debug("update_idrange_type: search for ID ranges with no " "type set") while True: # Run the search in loop to avoid issues when LDAP limits are hit # during update try: (entries, truncated) = ldap.find_entries(search_filter, ['objectclass'], base_dn, time_limit=0, size_limit=0) except errors.NotFound: root_logger.debug("update_idrange_type: no ID range without " "type set found") return (False, False, []) except errors.ExecutionError, e: root_logger.error("update_idrange_type: cannot retrieve list " "of ranges with no type set: %s", e) return (False, False, []) if not entries: # No entry was returned, rather break than continue cycling root_logger.debug("update_idrange_type: no ID range was " "returned") return (False, False, []) root_logger.debug("update_idrange_type: found %d " "idranges to update, truncated: %s", len(entries), truncated) error = False # Set the range type for dn, entry in entries: update = {} objectclasses = [o.lower() for o in entry.get('objectclass', [])] if 'ipatrustedaddomainrange' in objectclasses: # NOTICE: assumes every AD range does not use POSIX # attributes update['ipaRangeType'] = 'ipa-ad-trust' elif 'ipadomainidrange' in objectclasses: update['ipaRangeType'] = 'ipa-local' else: update['ipaRangeType'] = 'unknown' root_logger.error("update_idrange_type: could not detect " "range type for entry: %s" % str(dn)) root_logger.error("update_idrange_type: ID range type set " "to 'unknown' for entry: %s" % str(dn)) try: ldap.update_entry(dn, update) except (errors.EmptyModlist, errors.NotFound): pass except errors.ExecutionError, e: root_logger.debug("update_idrange_type: cannot " "update idrange type: %s", e) error = True if error: # Exit loop to avoid infinite cycles root_logger.error("update_idrange_type: error(s) " "detected during idrange type update") return (False, False, []) elif not truncated: # All affected entries updated, exit the loop root_logger.debug("update_idrange_type: all affected idranges " "were assigned types") return (False, False, []) return (False, False, []) api.register(update_idrange_type) freeipa-3.3.4/ipaserver/install/installutils.py0000664000175000017500000007003012271663206021256 0ustar mkosekmkosek# Authors: Simo Sorce # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import socket import getpass import os import re import fileinput import sys import tempfile import shutil from ConfigParser import SafeConfigParser, NoOptionError import traceback import textwrap from contextlib import contextmanager from dns import resolver, rdatatype from dns.exception import DNSException import ldap from ipapython import ipautil, sysrestore, admintool, dogtag from ipapython.admintool import ScriptError from ipapython.ipa_log_manager import * from ipalib.util import validate_hostname from ipapython import config from ipalib import errors from ipapython.dn import DN from ipaserver.install import certs from ipapython import services as ipaservices # Used to determine install status IPA_MODULES = [ 'httpd', 'kadmin', 'dirsrv', 'pki-cad', 'pki-tomcatd', 'install', 'krb5kdc', 'ntpd', 'named', 'ipa_memcached'] class BadHostError(Exception): pass class HostLookupError(BadHostError): pass class HostForwardLookupError(HostLookupError): pass class HostReverseLookupError(HostLookupError): pass class HostnameLocalhost(HostLookupError): pass class ReplicaConfig: def __init__(self): self.realm_name = "" self.domain_name = "" self.master_host_name = "" self.dirman_password = "" self.host_name = "" self.dir = "" self.subject_base = None self.setup_ca = False self.version = 0 subject_base = ipautil.dn_attribute_property('_subject_base') def get_fqdn(): fqdn = "" try: fqdn = socket.getfqdn() except: try: fqdn = socket.gethostname() except: fqdn = "" return fqdn def verify_fqdn(host_name, no_host_dns=False, local_hostname=True): """ Run fqdn checks for given host: - test hostname format - test that hostname is fully qualified - test forward and reverse hostname DNS lookup Raises `BadHostError` or derived Exceptions if there is an error :param host_name: The host name to verify. :param no_host_dns: If true, skip DNS resolution tests of the host name. :param local_hostname: If true, run additional checks for local hostnames """ if len(host_name.split(".")) < 2 or host_name == "localhost.localdomain": raise BadHostError("Invalid hostname '%s', must be fully-qualified." % host_name) if host_name != host_name.lower(): raise BadHostError("Invalid hostname '%s', must be lower-case." % host_name) if ipautil.valid_ip(host_name): raise BadHostError("IP address not allowed as a hostname") try: # make sure that the host name meets the requirements in ipalib validate_hostname(host_name) except ValueError, e: raise BadHostError("Invalid hostname '%s', %s" % (host_name, unicode(e))) if local_hostname: try: root_logger.debug('Check if %s is a primary hostname for localhost', host_name) ex_name = socket.gethostbyaddr(host_name) root_logger.debug('Primary hostname for localhost: %s', ex_name[0]) if host_name != ex_name[0]: raise HostLookupError("The host name %s does not match the primary host name %s. "\ "Please check /etc/hosts or DNS name resolution" % (host_name, ex_name[0])) except socket.gaierror: pass except socket.error, e: root_logger.debug('socket.gethostbyaddr() error: %d: %s' % (e.errno, e.strerror)) if no_host_dns: print "Warning: skipping DNS resolution of host", host_name return try: root_logger.debug('Search DNS for %s', host_name) hostaddr = socket.getaddrinfo(host_name, None) except Exception, e: root_logger.debug('Search failed: %s', e) raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") if len(hostaddr) == 0: raise HostForwardLookupError("Unable to resolve host name, check /etc/hosts or DNS name resolution") # Verify this is NOT a CNAME try: root_logger.debug('Check if %s is not a CNAME', host_name) resolver.query(host_name, rdatatype.CNAME) raise HostReverseLookupError("The IPA Server Hostname cannot be a CNAME, only A and AAAA names are allowed.") except DNSException: pass # list of verified addresses to prevent multiple searches for the same address verified = set() for a in hostaddr: address = a[4][0] if address in verified: continue if address == '127.0.0.1' or address == '::1': raise HostForwardLookupError("The IPA Server hostname must not resolve to localhost (%s). A routable IP address must be used. Check /etc/hosts to see if %s is an alias for %s" % (address, host_name, address)) try: root_logger.debug('Check reverse address of %s', address) revname = socket.gethostbyaddr(address)[0] except Exception, e: root_logger.debug('Check failed: %s', e) raise HostReverseLookupError("Unable to resolve the reverse ip address, check /etc/hosts or DNS name resolution") root_logger.debug('Found reverse name: %s', revname) if revname != host_name: raise HostReverseLookupError("The host name %s does not match the reverse lookup %s" % (host_name, revname)) verified.add(address) def record_in_hosts(ip, host_name=None, file="/etc/hosts"): """ Search record in /etc/hosts - static table lookup for hostnames In case of match, returns a tuple of ip address and a list of hostname aliases When no record is matched, None is returned :param ip: IP address :param host_name: Optional hostname to search :param file: Optional path to the lookup table """ hosts = open(file, 'r').readlines() for line in hosts: line = line.rstrip('\n') fields = line.partition('#')[0].split() if len(fields) == 0: continue try: hosts_ip = fields[0] names = fields[1:] if hosts_ip != ip: continue if host_name is not None: if host_name in names: return (hosts_ip, names) else: return None return (hosts_ip, names) except IndexError: print "Warning: Erroneous line '%s' in %s" % (line, file) continue return None def add_record_to_hosts(ip, host_name, file="/etc/hosts"): hosts_fd = open(file, 'r+') hosts_fd.seek(0, 2) hosts_fd.write(ip+'\t'+host_name+' '+host_name.split('.')[0]+'\n') hosts_fd.close() def read_ip_address(host_name, fstore): while True: ip = ipautil.user_input("Please provide the IP address to be used for this host name", allow_empty = False) try: ip_parsed = ipautil.CheckedIPAddress(ip, match_local=True) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) continue else: break return ip_parsed def read_dns_forwarders(): addrs = [] if ipautil.user_input("Do you want to configure DNS forwarders?", True): print "Enter the IP address of DNS forwarder to use, or press Enter to finish." while True: ip = ipautil.user_input("Enter IP address for a DNS forwarder", allow_empty=True) if not ip: break try: ip_parsed = ipautil.CheckedIPAddress(ip, parse_netmask=False) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) print "DNS forwarder %s not added" % ip continue print "DNS forwarder %s added" % ip addrs.append(str(ip_parsed)) if not addrs: print "No DNS forwarders configured" return addrs def get_password(prompt): if os.isatty(sys.stdin.fileno()): return getpass.getpass(prompt) else: sys.stdout.write(prompt) sys.stdout.flush() line = sys.stdin.readline() if not line: raise EOFError() return line.rstrip() def _read_password_default_validator(password): if len(password) < 8: raise ValueError("Password must be at least 8 characters long") def read_password(user, confirm=True, validate=True, retry=True, validator=_read_password_default_validator): correct = False pwd = None try: while not correct: if not retry: correct = True pwd = get_password(user + " password: ") if not pwd: continue if validate: try: validator(pwd) except ValueError, e: print str(e) pwd = None continue if not confirm: correct = True continue pwd_confirm = get_password("Password (confirm): ") if pwd != pwd_confirm: print "Password mismatch!" print "" pwd = None else: correct = True except EOFError: return None finally: print "" return pwd def update_file(filename, orig, subst): if os.path.exists(filename): st = os.stat(filename) pattern = "%s" % re.escape(orig) p = re.compile(pattern) for line in fileinput.input(filename, inplace=1): if not p.search(line): sys.stdout.write(line) else: sys.stdout.write(p.sub(subst, line)) fileinput.close() os.chown(filename, st.st_uid, st.st_gid) # reset perms return 0 else: print "File %s doesn't exist." % filename return 1 def set_directive(filename, directive, value, quotes=True, separator=' '): """Set a name/value pair directive in a configuration file. A value of None means to drop the directive. This has only been tested with nss.conf """ valueset = False st = os.stat(filename) fd = open(filename) newfile = [] for line in fd: if line.lstrip().startswith(directive): valueset = True if value is not None: if quotes: newfile.append('%s%s"%s"\n' % (directive, separator, value)) else: newfile.append('%s%s%s\n' % (directive, separator, value)) else: newfile.append(line) fd.close() if not valueset: if value is not None: if quotes: newfile.append('%s%s"%s"\n' % (directive, separator, value)) else: newfile.append('%s%s%s\n' % (directive, separator, value)) fd = open(filename, "w") fd.write("".join(newfile)) fd.close() os.chown(filename, st.st_uid, st.st_gid) # reset perms def get_directive(filename, directive, separator=' '): """ A rather inefficient way to get a configuration directive. """ fd = open(filename, "r") for line in fd: if line.lstrip().startswith(directive): line = line.strip() result = line.split(separator, 1)[1] result = result.strip('"') result = result.strip(' ') fd.close() return result fd.close() return None def kadmin(command): ipautil.run(["kadmin.local", "-q", command, "-x", "ipa-setup-override-restrictions"]) def kadmin_addprinc(principal): kadmin("addprinc -randkey " + principal) def kadmin_modprinc(principal, options): kadmin("modprinc " + options + " " + principal) def create_keytab(path, principal): try: if ipautil.file_exists(path): os.remove(path) except os.error: root_logger.critical("Failed to remove %s." % path) kadmin("ktadd -k " + path + " " + principal) def resolve_host(host_name): try: addrinfos = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM) ip_list = [] for ai in addrinfos: ip = ai[4][0] if ip == "127.0.0.1" or ip == "::1": raise HostnameLocalhost("The hostname resolves to the localhost address") ip_list.append(ip) return ip_list except socket.error: return [] def get_host_name(no_host_dns): """ Get the current FQDN from the socket and verify that it is valid. no_host_dns is a boolean that determines whether we enforce that the hostname is resolvable. Will raise a RuntimeError on error, returns hostname on success """ hostname = get_fqdn() verify_fqdn(hostname, no_host_dns) return hostname def get_server_ip_address(host_name, fstore, unattended, options): # Check we have a public IP that is associated with the hostname try: hostaddr = resolve_host(host_name) except 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, "The KDC service does not listen on localhost" print >> sys.stderr, "" print >> sys.stderr, "Please fix your /etc/hosts file and restart the setup program" sys.exit(1) ip_add_to_hosts = False if len(hostaddr) > 1: print >> sys.stderr, "The server hostname resolves to more than one address:" for addr in hostaddr: print >> sys.stderr, " %s" % addr if options.ip_address: if str(options.ip_address) not in hostaddr: print >> sys.stderr, "Address passed in --ip-address did not match any resolved" print >> sys.stderr, "address!" sys.exit(1) print "Selected IP address:", str(options.ip_address) ip = options.ip_address else: if unattended: print >> sys.stderr, "Please use --ip-address option to specify the address" sys.exit(1) else: ip = read_ip_address(host_name, fstore) elif len(hostaddr) == 1: try: ip = ipautil.CheckedIPAddress(hostaddr[0], match_local=True) except ValueError, e: sys.exit("Invalid IP Address %s for %s: %s" % (hostaddr[0], host_name, unicode(e))) else: # hostname is not resolvable ip = options.ip_address ip_add_to_hosts = True if ip is None: print "Unable to resolve IP address for host name" if unattended: sys.exit(1) if options.ip_address: if options.ip_address != ip and not options.setup_dns: print >>sys.stderr, "Error: the hostname resolves to an IP address that is different" print >>sys.stderr, "from the one provided on the command line. Please fix your DNS" print >>sys.stderr, "or /etc/hosts file and restart the installation." sys.exit(1) ip = options.ip_address if ip is None: ip = read_ip_address(host_name, fstore) root_logger.debug("read ip_address: %s\n" % str(ip)) ip_address = str(ip) # check /etc/hosts sanity, add a record when needed hosts_record = record_in_hosts(ip_address) if hosts_record is None: if ip_add_to_hosts: print "Adding ["+ip_address+" "+host_name+"] to your /etc/hosts file" fstore.backup_file("/etc/hosts") add_record_to_hosts(ip_address, host_name) else: primary_host = hosts_record[1][0] if primary_host != host_name: print >>sys.stderr, "Error: there is already a record in /etc/hosts for IP address %s:" \ % ip_address print >>sys.stderr, hosts_record[0], " ".join(hosts_record[1]) print >>sys.stderr, "Chosen hostname %s does not match configured canonical hostname %s" \ % (host_name, primary_host) print >>sys.stderr, "Please fix your /etc/hosts file and restart the installation." sys.exit(1) return ip def expand_replica_info(filename, password): """ Decrypt and expand a replica installation file into a temporary location. The caller is responsible to remove this directory. """ top_dir = tempfile.mkdtemp("ipa") tarfile = top_dir+"/files.tar" dir = top_dir + "/realm_info" ipautil.decrypt_file(filename, tarfile, password, top_dir) ipautil.run(["tar", "xf", tarfile, "-C", top_dir]) os.remove(tarfile) return top_dir, dir def read_replica_info(dir, rconfig): """ Read the contents of a replica installation file. rconfig is a ReplicaConfig object """ filename = dir + "/realm_info" fd = open(filename) config = SafeConfigParser() config.readfp(fd) rconfig.realm_name = config.get("realm", "realm_name") rconfig.master_host_name = config.get("realm", "master_host_name") rconfig.domain_name = config.get("realm", "domain_name") rconfig.host_name = config.get("realm", "destination_host") rconfig.subject_base = config.get("realm", "subject_base") try: rconfig.version = int(config.get("realm", "version")) except NoOptionError: pass def check_server_configuration(): """ Check if IPA server is configured on the system. This is done by checking if there are system restore (uninstall) files present on the system. Note that this check can only be run with root privileges. When IPA is not configured, this function raises a RuntimeError exception. Most convenient use case for the function is in install tools that require configured IPA for its function. """ server_fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') if not server_fstore.has_files(): raise RuntimeError("IPA is not configured on this system.") def remove_file(filename): """ Remove a file and log any exceptions raised. """ try: if os.path.exists(filename): os.unlink(filename) except Exception, e: root_logger.error('Error removing %s: %s' % (filename, str(e))) def rmtree(path): """ Remove a directory structure and log any exceptions raised. """ try: if os.path.exists(path): shutil.rmtree(path) except Exception, e: root_logger.error('Error removing %s: %s' % (path, str(e))) def is_ipa_configured(): """ Using the state and index install files determine if IPA is already configured. """ installed = False sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') for module in IPA_MODULES: if sstore.has_state(module): root_logger.debug('%s is configured' % module) installed = True else: root_logger.debug('%s is not configured' % module) if fstore.has_files(): root_logger.debug('filestore has files') installed = True else: root_logger.debug('filestore is tracking no files') return installed def run_script(main_function, operation_name, log_file_name=None, fail_message=None): """Run the given function as a command-line utility This function: - Runs the given function - Formats any errors - Exits with the appropriate code :param main_function: Function to call :param log_file_name: Name of the log file (displayed on unexpected errors) :param operation_name: Name of the script :param fail_message: Optional message displayed on failure """ root_logger.info('Starting script: %s', operation_name) try: try: return_value = main_function() except BaseException, e: if isinstance(e, SystemExit) and (e.code is None or e.code == 0): # Not an error after all root_logger.info('The %s command was successful', operation_name) else: # Log at the DEBUG level, which is not output to the console # (unless in debug/verbose mode), but is written to a logfile # if one is open. tb = sys.exc_info()[2] root_logger.debug('\n'.join(traceback.format_tb(tb))) root_logger.debug('The %s command failed, exception: %s: %s', operation_name, type(e).__name__, e) if fail_message and not isinstance(e, SystemExit): print fail_message raise else: if return_value: root_logger.info('The %s command failed, return value %s', operation_name, return_value) else: root_logger.info('The %s command was successful', operation_name) sys.exit(return_value) except BaseException, error: 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. Returns a message and return code""" if isinstance(error, SystemExit): 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): return str(error), 1 if isinstance(error, KeyboardInterrupt): return "Cancelled.", 1 if isinstance(error, admintool.ScriptError): return error.msg, error.rval if isinstance(error, socket.error): return error, 1 if isinstance(error, ldap.INVALID_CREDENTIALS): return "Invalid password", 1 if isinstance(error, ldap.INSUFFICIENT_ACCESS): return "Insufficient access", 1 if isinstance(error, ldap.LOCAL_ERROR): return error.args[0]['info'], 1 if isinstance(error, ldap.SERVER_DOWN): return error.args[0]['desc'], 1 if isinstance(error, ldap.LDAPError): return 'LDAP error: %s\n%s' % ( type(error).__name__, error.args[0]['info']), 1 if isinstance(error, config.IPAConfigError): 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): return "An error occurred while performing operations: %s" % error, 1 if isinstance(error, HostnameLocalhost): 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: message = "Unexpected error - see %s for details:" % log_file_name else: message = "Unexpected error" message += '\n%s: %s' % (type(error).__name__, error) return message, 1 def check_pkcs12(pkcs12_info, ca_file, hostname): """Check the given PKCS#12 with server cert and return the cert nickname This is used for files given to --*_pkcs12 to ipa-server-install and ipa-replica-prepare. Return a (server cert name, CA cert names) tuple """ pkcs12_filename, pkcs12_passwd = pkcs12_info root_logger.debug('Checking PKCS#12 certificate %s', pkcs12_filename) db_pwd_file = ipautil.write_tmp_file(ipautil.ipa_generate_password()) with certs.NSSDatabase() as nssdb: nssdb.create_db(db_pwd_file.name) # Import the CA cert first so it has a known nickname # (if it's present in the PKCS#12 it won't be overwritten) ca_cert_name = 'The Root CA' try: nssdb.import_pem_cert(ca_cert_name, "CT,C,C", ca_file) except (ValueError, RuntimeError) as e: raise ScriptError(str(e)) # Import everything in the PKCS#12 nssdb.import_pkcs12(pkcs12_filename, db_pwd_file.name, pkcs12_passwd) # Check we have exactly one server cert (one with a private key) server_certs = nssdb.find_server_certs() if not server_certs: raise ScriptError( 'no server certificate found in %s' % pkcs12_filename) if len(server_certs) > 1: raise ScriptError( '%s server certificates found in %s, expecting only one' % (len(server_certs), pkcs12_filename)) [(server_cert_name, server_cert_trust)] = server_certs # Check we have the whole cert chain & the CA is in it trust_chain = nssdb.get_trust_chain(server_cert_name) while trust_chain: if trust_chain[0] == ca_cert_name: break trust_chain = trust_chain[1:] else: raise ScriptError( '%s is not signed by %s, or the full certificate chain is not ' 'present in the PKCS#12 file' % (pkcs12_filename, ca_file)) if len(trust_chain) != 2: raise ScriptError( 'trust chain of the server certificate in %s contains %s ' 'certificates, expected 2' % (pkcs12_filename, len(trust_chain))) # Check server validity try: nssdb.verify_server_cert_validity(server_cert_name, hostname) except ValueError as e: raise ScriptError( 'The server certificate in %s is not valid: %s' % (pkcs12_filename, e)) return server_cert_name @contextmanager def private_ccache(path=None): if path is None: (desc, path) = tempfile.mkstemp(prefix='krbcc') os.close(desc) original_value = os.environ.get('KRB5CCNAME', None) os.environ['KRB5CCNAME'] = path try: yield finally: if original_value is not None: os.environ['KRB5CCNAME'] = original_value else: os.environ.pop('KRB5CCNAME') if os.path.exists(path): os.remove(path) @contextmanager def stopped_service(service, instance_name=""): """ Ensure that the specified service is stopped while the commands within this context are executed. Service is started at the end of the execution. """ if instance_name: log_instance_name = "@{instance}".format(instance=instance_name) else: log_instance_name = "" root_logger.debug('Ensuring that service %s%s is not running while ' 'the next set of commands is being executed.', service, log_instance_name) # Figure out if the service is running, if not, yield if not ipaservices.knownservices[service].is_running(instance_name): root_logger.debug('Service %s%s is not running, continue.', service, log_instance_name) yield else: # Stop the service, do the required stuff and start it again root_logger.debug('Stopping %s%s.', service, log_instance_name) ipaservices.knownservices[service].stop(instance_name) try: yield finally: root_logger.debug('Starting %s%s.', service, log_instance_name) ipaservices.knownservices[service].start(instance_name) freeipa-3.3.4/ipaserver/install/ntpinstance.py0000664000175000017500000001350612271663206021062 0ustar mkosekmkosek# Authors: Karl MacMillan # Authors: Simo Sorce # # Copyright (C) 2007-2010 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 . # import service from ipapython import sysrestore from ipapython import ipautil from ipapython.ipa_log_manager import * class NTPInstance(service.Service): def __init__(self, fstore=None): service.Service.__init__(self, "ntpd", service_desc="NTP daemon") if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') def __write_config(self): self.fstore.backup_file("/etc/ntp.conf") self.fstore.backup_file("/etc/sysconfig/ntpd") # We use the OS variable to point it towards either the rhel # or fedora pools. Other distros should be added in the future # or we can get our own pool. os = "" if ipautil.file_exists("/etc/fedora-release"): os = "fedora" elif ipautil.file_exists("/etc/redhat-release"): os = "rhel" srv_vals = [] srv_vals.append("0.%s.pool.ntp.org" % os) srv_vals.append("1.%s.pool.ntp.org" % os) srv_vals.append("2.%s.pool.ntp.org" % os) srv_vals.append("127.127.1.0") fudge = ["fudge", "127.127.1.0", "stratum", "10"] #read in memory, change it, then overwrite file file_changed = False fudge_present = False ntpconf = [] fd = open("/etc/ntp.conf", "r") for line in fd: opt = line.split() if len(opt) < 1: ntpconf.append(line) continue if opt[0] == "server": match = False for srv in srv_vals: if opt[1] == srv: match = True break if match: srv_vals.remove(srv) else: file_changed = True line = "" elif opt[0] == "fudge": if opt[0:4] == fudge[0:4]: fudge_present = True else: file_changed = True line = "" ntpconf.append(line) if file_changed or len(srv_vals) != 0 or not fudge_present: fd = open("/etc/ntp.conf", "w") for line in ntpconf: fd.write(line) fd.write("\n### Added by IPA Installer ###\n") if len(srv_vals) != 0: for srv in srv_vals: fd.write("server "+srv+"\n") if not fudge_present: fd.write("fudge 127.127.1.0 stratum 10\n") fd.close() #read in memory, find OPTIONS, check/change it, then overwrite file needopts = [ {'val':'-x', 'need':True}, {'val':'-g', 'need':True} ] fd = open("/etc/sysconfig/ntpd", "r") lines = fd.readlines() fd.close() for line in lines: sline = line.strip() if not sline.startswith('OPTIONS'): continue sline = sline.replace('"', '') for opt in needopts: if sline.find(opt['val']) != -1: opt['need'] = False newopts = [] for opt in needopts: if opt['need']: newopts.append(opt['val']) done = False if newopts: fd = open("/etc/sysconfig/ntpd", "w") for line in lines: if not done: sline = line.strip() if not sline.startswith('OPTIONS'): fd.write(line) continue sline = sline.replace('"', '') (variable, opts) = sline.split('=', 1) fd.write('OPTIONS="%s %s"\n' % (opts, ' '.join(newopts))) done = True else: fd.write(line) fd.close() def __stop(self): self.backup_state("running", self.is_running()) self.stop() def __start(self): self.start() def __enable(self): self.backup_state("enabled", self.is_enabled()) self.enable() def create_instance(self): # we might consider setting the date manually using ntpd -qg in case # the current time is very far off. self.step("stopping ntpd", self.__stop) self.step("writing configuration", self.__write_config) self.step("configuring ntpd to start on boot", self.__enable) self.step("starting ntpd", self.__start) self.start_creation() def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) running = self.restore_state("running") enabled = self.restore_state("enabled") if not running is None: self.stop() try: self.fstore.restore_file("/etc/ntp.conf") except ValueError, error: root_logger.debug(error) pass if not enabled is None and not enabled: self.disable() if not running is None and running: self.start() freeipa-3.3.4/ipaserver/install/Makefile.am0000664000175000017500000000065212202434255020206 0ustar mkosekmkosekNULL = appdir = $(pythondir)/ipaserver app_PYTHON = \ __init__.py \ bindinstance.py \ cainstance.py \ dsinstance.py \ ipaldap.py \ krbinstance.py \ httpinstance.py \ ntpinstance.py \ adtrustinstance.py \ service.py \ installutils.py \ replication.py \ certs.py \ ldapupdate.py \ certmonger.py \ $(NULL) EXTRA_DIST = \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/ipaserver/install/upgradeinstance.py0000664000175000017500000001247412271663206021713 0ustar mkosekmkosek# Authors: Rob Crittenden # # Copyright (C) 2010 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 . # import os import sys import shutil import random import traceback from ipapython.ipa_log_manager import * from ipaserver.install import installutils from ipaserver.install import dsinstance from ipaserver.install import ldapupdate from ipaserver.install import service DSBASE = '/etc/dirsrv/slapd-' DSE = 'dse.ldif' class IPAUpgrade(service.Service): """ Update the LDAP data in an instance by turning off all network listeners and updating over ldapi. This way we know the server is quiet. """ def __init__(self, realm_name, files=[], live_run=True): """ realm_name: kerberos realm name, used to determine DS instance dir files: list of update files to process. If none use UPDATEDIR live_run: boolean that defines if we are in test or live mode. """ ext = '' rand = random.Random() for i in range(8): h = "%02x" % rand.randint(0,255) ext += h service.Service.__init__(self, "dirsrv") serverid = dsinstance.realm_to_serverid(realm_name) self.filename = '%s%s/%s' % (DSBASE, serverid, DSE) self.savefilename = '%s%s/%s.ipa.%s' % (DSBASE, serverid, DSE, ext) self.live_run = live_run self.files = files self.modified = False self.badsyntax = False self.upgradefailed = False self.serverid = serverid def __start_nowait(self): # Don't wait here because we've turned off port 389. The connection # we make will wait for the socket. super(IPAUpgrade, self).start(wait=False) def __stop_instance(self): """Stop only the main DS instance""" super(IPAUpgrade, self).stop(self.serverid) def create_instance(self): self.step("stopping directory server", self.__stop_instance) self.step("saving configuration", self.__save_config) self.step("disabling listeners", self.__disable_listeners) self.step("starting directory server", self.__start_nowait) self.step("upgrading server", self.__upgrade) self.step("stopping directory server", self.__stop_instance) self.step("restoring configuration", self.__restore_config) self.step("starting directory server", self.start) self.start_creation(start_message="Upgrading IPA:", show_service_name=False) def __save_config(self): shutil.copy2(self.filename, self.savefilename) port = installutils.get_directive(self.filename, 'nsslapd-port', separator=':') security = installutils.get_directive(self.filename, 'nsslapd-security', separator=':') self.backup_state('nsslapd-port', port) self.backup_state('nsslapd-security', security) def __restore_config(self): port = self.restore_state('nsslapd-port') security = self.restore_state('nsslapd-security') installutils.set_directive(self.filename, 'nsslapd-port', port, quotes=False, separator=':') installutils.set_directive(self.filename, 'nsslapd-security', security, quotes=False, separator=':') def __disable_listeners(self): installutils.set_directive(self.filename, 'nsslapd-port', 0, quotes=False, separator=':') installutils.set_directive(self.filename, 'nsslapd-security', 'off', quotes=False, separator=':') installutils.set_directive(self.filename, 'nsslapd-ldapientrysearchbase', None, quotes=False, separator=':') def __upgrade(self): try: ld = ldapupdate.LDAPUpdate(dm_password='', ldapi=True, live_run=self.live_run, plugins=True) if len(self.files) == 0: self.files = ld.get_all_files(ldapupdate.UPDATES_DIR) self.modified = ld.update(self.files, ordered=True) except ldapupdate.BadSyntax, e: root_logger.error('Bad syntax in upgrade %s' % str(e)) self.modified = False self.badsyntax = True except Exception, e: # Bad things happened, return gracefully self.modified = False self.upgradefailed = True root_logger.error('Upgrade failed with %s' % str(e)) root_logger.debug('%s', traceback.format_exc()) def main(): if os.getegid() != 0: print "Must be root to set up server" return 1 update = IPAUpgrade('EXAMPLE.COM') update.create_instance() return 0 try: if __name__ == "__main__": sys.exit(main()) except SystemExit, e: sys.exit(e) except KeyboardInterrupt, e: sys.exit(1) freeipa-3.3.4/ipaserver/install/memcacheinstance.py0000664000175000017500000000164612202434255022017 0ustar mkosekmkosek# Authors: John Dennis # # Copyright (C) 2011 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 . # import service class MemcacheInstance(service.SimpleServiceInstance): def __init__(self): service.SimpleServiceInstance.__init__(self, "ipa_memcached") freeipa-3.3.4/ipaserver/install/bindinstance.py0000664000175000017500000010550112271663206021172 0ustar mkosekmkosek# Authors: Simo Sorce # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import tempfile import os import pwd import netaddr import re import ldap import installutils import service from ipaserver.plugins import ldap2 from ipaserver.install.dsinstance import realm_to_serverid from ipaserver.install.cainstance import IPA_CA_RECORD from ipapython import sysrestore, ipautil, ipaldap from ipapython.ipa_log_manager import * from ipapython.dn import DN import ipalib from ipalib import api, errors from ipalib.util import (validate_zonemgr, normalize_zonemgr, get_dns_forward_zone_update_policy, get_dns_reverse_zone_update_policy, normalize_zone, get_reverse_zone_default, zone_is_reverse) NAMED_CONF = '/etc/named.conf' RESOLV_CONF = '/etc/resolv.conf' named_conf_section_ipa_start_re = re.compile('\s*dynamic-db\s+"ipa"\s+{') named_conf_section_options_start_re = re.compile('\s*options\s+{') named_conf_section_end_re = re.compile('};') named_conf_arg_ipa_re = re.compile(r'(?P\s*)arg\s+"(?P\S+)\s(?P[^"]+)";') named_conf_arg_options_re = re.compile(r'(?P\s*)(?P\S+)\s+"(?P[^"]+)"\s*;') named_conf_arg_ipa_template = "%(indent)sarg \"%(name)s %(value)s\";\n" named_conf_arg_options_template = "%(indent)s%(name)s \"%(value)s\";\n" def check_inst(unattended): has_bind = True # So far this file is always present in both RHEL5 and Fedora if all the necessary # bind packages are installed (RHEL5 requires also the pkg: caching-nameserver) if not os.path.exists('/etc/named.rfc1912.zones'): print "BIND was not found on this system" print "Please install the 'bind' package and start the installation again" has_bind = False # Also check for the LDAP BIND plug-in if not os.path.exists('/usr/lib/bind/ldap.so') and \ not os.path.exists('/usr/lib64/bind/ldap.so'): print "The BIND LDAP plug-in was not found on this system" print "Please install the 'bind-dyndb-ldap' package and start the installation again" has_bind = False if not has_bind: return False if not unattended and os.path.exists(NAMED_CONF): msg = "Existing BIND configuration detected, overwrite?" return ipautil.user_input(msg, False) return True def create_reverse(): return ipautil.user_input("Do you want to configure the reverse zone?", True) def named_conf_exists(): try: named_fd = open(NAMED_CONF, 'r') except IOError: return False lines = named_fd.readlines() named_fd.close() for line in lines: if line.startswith('dynamic-db "ipa"'): return True return False NAMED_SECTION_OPTIONS = "options" NAMED_SECTION_IPA = "ipa" def named_conf_get_directive(name, section=NAMED_SECTION_IPA): """Get a configuration option in bind-dyndb-ldap section of named.conf""" if section == NAMED_SECTION_IPA: named_conf_section_start_re = named_conf_section_ipa_start_re named_conf_arg_re = named_conf_arg_ipa_re elif section == NAMED_SECTION_OPTIONS: named_conf_section_start_re = named_conf_section_options_start_re named_conf_arg_re = named_conf_arg_options_re else: raise NotImplementedError('Section "%s" is not supported' % section) with open(NAMED_CONF, 'r') as f: target_section = False for line in f: if named_conf_section_start_re.match(line): target_section = True continue if named_conf_section_end_re.match(line): if target_section: break if target_section: match = named_conf_arg_re.match(line) if match and name == match.group('name'): return match.group('value') def named_conf_set_directive(name, value, section=NAMED_SECTION_IPA): """ Set configuration option in bind-dyndb-ldap section of named.conf. When the configuration option with given name does not exist, it is added at the end of ipa section in named.conf. If the value is set to None, the configuration option is removed from named.conf. """ new_lines = [] if section == NAMED_SECTION_IPA: named_conf_section_start_re = named_conf_section_ipa_start_re named_conf_arg_re = named_conf_arg_ipa_re named_conf_arg_template = named_conf_arg_ipa_template elif section == NAMED_SECTION_OPTIONS: named_conf_section_start_re = named_conf_section_options_start_re named_conf_arg_re = named_conf_arg_options_re named_conf_arg_template = named_conf_arg_options_template else: raise NotImplementedError('Section "%s" is not supported' % section) with open(NAMED_CONF, 'r') as f: target_section = False matched = False last_indent = "\t" for line in f: if named_conf_section_start_re.match(line): target_section = True if named_conf_section_end_re.match(line): if target_section and not matched and \ value is not None: # create a new conf new_conf = named_conf_arg_template \ % dict(indent=last_indent, name=name, value=value) new_lines.append(new_conf) target_section = False if target_section and not matched: match = named_conf_arg_re.match(line) if match: last_indent = match.group('indent') if name == match.group('name'): matched = True if value is not None: if not isinstance(value, basestring): value = str(value) new_conf = named_conf_arg_template \ % dict(indent=last_indent, name=name, value=value) new_lines.append(new_conf) continue new_lines.append(line) # write new configuration with open(NAMED_CONF, 'w') as f: f.write("".join(new_lines)) def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None): """ Test whether the dns container exists. """ def object_exists(dn): # FIXME, this should be a IPAdmin/ldap2 method so it can be shared """ Test whether the given object exists in LDAP. """ assert isinstance(dn, DN) try: conn.get_entry(dn) except errors.NotFound: return False else: return True assert isinstance(suffix, DN) try: # At install time we may need to use LDAPI to avoid chicken/egg # issues with SSL certs and truting CAs if ldapi: conn = ipaldap.IPAdmin(host=fqdn, ldapi=True, realm=realm) else: conn = ipaldap.IPAdmin(host=fqdn, port=636, cacert=service.CACERT) if dm_password: conn.do_simple_bind(bindpw=dm_password) else: conn.do_sasl_gssapi_bind() except ldap.SERVER_DOWN: raise RuntimeError('LDAP server on %s is not responding. Is IPA installed?' % fqdn) ret = object_exists(DN(('cn', 'dns'), suffix)) conn.unbind() return ret def dns_zone_exists(name): try: zone = api.Command.dnszone_show(unicode(name)) except ipalib.errors.NotFound: return False if len(zone) == 0: return False else: return True def get_reverse_record_name(zone, ip_address): ip = netaddr.IPAddress(ip_address) rev = '.' + normalize_zone(zone) fullrev = '.' + normalize_zone(ip.reverse_dns) if not fullrev.endswith(rev): raise ValueError("IP address does not match reverse zone") return fullrev[1:-len(rev)] def verify_reverse_zone(zone, ip_address): try: get_reverse_record_name(zone, ip_address) except ValueError: print "Invalid reverse zone %s" % zone return False return True def find_reverse_zone(ip_address): ip = netaddr.IPAddress(ip_address) zone = normalize_zone(ip.reverse_dns) while len(zone) > 0: if dns_zone_exists(zone): return zone foo, bar, zone = zone.partition('.') return None def get_reverse_zone(ip_address): return find_reverse_zone(ip_address) or get_reverse_zone_default(ip_address) def read_reverse_zone(default, ip_address): while True: zone = ipautil.user_input("Please specify the reverse zone name", default=default) if not zone: return None if verify_reverse_zone(zone, ip_address): break return normalize_zone(zone) def add_zone(name, zonemgr=None, dns_backup=None, ns_hostname=None, ns_ip_address=None, update_policy=None, force=False): if zone_is_reverse(name): # always normalize reverse zones name = normalize_zone(name) if update_policy is None: if zone_is_reverse(name): update_policy = get_dns_reverse_zone_update_policy(api.env.realm, name) else: update_policy = get_dns_forward_zone_update_policy(api.env.realm) if zonemgr is None: zonemgr = 'hostmaster.%s' % name if ns_hostname is None: # automatically retrieve list of DNS masters dns_masters = api.Object.dnsrecord.get_dns_masters() if not dns_masters: raise installutils.ScriptError( "No IPA server with DNS support found!") ns_main = dns_masters.pop(0) ns_replicas = dns_masters else: ns_main = ns_hostname ns_replicas = [] ns_main = normalize_zone(ns_main) if ns_ip_address is not None: ns_ip_address = unicode(ns_ip_address) try: api.Command.dnszone_add(unicode(name), idnssoamname=unicode(ns_main), idnssoarname=unicode(zonemgr), ip_address=ns_ip_address, idnsallowdynupdate=True, idnsupdatepolicy=unicode(update_policy), idnsallowquery=u'any', idnsallowtransfer=u'none', force=force) except (errors.DuplicateEntry, errors.EmptyModlist): pass nameservers = ns_replicas + [ns_main] for hostname in nameservers: hostname = normalize_zone(hostname) add_ns_rr(name, hostname, dns_backup=None, force=True) def add_rr(zone, name, type, rdata, dns_backup=None, **kwargs): addkw = { '%srecord' % str(type.lower()) : unicode(rdata) } addkw.update(kwargs) try: api.Command.dnsrecord_add(unicode(zone), unicode(name), **addkw) except (errors.DuplicateEntry, errors.EmptyModlist): pass if dns_backup: dns_backup.add(zone, type, name, rdata) def add_fwd_rr(zone, host, ip_address): addr = netaddr.IPAddress(ip_address) if addr.version == 4: add_rr(zone, host, "A", ip_address) elif addr.version == 6: add_rr(zone, host, "AAAA", ip_address) def add_ptr_rr(zone, ip_address, fqdn, dns_backup=None): name = get_reverse_record_name(zone, ip_address) add_rr(zone, name, "PTR", normalize_zone(fqdn), dns_backup) def add_ns_rr(zone, hostname, dns_backup=None, force=True): hostname = normalize_zone(hostname) add_rr(zone, "@", "NS", hostname, dns_backup=dns_backup, force=force) def del_rr(zone, name, type, rdata): delkw = { '%srecord' % str(type.lower()) : unicode(rdata) } try: api.Command.dnsrecord_del(unicode(zone), unicode(name), **delkw) except (errors.NotFound, errors.AttrValueNotFound, errors.EmptyModlist): pass def del_fwd_rr(zone, host, ip_address): addr = netaddr.IPAddress(ip_address) if addr.version == 4: del_rr(zone, host, "A", ip_address) elif addr.version == 6: del_rr(zone, host, "AAAA", ip_address) def get_rr(zone, name, type): rectype = '%srecord' % unicode(type.lower()) ret = api.Command.dnsrecord_find(unicode(zone), unicode(name)) if ret['count'] > 0: for r in ret['result']: if rectype in r: return r[rectype] return [] def get_fwd_rr(zone, host): return [x for t in ("A", "AAAA") for x in get_rr(zone, host, t)] def zonemgr_callback(option, opt_str, value, parser): """ Properly validate and convert --zonemgr Option to IA5String """ # validate the value first try: validate_zonemgr(value) except ValueError, e: parser.error("invalid zonemgr: " + unicode(e)) parser.values.zonemgr = value class DnsBackup(object): def __init__(self, service): self.service = service self.zones = {} def add(self, zone, record_type, host, rdata): """ Backup a DNS record in the file store so it can later be removed. """ if zone not in self.zones: zone_id = len(self.zones) self.zones[zone] = (zone_id, 0) self.service.backup_state("dns_zone_%s" % zone_id, zone) (zone_id, record_id) = self.zones[zone] self.service.backup_state("dns_record_%s_%s" % (zone_id, record_id), "%s %s %s" % (record_type, host, rdata)) self.zones[zone] = (zone_id, record_id + 1) def clear_records(self, have_ldap): """ Remove all records from the file store. If we are connected to ldap, we will also remove them there. """ i = 0 while True: zone = self.service.restore_state("dns_zone_%s" % i) if not zone: return j = 0 while True: dns_record = self.service.restore_state("dns_record_%s_%s" % (i, j)) if not dns_record: break if have_ldap: type, host, rdata = dns_record.split(" ", 2) try: delkw = { '%srecord' % str(type.lower()) : unicode(rdata) } api.Command.dnsrecord_del(unicode(zone), unicode(host), **delkw) except: pass j += 1 i += 1 class BindInstance(service.Service): def __init__(self, fstore=None, dm_password=None): service.Service.__init__(self, "named", service_desc="DNS", dm_password=dm_password, ldapi=False, autobind=service.DISABLED ) self.dns_backup = DnsBackup(self) self.named_user = None self.domain = None self.host = None self.ip_address = None self.realm = None self.forwarders = None self.sub_dict = None self.reverse_zone = None self.dm_password = dm_password if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') suffix = ipautil.dn_attribute_property('_suffix') def setup(self, fqdn, ip_address, realm_name, domain_name, forwarders, ntp, reverse_zone, named_user="named", zonemgr=None, ca_configured=None): self.named_user = named_user self.fqdn = fqdn self.ip_address = ip_address self.realm = realm_name self.domain = domain_name self.forwarders = forwarders self.host = fqdn.split(".")[0] self.suffix = ipautil.realm_to_suffix(self.realm) self.ntp = ntp self.reverse_zone = reverse_zone self.ca_configured = ca_configured if not zonemgr: self.zonemgr = 'hostmaster.%s' % self.domain else: self.zonemgr = normalize_zonemgr(zonemgr) self.first_instance = not dns_container_exists( self.fqdn, self.suffix, realm=self.realm, ldapi=True, dm_password=self.dm_password) self.__setup_sub_dict() @property def host_domain(self): return self.fqdn.split(".", 1)[1] @property def host_in_rr(self): # when a host is not in a default domain, it needs to be referred # with FQDN and not in a domain-relative host name if not self.host_in_default_domain(): return normalize_zone(self.fqdn) return self.host def host_in_default_domain(self): return normalize_zone(self.host_domain) == normalize_zone(self.domain) def create_sample_bind_zone(self): bind_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.zone.db.template", self.sub_dict) [bind_fd, bind_name] = tempfile.mkstemp(".db","sample.zone.") os.write(bind_fd, bind_txt) os.close(bind_fd) print "Sample zone file for bind has been created in "+bind_name def create_instance(self): try: self.stop() except: pass # get a connection to the DS self.ldap_connect() if installutils.record_in_hosts(self.ip_address, self.fqdn) is None: installutils.add_record_to_hosts(self.ip_address, self.fqdn) if self.first_instance: self.step("adding DNS container", self.__setup_dns_container) if dns_zone_exists(self.domain): self.step("adding NS record to the zone", self.__add_self_ns) else: self.step("setting up our zone", self.__setup_zone) if self.reverse_zone is not None: self.step("setting up reverse zone", self.__setup_reverse_zone) self.step("setting up our own record", self.__add_self) if self.first_instance: self.step("setting up records for other masters", self.__add_others) self.step("setting up CA record", self.__add_ipa_ca_record) self.step("setting up kerberos principal", self.__setup_principal) self.step("setting up named.conf", self.__setup_named_conf) self.step("restarting named", self.__start) self.step("configuring named to start on boot", self.__enable) self.step("changing resolv.conf to point to ourselves", self.__setup_resolv_conf) self.start_creation() def __start(self): try: self.backup_state("running", self.is_running()) self.restart() except: print "named service failed to start" def __enable(self): self.backup_state("enabled", self.is_running()) # 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 try: self.ldap_enable('DNS', self.fqdn, self.dm_password, self.suffix) except errors.DuplicateEntry: # service already exists (forced DNS reinstall) # don't crash, just report error root_logger.error("DNS service already exists") def __setup_sub_dict(self): if self.forwarders: fwds = "\n" for forwarder in self.forwarders: fwds += "\t\t%s;\n" % forwarder fwds += "\t" else: fwds = " " if self.ntp: optional_ntp = "\n;ntp server\n" optional_ntp += "_ntp._udp\t\tIN SRV 0 100 123\t%s" % self.host_in_rr else: optional_ntp = "" addr = netaddr.IPAddress(self.ip_address) if addr.version in (4, 6): ipa_ca = "%s\t\t\tIN %s\t\t\t%s\n" % ( IPA_CA_RECORD, "A" if addr.version == 4 else "AAAA", self.ip_address) else: ipa_ca = "" self.sub_dict = dict( FQDN=self.fqdn, IP=self.ip_address, DOMAIN=self.domain, HOST=self.host, REALM=self.realm, SERVER_ID=realm_to_serverid(self.realm), FORWARDERS=fwds, SUFFIX=self.suffix, OPTIONAL_NTP=optional_ntp, ZONEMGR=self.zonemgr, IPA_CA_RECORD=ipa_ca, ) def __setup_dns_container(self): self._ldap_mod("dns.ldif", self.sub_dict) def __setup_zone(self): nameserver_ip_address = self.ip_address if not self.host_in_default_domain(): # Nameserver is in self.host_domain, no forward record added to self.domain nameserver_ip_address = None # Always use force=True as named is not set up yet add_zone(self.domain, self.zonemgr, dns_backup=self.dns_backup, ns_hostname=api.env.host, ns_ip_address=nameserver_ip_address, force=True) add_rr(self.domain, "_kerberos", "TXT", self.realm) def __add_self_ns(self): add_ns_rr(self.domain, api.env.host, self.dns_backup, force=True) def __setup_reverse_zone(self): # Always use force=True as named is not set up yet add_zone(self.reverse_zone, self.zonemgr, ns_hostname=api.env.host, dns_backup=self.dns_backup, force=True) def __add_master_records(self, fqdn, addrs): host, zone = fqdn.split(".", 1) if normalize_zone(zone) == normalize_zone(self.domain): host_in_rr = host else: host_in_rr = normalize_zone(fqdn) srv_records = ( ("_ldap._tcp", "0 100 389 %s" % host_in_rr), ("_kerberos._tcp", "0 100 88 %s" % host_in_rr), ("_kerberos._udp", "0 100 88 %s" % host_in_rr), ("_kerberos-master._tcp", "0 100 88 %s" % host_in_rr), ("_kerberos-master._udp", "0 100 88 %s" % host_in_rr), ("_kpasswd._tcp", "0 100 464 %s" % host_in_rr), ("_kpasswd._udp", "0 100 464 %s" % host_in_rr), ) if self.ntp: srv_records += ( ("_ntp._udp", "0 100 123 %s" % host_in_rr), ) for (rname, rdata) in srv_records: add_rr(self.domain, rname, "SRV", rdata, self.dns_backup) if not dns_zone_exists(zone): # add DNS domain for host first root_logger.debug( "Host domain (%s) is different from DNS domain (%s)!" % ( zone, self.domain)) root_logger.debug("Add DNS zone for host first.") if normalize_zone(zone) == normalize_zone(self.host_domain): ns_ip_address = self.ip_address else: ns_ip_address = None add_zone(zone, self.zonemgr, dns_backup=self.dns_backup, ns_hostname=self.fqdn, ns_ip_address=ns_ip_address, force=True) # Add forward and reverse records to self for addr in addrs: add_fwd_rr(zone, host, addr) reverse_zone = find_reverse_zone(addr) if reverse_zone: add_ptr_rr(reverse_zone, addr, fqdn) def __add_self(self): self.__add_master_records(self.fqdn, [self.ip_address]) def __add_others(self): entries = self.admin_conn.get_entries( DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.suffix), self.admin_conn.SCOPE_ONELEVEL, None, ['dn']) for entry in entries: fqdn = entry.dn[0]['cn'] if fqdn == self.fqdn: continue addrs = installutils.resolve_host(fqdn) root_logger.debug("Adding DNS records for master %s" % fqdn) self.__add_master_records(fqdn, addrs) def __add_ipa_ca_records(self, fqdn, addrs, ca_configured): if ca_configured is False: root_logger.debug("CA is not configured") return elif ca_configured is None: # we do not know if CA is configured for this host and we can # add the CA record. So we need to find out root_logger.debug("Check if CA is enabled for this host") base_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) ldap_filter = '(&(objectClass=ipaConfigObject)(cn=CA))' try: api.Backend.ldap2.find_entries(filter=ldap_filter, base_dn=base_dn) except ipalib.errors.NotFound: root_logger.debug("CA is not configured") return else: root_logger.debug("CA is configured for this host") try: for addr in addrs: add_fwd_rr(self.domain, IPA_CA_RECORD, addr) except errors.ValidationError: # there is a CNAME record in ipa-ca, we can't add A/AAAA records pass def __add_ipa_ca_record(self): self.__add_ipa_ca_records(self.fqdn, [self.ip_address], self.ca_configured) if self.first_instance: ldap = api.Backend.ldap2 try: entries = ldap.get_entries( DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn), ldap.SCOPE_SUBTREE, '(&(objectClass=ipaConfigObject)(cn=CA))', ['dn']) except errors.NotFound: root_logger.debug('No server with CA found') entries = [] for entry in entries: fqdn = entry.dn[1]['cn'] if fqdn == self.fqdn: continue host, zone = fqdn.split('.', 1) if dns_zone_exists(zone): addrs = get_fwd_rr(zone, host) else: addrs = installutils.resolve_host(fqdn) self.__add_ipa_ca_records(fqdn, addrs, True) def __setup_principal(self): dns_principal = "DNS/" + self.fqdn + "@" + self.realm installutils.kadmin_addprinc(dns_principal) # Store the keytab on disk self.fstore.backup_file("/etc/named.keytab") installutils.create_keytab("/etc/named.keytab", dns_principal) p = self.move_service(dns_principal) if p is None: # the service has already been moved, perhaps we're doing a DNS reinstall dns_principal = DN(('krbprincipalname', dns_principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix) else: dns_principal = p # Make sure access is strictly reserved to the named user pent = pwd.getpwnam(self.named_user) os.chown("/etc/named.keytab", pent.pw_uid, pent.pw_gid) os.chmod("/etc/named.keytab", 0400) # modify the principal so that it is marked as an ipa service so that # it can host the memberof attribute, then also add it to the # dnsserver role group, this way the DNS is allowed to perform # DNS Updates dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'), self.suffix) mod = [(ldap.MOD_ADD, 'member', dns_principal)] try: self.admin_conn.modify_s(dns_group, mod) except ldap.TYPE_OR_VALUE_EXISTS: pass except Exception, e: root_logger.critical("Could not modify principal's %s entry: %s" \ % (dns_principal, str(e))) raise # bind-dyndb-ldap persistent search feature requires both size and time # limit-free connection mod = [(ldap.MOD_REPLACE, 'nsTimeLimit', '-1'), (ldap.MOD_REPLACE, 'nsSizeLimit', '-1'), (ldap.MOD_REPLACE, 'nsIdleTimeout', '-1'), (ldap.MOD_REPLACE, 'nsLookThroughLimit', '-1')] try: self.admin_conn.modify_s(dns_principal, mod) except Exception, e: root_logger.critical("Could not set principal's %s LDAP limits: %s" \ % (dns_principal, str(e))) raise def __setup_named_conf(self): self.fstore.backup_file(NAMED_CONF) named_txt = ipautil.template_file(ipautil.SHARE_DIR + "bind.named.conf.template", self.sub_dict) named_fd = open(NAMED_CONF, 'w') named_fd.seek(0) named_fd.truncate(0) named_fd.write(named_txt) named_fd.close() def __setup_resolv_conf(self): self.fstore.backup_file(RESOLV_CONF) resolv_txt = "search "+self.domain+"\nnameserver "+self.ip_address+"\n" resolv_fd = open(RESOLV_CONF, 'w') resolv_fd.seek(0) resolv_fd.truncate(0) resolv_fd.write(resolv_txt) resolv_fd.close() def add_master_dns_records(self, fqdn, ip_address, realm_name, domain_name, reverse_zone, ntp=False, ca_configured=None): self.fqdn = fqdn self.ip_address = ip_address self.realm = realm_name self.domain = domain_name self.host = fqdn.split(".")[0] self.suffix = ipautil.realm_to_suffix(self.realm) self.ntp = ntp self.reverse_zone = reverse_zone self.ca_configured = ca_configured self.first_instance = False self.__add_self() self.__add_ipa_ca_record() def add_ipa_ca_dns_records(self, fqdn, domain_name, ca_configured=True): host, zone = fqdn.split(".", 1) if dns_zone_exists(zone): addrs = get_fwd_rr(zone, host) else: addrs = installutils.resolve_host(fqdn) self.domain = domain_name self.__add_ipa_ca_records(fqdn, addrs, ca_configured) def convert_ipa_ca_cnames(self, domain_name): # get ipa-ca CNAMEs cnames = get_rr(domain_name, IPA_CA_RECORD, "CNAME") if not cnames: return root_logger.info('Converting IPA CA CNAME records to A/AAAA records') # create CNAME to FQDN mapping cname_fqdn = {} for cname in cnames: if cname.endswith('.'): fqdn = cname[:-1] else: fqdn = '%s.%s' % (cname, domain_name) cname_fqdn[cname] = fqdn # get FQDNs of all IPA masters ldap = api.Backend.ldap2 try: entries = ldap.get_entries( DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn), ldap.SCOPE_ONELEVEL, None, ['cn']) masters = set(e['cn'][0] for e in entries) except errors.NotFound: masters = set() # check if all CNAMEs point to IPA masters for cname in cnames: fqdn = cname_fqdn[cname] if fqdn not in masters: root_logger.warning( "Cannot convert IPA CA CNAME records to A/AAAA records, " "please convert them manually if necessary") return # delete all CNAMEs for cname in cnames: del_rr(domain_name, IPA_CA_RECORD, "CNAME", cname) # add A/AAAA records for cname in cnames: fqdn = cname_fqdn[cname] self.add_ipa_ca_dns_records(fqdn, domain_name, None) def remove_master_dns_records(self, fqdn, realm_name, domain_name): host, zone = fqdn.split(".", 1) self.host = host self.fqdn = fqdn self.domain = domain_name suffix = ipautil.realm_to_suffix(realm_name) resource_records = ( ("_ldap._tcp", "SRV", "0 100 389 %s" % self.host_in_rr), ("_kerberos._tcp", "SRV", "0 100 88 %s" % self.host_in_rr), ("_kerberos._udp", "SRV", "0 100 88 %s" % self.host_in_rr), ("_kerberos-master._tcp", "SRV", "0 100 88 %s" % self.host_in_rr), ("_kerberos-master._udp", "SRV", "0 100 88 %s" % self.host_in_rr), ("_kpasswd._tcp", "SRV", "0 100 464 %s" % self.host_in_rr), ("_kpasswd._udp", "SRV", "0 100 464 %s" % self.host_in_rr), ("_ntp._udp", "SRV", "0 100 123 %s" % self.host_in_rr), ("@", "NS", normalize_zone(fqdn)), ) for (record, type, rdata) in resource_records: del_rr(self.domain, record, type, rdata) areclist = get_fwd_rr(zone, host) for rdata in areclist: del_fwd_rr(zone, host, rdata) rzone = find_reverse_zone(rdata) if rzone is not None: record = get_reverse_record_name(rzone, rdata) del_rr(rzone, record, "PTR", normalize_zone(fqdn)) # remove also master NS record from the reverse zone del_rr(rzone, "@", "NS", normalize_zone(fqdn)) def remove_ipa_ca_dns_records(self, fqdn, domain_name): host, zone = fqdn.split(".", 1) if dns_zone_exists(zone): addrs = get_fwd_rr(zone, host) else: addrs = installutils.resolve_host(fqdn) for addr in addrs: del_fwd_rr(domain_name, IPA_CA_RECORD, addr) def check_global_configuration(self): """ Check global DNS configuration in LDAP server and inform user when it set and thus overrides his configured options in named.conf. """ result = api.Command.dnsconfig_show() global_conf_set = any(param in result['result'] for \ param in api.Object['dnsconfig'].params) if not global_conf_set: print "Global DNS configuration in LDAP server is empty" print "You can use 'dnsconfig-mod' command to set global DNS options that" print "would override settings in local named.conf files" return print "Global DNS configuration in LDAP server is not empty" print "The following configuration options override local settings in named.conf:" print "" textui = ipalib.cli.textui() api.Command.dnsconfig_show.output_for_cli(textui, result, None, reverse=False) def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) running = self.restore_state("running") enabled = self.restore_state("enabled") self.dns_backup.clear_records(api.Backend.ldap2.isconnected()) if not running is None: self.stop() for f in [NAMED_CONF, RESOLV_CONF]: try: self.fstore.restore_file(f) except ValueError, error: root_logger.debug(error) pass if not enabled is None and not enabled: self.disable() if not running is None and running: self.start() freeipa-3.3.4/ipaserver/install/krbinstance.py0000664000175000017500000004566312271663206021050 0ustar mkosekmkosek# Authors: Simo Sorce # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import shutil import fileinput import re import sys import os import pwd import socket import dns.name import service import installutils from ipapython import sysrestore from ipapython import ipautil from ipapython import services as ipaservices from ipapython import kernel_keyring from ipalib import errors from ipapython.ipa_log_manager import * from ipapython.dn import DN from ipaserver.install import replication from ipaserver.install import dsinstance import pyasn1.codec.ber.decoder import struct import certs from distutils import version def update_key_val_in_file(filename, key, val): if os.path.exists(filename): pattern = "^[\s#]*%s\s*=\s*%s\s*" % (re.escape(key), re.escape(val)) p = re.compile(pattern) for line in fileinput.input(filename): if p.search(line): fileinput.close() return fileinput.close() pattern = "^[\s#]*%s\s*=" % re.escape(key) p = re.compile(pattern) for line in fileinput.input(filename, inplace=1): if not p.search(line): sys.stdout.write(line) fileinput.close() f = open(filename, "a") f.write("%s=%s\n" % (key, val)) f.close() class KpasswdInstance(service.SimpleServiceInstance): def __init__(self): service.SimpleServiceInstance.__init__(self, "kadmin") class KrbInstance(service.Service): def __init__(self, fstore=None): service.Service.__init__(self, "krb5kdc", service_desc="Kerberos KDC") self.fqdn = None self.realm = None self.domain = None self.host = None self.admin_password = None self.master_password = None self.suffix = None self.subject_base = None self.kdc_password = None self.sub_dict = None self.pkcs12_info = None if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') suffix = ipautil.dn_attribute_property('_suffix') subject_base = ipautil.dn_attribute_property('_subject_base') def get_realm_suffix(self): return DN(('cn', self.realm), ('cn', 'kerberos'), self.suffix) def move_service_to_host(self, principal): """ Used to move a host/ service principal created by kadmin.local from cn=kerberos to reside under the host entry. """ service_dn = DN(('krbprincipalname', principal), self.get_realm_suffix()) service_entry = self.admin_conn.get_entry(service_dn) self.admin_conn.delete_entry(service_entry) # Create a host entry for this master host_dn = DN( ('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix) host_entry = self.admin_conn.make_entry( host_dn, objectclass=[ 'top', 'ipaobject', 'nshost', 'ipahost', 'ipaservice', 'pkiuser', 'krbprincipalaux', 'krbprincipal', 'krbticketpolicyaux', 'ipasshhost'], krbextradata=service_entry['krbextradata'], krblastpwdchange=service_entry['krblastpwdchange'], krbprincipalname=service_entry['krbprincipalname'], krbprincipalkey=service_entry['krbprincipalkey'], serverhostname=[self.fqdn.split('.',1)[0]], cn=[self.fqdn], fqdn=[self.fqdn], ipauniqueid=['autogenerate'], managedby=[host_dn], ) if 'krbpasswordexpiration' in service_entry.toDict(): host_entry['krbpasswordexpiration'] = service_entry[ 'krbpasswordexpiration'] if 'krbticketflags' in service_entry.toDict(): host_entry['krbticketflags'] = service_entry['krbticketflags'] self.admin_conn.add_entry(host_entry) def __common_setup(self, realm_name, host_name, domain_name, admin_password): self.fqdn = host_name self.realm = realm_name.upper() self.host = host_name.split(".")[0] self.ip = socket.getaddrinfo(host_name, None, socket.AF_UNSPEC, socket.SOCK_STREAM)[0][4][0] self.domain = domain_name self.suffix = ipautil.realm_to_suffix(self.realm) self.kdc_password = ipautil.ipa_generate_password() self.admin_password = admin_password self.dm_password = admin_password self.__setup_sub_dict() # get a connection to the DS self.ldap_connect() self.backup_state("running", self.is_running()) try: self.stop() except: # It could have been not running pass def __common_post_setup(self): self.step("starting the KDC", self.__start_instance) self.step("configuring KDC to start on boot", self.__enable) def create_instance(self, realm_name, host_name, domain_name, admin_password, master_password, setup_pkinit=False, pkcs12_info=None, subject_base=None): self.master_password = master_password self.pkcs12_info = pkcs12_info self.subject_base = subject_base self.__common_setup(realm_name, host_name, domain_name, admin_password) self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) self.step("adding kerberos container to the directory", self.__add_krb_container) self.step("configuring KDC", self.__configure_instance) self.step("initialize kerberos container", self.__init_ipa_kdb) self.step("adding default ACIs", self.__add_default_acis) self.step("creating a keytab for the directory", self.__create_ds_keytab) self.step("creating a keytab for the machine", self.__create_host_keytab) self.step("adding the password extension to the directory", self.__add_pwd_extop_module) if setup_pkinit: self.step("creating X509 Certificate for PKINIT", self.__setup_pkinit) self.step("creating principal for anonymous PKINIT", self.__add_anonymous_pkinit_principal) self.__common_post_setup() self.start_creation(runtime=30) self.kpasswd = KpasswdInstance() 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, domain_name, admin_password, setup_pkinit=False, pkcs12_info=None, subject_base=None): self.pkcs12_info = pkcs12_info self.subject_base = subject_base self.master_fqdn = master_fqdn self.__common_setup(realm_name, host_name, domain_name, admin_password) self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings) self.step("writing stash file from DS", self.__write_stash_from_ds) self.step("configuring KDC", self.__configure_instance) self.step("creating a keytab for the directory", self.__create_ds_keytab) self.step("creating a keytab for the machine", self.__create_host_keytab) self.step("adding the password extension to the directory", self.__add_pwd_extop_module) if setup_pkinit: self.step("installing X509 Certificate for PKINIT", self.__setup_pkinit) self.step("enable GSSAPI for replication", self.__convert_to_gssapi_replication) self.__common_post_setup() self.start_creation(runtime=30) self.kpasswd = KpasswdInstance() self.kpasswd.create_instance('KPASSWD', self.fqdn, self.admin_password, self.suffix) def __enable(self): self.backup_state("enabled", self.is_enabled()) # 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 self.ldap_enable('KDC', self.fqdn, self.admin_password, self.suffix) def __start_instance(self): try: self.start() except: root_logger.critical("krb5kdc service failed to start") def __setup_sub_dict(self): self.sub_dict = dict(FQDN=self.fqdn, IP=self.ip, PASSWORD=self.kdc_password, SUFFIX=self.suffix, DOMAIN=self.domain, HOST=self.host, SERVER_ID=dsinstance.realm_to_serverid(self.realm), REALM=self.realm) # IPA server/KDC is not a subdomain of default domain # Proper domain-realm mapping needs to be specified domain = dns.name.from_text(self.domain) fqdn = dns.name.from_text(self.fqdn) if not fqdn.is_subdomain(domain): root_logger.debug("IPA FQDN '%s' is not located in default domain '%s'", fqdn, domain) server_domain = fqdn.parent().to_unicode(omit_final_dot=True) root_logger.debug("Domain '%s' needs additional mapping in krb5.conf", server_domain) dr_map = " .%(domain)s = %(realm)s\n %(domain)s = %(realm)s\n" \ % dict(domain=server_domain, realm=self.realm) else: dr_map = "" self.sub_dict['OTHER_DOMAIN_REALM_MAPS'] = dr_map # Configure KEYRING CCACHE if supported if kernel_keyring.is_persistent_keyring_supported(): root_logger.debug("Enabling persistent keyring CCACHE") self.sub_dict['OTHER_LIBDEFAULTS'] = \ " default_ccache_name = KEYRING:persistent:%{uid}\n" else: root_logger.debug("Persistent keyring CCACHE is not enabled") self.sub_dict['OTHER_LIBDEFAULTS'] = '' def __configure_sasl_mappings(self): # we need to remove any existing SASL mappings in the directory as otherwise they # they may conflict. try: res = self.admin_conn.get_entries( DN(('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')), self.admin_conn.SCOPE_ONELEVEL, "(objectclass=nsSaslMapping)") for r in res: try: self.admin_conn.delete_entry(r) except Exception, e: root_logger.critical( "Error during SASL mapping removal: %s", e) raise except Exception, e: root_logger.critical("Error while enumerating SASL mappings %s", e) raise entry = self.admin_conn.make_entry( DN( ('cn', 'Full Principal'), ('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')), objectclass=["top", "nsSaslMapping"], cn=["Full Principal"], nsSaslMapRegexString=['\(.*\)@\(.*\)'], nsSaslMapBaseDNTemplate=[self.suffix], nsSaslMapFilterTemplate=['(krbPrincipalName=\\1@\\2)'], nsSaslMapPriority=['10'], ) self.admin_conn.add_entry(entry) entry = self.admin_conn.make_entry( DN( ('cn', 'Name Only'), ('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')), objectclass=["top", "nsSaslMapping"], cn=["Name Only"], nsSaslMapRegexString=['^[^:@]+$'], nsSaslMapBaseDNTemplate=[self.suffix], nsSaslMapFilterTemplate=['(krbPrincipalName=&@%s)' % self.realm], nsSaslMapPriority=['10'], ) self.admin_conn.add_entry(entry) def __add_krb_container(self): self._ldap_mod("kerberos.ldif", self.sub_dict) def __add_default_acis(self): self._ldap_mod("default-aci.ldif", self.sub_dict) def __template_file(self, path, chmod=0644): template = os.path.join(ipautil.SHARE_DIR, os.path.basename(path) + ".template") conf = ipautil.template_file(template, self.sub_dict) self.fstore.backup_file(path) fd = open(path, "w+") fd.write(conf) fd.close() if chmod is not None: os.chmod(path, chmod) def __init_ipa_kdb(self): #populate the directory with the realm structure args = ["kdb5_util", "create", "-s", "-r", self.realm, "-x", "ipa-setup-override-restrictions"] dialogue = ( # Enter KDC database master key: self.master_password + '\n', # Re-enter KDC database master key to verify: self.master_password + '\n', ) try: ipautil.run(args, nolog=(self.master_password,), stdin=''.join(dialogue)) except ipautil.CalledProcessError, e: print "Failed to initialize the realm container" def __configure_instance(self): self.__template_file("/var/kerberos/krb5kdc/kdc.conf", chmod=None) self.__template_file("/etc/krb5.conf") self.__template_file("/usr/share/ipa/html/krb5.ini") self.__template_file("/usr/share/ipa/html/krb.con") self.__template_file("/usr/share/ipa/html/krbrealm.con") MIN_KRB5KDC_WITH_WORKERS = "1.9" cpus = os.sysconf('SC_NPROCESSORS_ONLN') workers = False (stdout, stderr, rc) = ipautil.run(['klist', '-V'], raiseonerr=False) if rc == 0: verstr = stdout.split()[-1] ver = version.LooseVersion(verstr) min = version.LooseVersion(MIN_KRB5KDC_WITH_WORKERS) if ver >= min: workers = True # Write down config file # We write realm and also number of workers (for multi-CPU systems) replacevars = {'KRB5REALM':self.realm} appendvars = {} if workers and cpus > 1: appendvars = {'KRB5KDC_ARGS': "'-w %s'" % str(cpus)} ipautil.backup_config_and_replace_variables(self.fstore, "/etc/sysconfig/krb5kdc", replacevars=replacevars, appendvars=appendvars) ipaservices.restore_context("/etc/sysconfig/krb5kdc") def __write_stash_from_ds(self): try: entries = self.admin_conn.get_entries( self.get_realm_suffix(), self.admin_conn.SCOPE_SUBTREE) # TODO: Ensure we got only one entry entry = entries[0] except errors.NotFound, e: root_logger.critical("Could not find master key in DS") raise e krbMKey = pyasn1.codec.ber.decoder.decode( entry.single_value('krbmkey', None)) keytype = int(krbMKey[0][1][0]) keydata = str(krbMKey[0][1][1]) format = '=hi%ss' % len(keydata) s = struct.pack(format, keytype, len(keydata), keydata) try: fd = open("/var/kerberos/krb5kdc/.k5."+self.realm, "w") fd.write(s) fd.close() except os.error, e: root_logger.critical("failed to write stash file") raise e #add the password extop module def __add_pwd_extop_module(self): self._ldap_mod("pwd-extop-conf.ldif", self.sub_dict) def __create_ds_keytab(self): ldap_principal = "ldap/" + self.fqdn + "@" + self.realm installutils.kadmin_addprinc(ldap_principal) self.move_service(ldap_principal) self.fstore.backup_file("/etc/dirsrv/ds.keytab") installutils.create_keytab("/etc/dirsrv/ds.keytab", ldap_principal) update_key_val_in_file("/etc/sysconfig/dirsrv", "KRB5_KTNAME", "/etc/dirsrv/ds.keytab") pent = pwd.getpwnam(dsinstance.DS_USER) os.chown("/etc/dirsrv/ds.keytab", pent.pw_uid, pent.pw_gid) def __create_host_keytab(self): host_principal = "host/" + self.fqdn + "@" + self.realm installutils.kadmin_addprinc(host_principal) self.fstore.backup_file("/etc/krb5.keytab") installutils.create_keytab("/etc/krb5.keytab", host_principal) # Make sure access is strictly reserved to root only for now os.chown("/etc/krb5.keytab", 0, 0) os.chmod("/etc/krb5.keytab", 0600) self.move_service_to_host(host_principal) def __setup_pkinit(self): ca_db = certs.CertDB(self.realm, host_name=self.fqdn, subject_base=self.subject_base) if self.pkcs12_info: ca_db.install_pem_from_p12(self.pkcs12_info[0], self.pkcs12_info[1], "/var/kerberos/krb5kdc/kdc.pem") else: raise RuntimeError("PKI not supported yet\n") # Finally copy the cacert in the krb directory so we don't # have any selinux issues with the file context shutil.copyfile("/etc/ipa/ca.crt", "/var/kerberos/krb5kdc/cacert.pem") def __add_anonymous_pkinit_principal(self): princ = "WELLKNOWN/ANONYMOUS" princ_realm = "%s@%s" % (princ, self.realm) # Create the special anonymous principal installutils.kadmin_addprinc(princ_realm) dn = DN(('krbprincipalname', princ_realm), self.get_realm_suffix()) entry = self.admin_conn.get_entry(dn) entry['nsAccountlock'] = ['TRUE'] self.admin_conn.update_entry(entry) def __convert_to_gssapi_replication(self): repl = replication.ReplicationManager(self.realm, self.fqdn, self.dm_password) repl.convert_to_gssapi_replication(self.master_fqdn, r_binddn=DN(('cn', 'Directory Manager')), r_bindpw=self.dm_password) def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) running = self.restore_state("running") enabled = self.restore_state("enabled") try: self.stop() except: pass for f in ["/var/kerberos/krb5kdc/kdc.conf", "/etc/krb5.conf"]: try: self.fstore.restore_file(f) except ValueError, error: root_logger.debug(error) pass if not enabled is None and not enabled: self.disable() if not running is None and running: self.start() self.kpasswd = KpasswdInstance() self.kpasswd.uninstall() freeipa-3.3.4/ipaserver/install/dsinstance.py0000664000175000017500000010351712271663206020671 0ustar mkosekmkosek# Authors: Karl MacMillan # Simo Sorce # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import shutil import pwd import sys import os import re import time import tempfile import base64 import stat import grp from ipapython.ipa_log_manager import * from ipapython import ipautil, sysrestore, ipaldap from ipapython import services as ipaservices import service import installutils import certs import ldap from ipaserver.install import ldapupdate from ipaserver.install import replication from ipaserver.install import sysupgrade from ipalib import errors from ipapython.dn import DN SERVER_ROOT_64 = "/usr/lib64/dirsrv" SERVER_ROOT_32 = "/usr/lib/dirsrv" CACERT="/etc/ipa/ca.crt" DS_USER = 'dirsrv' DS_GROUP = 'dirsrv' def find_server_root(): if ipautil.dir_exists(SERVER_ROOT_64): return SERVER_ROOT_64 else: return SERVER_ROOT_32 def realm_to_serverid(realm_name): return "-".join(realm_name.split(".")) def config_dirname(serverid): return "/etc/dirsrv/slapd-" + serverid + "/" def schema_dirname(serverid): return config_dirname(serverid) + "/schema/" def erase_ds_instance_data(serverid): installutils.rmtree("/etc/dirsrv/slapd-%s" % serverid) installutils.rmtree("/usr/lib/dirsrv/slapd-%s" % serverid) installutils.rmtree("/usr/lib64/dirsrv/slapd-%s" % serverid) installutils.rmtree("/var/lib/dirsrv/slapd-%s" % serverid) installutils.rmtree("/var/lock/dirsrv/slapd-%s" % serverid) installutils.remove_file("/var/run/slapd-%s.socket" % serverid) installutils.rmtree("/var/lib/dirsrv/scripts-%s" % serverid) installutils.remove_file("/etc/dirsrv/ds.keytab") installutils.remove_file("/etc/sysconfig/dirsrv-%s" % serverid) # try: # shutil.rmtree("/var/log/dirsrv/slapd-%s" % serverid) # except: # pass def get_ds_instances(): ''' Return a sorted list of all 389ds instances. If the instance name ends with '.removed' it is ignored. This matches 389ds behavior. ''' dirsrv_instance_dir='/etc/dirsrv' instance_prefix = 'slapd-' instances = [] for basename in os.listdir(dirsrv_instance_dir): pathname = os.path.join(dirsrv_instance_dir, basename) # Must be a directory if os.path.isdir(pathname): # Must start with prefix and not end with .removed if basename.startswith(instance_prefix) and not basename.endswith('.removed'): # Strip off prefix instance = basename[len(instance_prefix):] # Must be non-empty if instance: instances.append(instance) instances.sort() return instances def check_ports(): """ 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=''): return ipaservices.knownservices.dirsrv.is_running(instance_name=server_id) def create_ds_user(): """ Create DS user if it doesn't exist yet. """ try: pwd.getpwnam(DS_USER) root_logger.debug('DS user %s exists', DS_USER) except KeyError: root_logger.debug('Adding DS user %s', DS_USER) args = [ '/usr/sbin/useradd', '-g', DS_GROUP, '-c', 'DS System User', '-d', '/var/lib/dirsrv', '-s', '/sbin/nologin', '-M', '-r', DS_USER ] try: ipautil.run(args) root_logger.debug('Done adding DS user') except ipautil.CalledProcessError, e: root_logger.critical('Failed to add DS user: %s', e) def create_ds_group(): """ Create DS group if it doesn't exist yet. Returns True if the group already exists. """ try: grp.getgrnam(DS_GROUP) root_logger.debug('DS group %s exists', DS_GROUP) group_exists = True except KeyError: group_exists = False root_logger.debug('Adding DS group %s', DS_GROUP) args = ['/usr/sbin/groupadd', '-r', DS_GROUP] try: ipautil.run(args) root_logger.debug('Done adding DS group') except ipautil.CalledProcessError, e: root_logger.critical('Failed to add DS group: %s', e) return group_exists INF_TEMPLATE = """ [General] FullMachineName= $FQDN SuiteSpotUserID= $USER SuiteSpotGroup= $GROUP ServerRoot= $SERVER_ROOT [slapd] ServerPort= 389 ServerIdentifier= $SERVERID Suffix= $SUFFIX RootDN= cn=Directory Manager RootDNPwd= $PASSWORD InstallLdifFile= /var/lib/dirsrv/boot.ldif inst_dir= /var/lib/dirsrv/scripts-$SERVERID """ BASE_TEMPLATE = """ dn: $SUFFIX objectClass: top objectClass: domain objectClass: pilotObject dc: $BASEDC info: IPA V2.0 """ class DsInstance(service.Service): def __init__(self, realm_name=None, domain_name=None, dm_password=None, fstore=None, cert_nickname='Server-Cert'): service.Service.__init__(self, "dirsrv", service_desc="directory server", dm_password=dm_password, ldapi=False, autobind=service.DISABLED ) self.nickname = cert_nickname self.dm_password = dm_password self.realm = realm_name self.sub_dict = None self.domain = domain_name self.serverid = None self.pkcs12_info = None self.ca_is_configured = True self.dercert = None self.idstart = None self.idmax = None self.subject_base = None self.open_ports = [] self.run_init_memberof = True if realm_name: self.suffix = ipautil.realm_to_suffix(self.realm) self.__setup_sub_dict() else: self.suffix = DN() if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') subject_base = ipautil.dn_attribute_property('_subject_base') def __common_setup(self, enable_ssl=False): self.step("creating directory server user", create_ds_user) self.step("creating directory server instance", self.__create_instance) self.step("adding default schema", self.__add_default_schemas) self.step("enabling memberof plugin", self.__add_memberof_module) self.step("enabling winsync plugin", self.__add_winsync_module) self.step("configuring replication version plugin", self.__config_version_module) self.step("enabling IPA enrollment plugin", self.__add_enrollment_module) self.step("enabling ldapi", self.__enable_ldapi) self.step("configuring uniqueness plugin", self.__set_unique_attrs) self.step("configuring uuid plugin", self.__config_uuid_module) self.step("configuring modrdn plugin", self.__config_modrdn_module) self.step("configuring DNS plugin", self.__config_dns_module) self.step("enabling entryUSN plugin", self.__enable_entryusn) self.step("configuring lockout plugin", self.__config_lockout_module) self.step("creating indices", self.__create_indices) self.step("enabling referential integrity plugin", self.__add_referint_module) if enable_ssl: self.step("configuring ssl for ds instance", self.enable_ssl) self.step("configuring certmap.conf", self.__certmap_conf) self.step("configure autobind for root", self.__root_autobind) self.step("configure new location for managed entries", self.__repoint_managed_entries) self.step("configure dirsrv ccache", self.configure_dirsrv_ccache) self.step("enable SASL mapping fallback", self.__enable_sasl_mapping_fallback) self.step("restarting directory server", self.__restart_instance) def __common_post_setup(self): self.step("initializing group membership", self.init_memberof) self.step("adding master entry", self.__add_master_entry) self.step("configuring Posix uid/gid generation", self.__config_uidgid_gen) self.step("adding replication acis", self.__add_replication_acis) self.step("enabling compatibility plugin", self.__enable_compat_plugin) self.step("tuning directory server", self.__tuning) self.step("configuring directory to start on boot", self.__enable) def init_info(self, realm_name, fqdn, domain_name, dm_password, subject_base, idstart, idmax, pkcs12_info, ca_file=None): self.realm = realm_name.upper() self.serverid = realm_to_serverid(self.realm) self.suffix = ipautil.realm_to_suffix(self.realm) self.fqdn = fqdn self.dm_password = dm_password self.domain = domain_name self.principal = "ldap/%s@%s" % (self.fqdn, self.realm) self.subject_base = subject_base self.idstart = idstart self.idmax = idmax self.pkcs12_info = pkcs12_info if pkcs12_info: self.ca_is_configured = False self.ca_file = ca_file self.__setup_sub_dict() def create_instance(self, realm_name, fqdn, domain_name, dm_password, pkcs12_info=None, idstart=1100, idmax=999999, subject_base=None, hbac_allow=True, ca_file=None): self.init_info( realm_name, fqdn, domain_name, dm_password, subject_base, idstart, idmax, pkcs12_info, ca_file=ca_file) self.__common_setup() self.step("adding default layout", self.__add_default_layout) self.step("adding delegation layout", self.__add_delegation_layout) self.step("creating container for managed entries", self.__managed_entries) self.step("configuring user private groups", self.__user_private_groups) self.step("configuring netgroups from hostgroups", self.__host_nis_groups) self.step("creating default Sudo bind user", self.__add_sudo_binduser) self.step("creating default Auto Member layout", self.__add_automember_config) self.step("adding range check plugin", self.__add_range_check_plugin) if hbac_allow: self.step("creating default HBAC rule allow_all", self.add_hbac) self.__common_post_setup() self.start_creation(runtime=60) def create_replica(self, realm_name, master_fqdn, fqdn, domain_name, dm_password, subject_base, pkcs12_info=None, ca_file=None, ca_is_configured=None): # idstart and idmax are configured so that the range is seen as # depleted by the DNA plugin and the replica will go and get a # new range from the master. # This way all servers use the initially defined range by default. idstart = 1101 idmax = 1100 self.init_info( realm_name=realm_name, fqdn=fqdn, domain_name=domain_name, dm_password=dm_password, subject_base=subject_base, idstart=idstart, idmax=idmax, pkcs12_info=pkcs12_info, ca_file=ca_file ) self.master_fqdn = master_fqdn if ca_is_configured is not None: self.ca_is_configured = ca_is_configured self.__common_setup(True) self.step("setting up initial replication", self.__setup_replica) self.step("updating schema", self.__update_schema) # See LDIFs for automember configuration during replica install self.step("setting Auto Member configuration", self.__add_replica_automember_config) self.step("enabling S4U2Proxy delegation", self.__setup_s4u2proxy) self.__common_post_setup() self.start_creation(runtime=60) def __setup_replica(self): replication.enable_replication_version_checking(self.fqdn, self.realm, self.dm_password) repl = replication.ReplicationManager(self.realm, self.fqdn, self.dm_password) repl.setup_replication(self.master_fqdn, r_binddn=DN(('cn', 'Directory Manager')), r_bindpw=self.dm_password) self.run_init_memberof = repl.needs_memberof_fixup() def __update_schema(self): # FIXME: https://fedorahosted.org/389/ticket/47490 self._ldap_mod("schema-update.ldif") def __enable(self): self.backup_state("enabled", self.is_enabled()) # At the end of the installation ipa-server-install will enable the # 'ipa' service wich takes care of starting/stopping dirsrv self.disable() def __setup_sub_dict(self): server_root = find_server_root() try: idrange_size = self.idmax - self.idstart + 1 except TypeError: idrange_size = None self.sub_dict = dict(FQDN=self.fqdn, SERVERID=self.serverid, PASSWORD=self.dm_password, RANDOM_PASSWORD=self.generate_random(), SUFFIX=self.suffix, REALM=self.realm, USER=DS_USER, SERVER_ROOT=server_root, DOMAIN=self.domain, TIME=int(time.time()), IDSTART=self.idstart, IDMAX=self.idmax, HOST=self.fqdn, ESCAPED_SUFFIX=str(self.suffix), GROUP=DS_GROUP, IDRANGE_SIZE=idrange_size ) def __create_instance(self): pent = pwd.getpwnam(DS_USER) self.backup_state("serverid", self.serverid) self.fstore.backup_file("/etc/sysconfig/dirsrv") self.sub_dict['BASEDC'] = self.realm.split('.')[0].lower() base_txt = ipautil.template_str(BASE_TEMPLATE, self.sub_dict) root_logger.debug(base_txt) target_fname = '/var/lib/dirsrv/boot.ldif' base_fd = open(target_fname, "w") base_fd.write(base_txt) base_fd.close() # Must be readable for dirsrv os.chmod(target_fname, 0440) os.chown(target_fname, pent.pw_uid, pent.pw_gid) inf_txt = ipautil.template_str(INF_TEMPLATE, self.sub_dict) root_logger.debug("writing inf template") inf_fd = ipautil.write_tmp_file(inf_txt) inf_txt = re.sub(r"RootDNPwd=.*\n", "", inf_txt) root_logger.debug(inf_txt) if ipautil.file_exists("/usr/sbin/setup-ds.pl"): args = ["/usr/sbin/setup-ds.pl", "--silent", "--logfile", "-", "-f", inf_fd.name] root_logger.debug("calling setup-ds.pl") else: args = ["/usr/bin/ds_newinst.pl", inf_fd.name] root_logger.debug("calling ds_newinst.pl") try: ipautil.run(args) root_logger.debug("completed creating ds instance") except ipautil.CalledProcessError, e: root_logger.critical("failed to create ds instance %s" % e) # check for open port 389 from now on self.open_ports.append(389) root_logger.debug("restarting ds instance") try: self.__restart_instance() root_logger.debug("done restarting ds instance") except ipautil.CalledProcessError, e: print "failed to restart ds instance", e root_logger.debug("failed to restart ds instance %s" % e) inf_fd.close() os.remove("/var/lib/dirsrv/boot.ldif") def __add_default_schemas(self): pent = pwd.getpwnam(DS_USER) for schema_fname in ("60kerberos.ldif", "60samba.ldif", "60ipaconfig.ldif", "60basev2.ldif", "60basev3.ldif", "60ipadns.ldif", "61kerberos-ipav3.ldif", "65ipasudo.ldif", "70ipaotp.ldif"): target_fname = schema_dirname(self.serverid) + schema_fname shutil.copyfile(ipautil.SHARE_DIR + schema_fname, target_fname) os.chmod(target_fname, 0440) # read access for dirsrv user/group os.chown(target_fname, pent.pw_uid, pent.pw_gid) try: shutil.move(schema_dirname(self.serverid) + "05rfc2247.ldif", schema_dirname(self.serverid) + "05rfc2247.ldif.old") target_fname = schema_dirname(self.serverid) + "05rfc2247.ldif" shutil.copyfile(ipautil.SHARE_DIR + "05rfc2247.ldif", target_fname) os.chmod(target_fname, 0440) os.chown(target_fname, pent.pw_uid, pent.pw_gid) except IOError: # Does not apply with newer DS releases pass def restart(self, instance=''): try: super(DsInstance, self).restart(instance) if not is_ds_running(instance): root_logger.critical("Failed to restart the directory server. See the installation log for details.") sys.exit(1) except SystemExit, e: raise e except Exception, e: # TODO: roll back here? root_logger.critical("Failed to restart the directory server (%s). See the installation log for details." % e) def __restart_instance(self): self.restart(self.serverid) def __enable_entryusn(self): self._ldap_mod("entryusn.ldif") def __add_memberof_module(self): self._ldap_mod("memberof-conf.ldif") def init_memberof(self): if not self.run_init_memberof: return self._ldap_mod("memberof-task.ldif", self.sub_dict) # Note, keep dn in sync with dn in install/share/memberof-task.ldif dn = DN(('cn', 'IPA install %s' % self.sub_dict["TIME"]), ('cn', 'memberof task'), ('cn', 'tasks'), ('cn', 'config')) root_logger.debug("Waiting for memberof task to complete.") conn = ipaldap.IPAdmin(self.fqdn) if self.dm_password: conn.do_simple_bind( DN(('cn', 'directory manager')), self.dm_password) else: conn.do_sasl_gssapi_bind() replication.wait_for_task(conn, dn) conn.unbind() def apply_updates(self): ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, sub_dict=self.sub_dict, plugins=True) files = ld.get_all_files(ldapupdate.UPDATES_DIR) ld.update(files, ordered=True) def __add_referint_module(self): self._ldap_mod("referint-conf.ldif") def __set_unique_attrs(self): self._ldap_mod("unique-attributes.ldif", self.sub_dict) def __config_uidgid_gen(self): self._ldap_mod("dna.ldif", self.sub_dict) def __add_master_entry(self): self._ldap_mod("master-entry.ldif", self.sub_dict) def __add_winsync_module(self): self._ldap_mod("ipa-winsync-conf.ldif") def __enable_compat_plugin(self): ld = ldapupdate.LDAPUpdate(dm_password=self.dm_password, sub_dict=self.sub_dict) rv = ld.update(['/usr/share/ipa/schema_compat.uldif']) if not rv: raise RuntimeError("Enabling compatibility plugin failed") def __config_version_module(self): self._ldap_mod("version-conf.ldif") def __config_uuid_module(self): self._ldap_mod("uuid-conf.ldif") self._ldap_mod("uuid-ipauniqueid.ldif", self.sub_dict) def __config_modrdn_module(self): self._ldap_mod("modrdn-conf.ldif") self._ldap_mod("modrdn-krbprinc.ldif", self.sub_dict) def __config_dns_module(self): # Configure DNS plugin unconditionally as we would otherwise have # troubles if other replica just configured DNS with ipa-dns-install self._ldap_mod("ipa-dns-conf.ldif") def __config_lockout_module(self): self._ldap_mod("lockout-conf.ldif") def __repoint_managed_entries(self): self._ldap_mod("repoint-managed-entries.ldif", self.sub_dict) def configure_dirsrv_ccache(self): pent = pwd.getpwnam("dirsrv") ccache = '/tmp/krb5cc_%d' % pent.pw_uid filepath = '/etc/sysconfig/dirsrv' 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) replacevars = {'KRB5CCNAME': ccache} old_values = ipautil.backup_config_and_replace_variables( self.fstore, filepath, replacevars=replacevars) ipaservices.restore_context(filepath) def __managed_entries(self): self._ldap_mod("managed-entries.ldif", self.sub_dict) def __user_private_groups(self): self._ldap_mod("user_private_groups.ldif", self.sub_dict) def __host_nis_groups(self): self._ldap_mod("host_nis_groups.ldif", self.sub_dict) def __add_enrollment_module(self): self._ldap_mod("enrollment-conf.ldif", self.sub_dict) def generate_random(self): return ipautil.ipa_generate_password() def enable_ssl(self): dirname = config_dirname(self.serverid) dsdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) if self.pkcs12_info: dsdb.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], ca_file=self.ca_file) server_certs = dsdb.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % self.pkcs12_info[0]) # We only handle one server cert nickname = server_certs[0][0] self.dercert = dsdb.get_cert_from_db(nickname, pem=False) else: nickname = self.nickname cadb = certs.CertDB(self.realm, host_name=self.fqdn, subject_base=self.subject_base) # FIXME, need to set this nickname in the RA plugin cadb.export_ca_cert('ipaCert', False) dsdb.create_from_cacert(cadb.cacert_fname, passwd=None) self.dercert = dsdb.create_server_cert( nickname, self.fqdn, cadb) dsdb.create_pin_file() if self.ca_is_configured: dsdb.track_server_cert( nickname, self.principal, dsdb.passwd_fname, 'restart_dirsrv %s' % self.serverid) conn = ipaldap.IPAdmin(self.fqdn) conn.do_simple_bind(DN(('cn', 'directory manager')), self.dm_password) mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"), (ldap.MOD_REPLACE, "nsSSL3Ciphers", "-rsa_null_md5,+rsa_rc4_128_md5,+rsa_rc4_40_md5,+rsa_rc2_40_md5,\ +rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,\ +fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,\ +tls_rsa_export1024_with_des_cbc_sha")] conn.modify_s(DN(('cn', 'encryption'), ('cn', 'config')), mod) mod = [(ldap.MOD_ADD, "nsslapd-security", "on")] conn.modify_s(DN(('cn', 'config')), mod) entry = conn.make_entry( DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')), objectclass=["top", "nsEncryptionModule"], cn=["RSA"], nsSSLPersonalitySSL=[nickname], nsSSLToken=["internal (software)"], nsSSLActivation=["on"], ) conn.add_entry(entry) conn.unbind() # check for open secure port 636 from now on self.open_ports.append(636) def export_ca_cert(self, nickname, location): dirname = config_dirname(self.serverid) dsdb = certs.NSSDatabase(nssdir=dirname) dsdb.export_pem_cert(nickname, location) def upload_ca_cert(self, cacert_name=None): """ Upload the CA certificate from the NSS database to the LDAP directory. """ dirname = config_dirname(self.serverid) certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) if cacert_name is None: cacert_name = certdb.cacert_name dercert = certdb.get_cert_from_db(cacert_name, pem=False) self.upload_ca_dercert(dercert) def upload_ca_dercert(self, dercert): """Upload the CA DER certificate to the LDAP directory """ # Note: Don't try to optimize if base64 data is already available. # We want to re-encode using Python's b64encode to ensure the # data is normalized (no extra newlines in the ldif) self.sub_dict['CADERCERT'] = base64.b64encode(dercert) self._ldap_mod('upload-cacert.ldif', self.sub_dict) def __add_default_layout(self): self._ldap_mod("bootstrap-template.ldif", self.sub_dict) def __add_delegation_layout(self): self._ldap_mod("delegation.ldif", self.sub_dict) def __add_replication_acis(self): self._ldap_mod("replica-acis.ldif", self.sub_dict) def __setup_s4u2proxy(self): self._ldap_mod("replica-s4u2proxy.ldif", self.sub_dict) def __create_indices(self): self._ldap_mod("indices.ldif") def __certmap_conf(self): shutil.copyfile(ipautil.SHARE_DIR + "certmap.conf.template", config_dirname(self.serverid) + "certmap.conf") installutils.update_file(config_dirname(self.serverid) + "certmap.conf", '$SUBJECT_BASE', str(self.subject_base)) sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', str(self.subject_base) ) def __enable_ldapi(self): self._ldap_mod("ldapi.ldif", self.sub_dict) def __enable_sasl_mapping_fallback(self): self._ldap_mod("sasl-mapping-fallback.ldif", self.sub_dict) def add_hbac(self): self._ldap_mod("default-hbac.ldif", self.sub_dict) def change_admin_password(self, password): root_logger.debug("Changing admin password") dirname = config_dirname(self.serverid) dmpwdfile = "" admpwdfile = "" try: (dmpwdfd, dmpwdfile) = tempfile.mkstemp(dir='/var/lib/ipa') os.write(dmpwdfd, self.dm_password) os.close(dmpwdfd) (admpwdfd, admpwdfile) = tempfile.mkstemp(dir='/var/lib/ipa') os.write(admpwdfd, password) os.close(admpwdfd) args = ["/usr/bin/ldappasswd", "-h", self.fqdn, "-ZZ", "-x", "-D", str(DN(('cn', 'Directory Manager'))), "-y", dmpwdfile, "-T", admpwdfile, str(DN(('uid', 'admin'), ('cn', 'users'), ('cn', 'accounts'), self.suffix))] try: env = { 'LDAPTLS_CACERTDIR':os.path.dirname(CACERT), 'LDAPTLS_CACERT':CACERT } ipautil.run(args, env=env) root_logger.debug("ldappasswd done") except ipautil.CalledProcessError, e: print "Unable to set admin password", e root_logger.debug("Unable to set admin password %s" % e) finally: if os.path.isfile(dmpwdfile): os.remove(dmpwdfile) if os.path.isfile(admpwdfile): os.remove(admpwdfile) def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring directory server") enabled = self.restore_state("enabled") # Just eat this state if it exists running = self.restore_state("running") try: self.fstore.restore_file("/etc/security/limits.conf") self.fstore.restore_file("/etc/sysconfig/dirsrv") except ValueError, error: root_logger.debug(error) pass if not enabled is None and not enabled: self.disable() serverid = self.restore_state("serverid") if not serverid is None: self.stop_tracking_certificates(serverid) erase_ds_instance_data(serverid) # At one time we removed this user on uninstall. That can potentially # orphan files, or worse, if another useradd runs in the intermim, # cause files to have a new owner. user_exists = self.restore_state("user_exists") # Make sure some upgrade-related state is removed. This could cause # re-installation problems. self.restore_state('nsslapd-port') self.restore_state('nsslapd-security') self.restore_state('nsslapd-ldapiautobind') # If any dirsrv instances remain after we've removed ours then # (re)start them. for ds_instance in get_ds_instances(): try: ipaservices.knownservices.dirsrv.restart(ds_instance, wait=False) except Exception, e: root_logger.error('Unable to restart ds instance %s: %s', ds_instance, e) def stop_tracking_certificates(self, serverid=None): if serverid is None: serverid = self.get_state("serverid") if not serverid is None: # drop the trailing / off the config_dirname so the directory # will match what is in certmonger dirname = config_dirname(serverid)[:-1] dsdb = certs.CertDB(self.realm, nssdir=dirname) dsdb.untrack_server_cert(self.nickname) # we could probably move this function into the service.Service # class - it's very generic - all we need is a way to get an # instance of a particular Service def add_ca_cert(self, cacert_fname, cacert_name=''): """Add a CA certificate to the directory server cert db. We first have to shut down the directory server in case it has opened the cert db read-only. Then we use the CertDB class to add the CA cert. We have to provide a nickname, and we do not use 'IPA CA' since that's the default, so we use 'Imported CA' if none specified. Then we restart the server.""" # first make sure we have a valid cacert_fname try: if not os.access(cacert_fname, os.R_OK): root_logger.critical("The given CA cert file named [%s] could not be read" % cacert_fname) return False except OSError, e: root_logger.critical("The given CA cert file named [%s] could not be read: %s" % (cacert_fname, str(e))) return False # ok - ca cert file can be read # shutdown the server self.stop() dirname = config_dirname(realm_to_serverid(self.realm)) certdb = certs.CertDB(self.realm, nssdir=dirname, subject_base=self.subject_base) if not cacert_name or len(cacert_name) == 0: cacert_name = "Imported CA" # we can't pass in the nickname, so we set the instance variable certdb.cacert_name = cacert_name status = True try: certdb.load_cacert(cacert_fname) except ipautil.CalledProcessError, e: root_logger.critical("Error importing CA cert file named [%s]: %s" % (cacert_fname, str(e))) status = False # restart the directory server self.start() return status def tune_nofile(self, num=8192): """ Increase the number of files descriptors available to directory server from the default 1024 to 8192. This will allow to support a greater number of clients out of the box. """ # Do the platform-specific changes proceed = ipaservices.knownservices.dirsrv.tune_nofile_platform( num=num, fstore=self.fstore) if proceed: # finally change also DS configuration # NOTE: dirsrv will not allow you to set max file descriptors unless # the user limits allow it, so we have to restart dirsrv before # attempting to change them in cn=config self.__restart_instance() nf_sub_dict = dict(NOFILES=str(num)) self._ldap_mod("ds-nfiles.ldif", nf_sub_dict) def __tuning(self): self.tune_nofile(8192) def __root_autobind(self): self._ldap_mod("root-autobind.ldif") def __add_sudo_binduser(self): self._ldap_mod("sudobind.ldif", self.sub_dict) def __add_automember_config(self): self._ldap_mod("automember.ldif", self.sub_dict) def __add_replica_automember_config(self): self._ldap_mod("replica-automember.ldif", self.sub_dict) def __add_range_check_plugin(self): self._ldap_mod("range-check-conf.ldif", self.sub_dict) def replica_populate(self): self.ldap_connect() dn = DN(('cn', 'default'), ('ou', 'profile'), self.suffix) try: entry = self.admin_conn.get_entry(dn) srvlist = entry.single_value('defaultServerList', '') srvlist = srvlist.split() if not self.fqdn in srvlist: srvlist.append(self.fqdn) attr = ' '.join(srvlist) mod = [(ldap.MOD_REPLACE, 'defaultServerList', attr)] self.admin_conn.modify_s(dn, mod) except errors.NotFound: pass except ldap.TYPE_OR_VALUE_EXISTS: pass self.ldap_disconnect() freeipa-3.3.4/ipaserver/install/certs.py0000664000175000017500000007432612271663206017663 0ustar mkosekmkosek# Authors: Karl MacMillan # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import os import stat import re import sys import tempfile import shutil import xml.dom.minidom import pwd import base64 from hashlib import sha1 from nss import nss from nss.error import NSPRError from ipapython.ipa_log_manager import root_logger from ipapython import dogtag from ipapython import sysrestore from ipapython import ipautil from ipapython import certmonger from ipapython.certdb import get_ca_nickname from ipapython import services as ipaservices from ipapython.dn import DN from ipalib import pkcs10, x509, api from ipalib.errors import CertificateOperationError from ipalib.text import _ # Apache needs access to this database so we need to create it # where apache can reach NSS_DIR = "/etc/httpd/alias" def find_cert_from_txt(cert, start=0): """ Given a cert blob (str) which may or may not contian leading and trailing text, pull out just the certificate part. This will return the FIRST cert in a stream of data. Returns a tuple (certificate, last position in cert) """ s = cert.find('-----BEGIN CERTIFICATE-----', start) e = cert.find('-----END CERTIFICATE-----', s) if e > 0: e = e + 25 if s < 0 or e < 0: raise RuntimeError("Unable to find certificate") cert = cert[s:e] return (cert, e) def get_cert_nickname(cert): """ Using the subject from cert come up with a nickname suitable for NSS. The caller can decide whether to use just the RDN or the whole subject. Returns a tuple of (rdn, subject_dn) when rdn is the string representation of the first RDN in the subject and subject_dn is a DN object. """ nsscert = x509.load_certificate(cert) subject = str(nsscert.subject) dn = DN(subject) return (str(dn[0]), dn) class NSSDatabase(object): """A general-purpose wrapper around a NSS cert database For permanent NSS databases, pass the cert DB directory to __init__ For temporary databases, do not pass nssdir, and call close() when done to remove the DB. Alternatively, a NSSDatabase can be used as a context manager that calls close() automatically. """ # Traditionally, we used CertDB for our NSS DB operations, but that class # got too tied to IPA server details, killing reusability. # BaseCertDB is a class that knows nothing about IPA. # Generic NSS DB code should be moved here. def __init__(self, nssdir=None): if nssdir is None: self.secdir = tempfile.mkdtemp() self._is_temporary = True else: self.secdir = nssdir self._is_temporary = False def close(self): if self._is_temporary: shutil.rmtree(self.secdir) def __enter__(self): return self def __exit__(self, type, value, tb): self.close() def run_certutil(self, args, stdin=None): new_args = ["/usr/bin/certutil", "-d", self.secdir] new_args = new_args + args return ipautil.run(new_args, stdin) def create_db(self, password_filename): """Create cert DB :param password_filename: Name of file containing the database password """ self.run_certutil(["-N", "-f", password_filename]) def list_certs(self): """Return nicknames and cert flags for all certs in the database :return: List of (name, trust_flags) tuples """ certs, stderr, returncode = self.run_certutil(["-L"]) certs = certs.splitlines() # FIXME, this relies on NSS never changing the formatting of certutil certlist = [] for cert in certs: nickname = cert[0:61] trust = cert[61:] if re.match(r'\w*,\w*,\w*', trust): certlist.append((nickname.strip(), trust.strip())) return tuple(certlist) def find_server_certs(self): """Return nicknames and cert flags for server certs in the database Server certs have an "u" character in the trust flags. :return: List of (name, trust_flags) tuples """ server_certs = [] for name, flags in self.list_certs(): if 'u' in flags: server_certs.append((name, flags)) return server_certs def get_trust_chain(self, nickname): """Return names of certs in a given cert's trust chain :param nickname: Name of the cert :return: List of certificate names """ root_nicknames = [] chain, stderr, returncode = self.run_certutil([ "-O", "-n", nickname]) chain = chain.splitlines() for c in chain: m = re.match('\s*"(.*)" \[.*', c) if m: root_nicknames.append(m.groups()[0]) return root_nicknames def import_pkcs12(self, pkcs12_filename, db_password_filename, pkcs12_passwd=None): args = ["/usr/bin/pk12util", "-d", self.secdir, "-i", pkcs12_filename, "-k", db_password_filename, '-v'] if pkcs12_passwd is not None: pkcs12_passwd = pkcs12_passwd + '\n' args = args + ["-w", "/dev/stdin"] try: ipautil.run(args, stdin=pkcs12_passwd) except ipautil.CalledProcessError, e: if e.returncode == 17: raise RuntimeError("incorrect password for pkcs#12 file %s" % pkcs12_filename) elif e.returncode == 10: raise RuntimeError("Failed to open %s" % pkcs12_filename) else: raise RuntimeError("unknown error import pkcs#12 file %s" % pkcs12_filename) def trust_root_cert(self, root_nickname): if root_nickname[:7] == "Builtin": root_logger.debug( "No need to add trust for built-in root CAs, skipping %s" % root_nickname) else: try: self.run_certutil(["-M", "-n", root_nickname, "-t", "CT,CT,"]) except ipautil.CalledProcessError, e: raise RuntimeError( "Setting trust on %s failed" % root_nickname) def export_pem_cert(self, nickname, location): """Export the given cert to PEM file in the given location""" cert, err, returncode = self.run_certutil(["-L", "-n", nickname, "-a"]) with open(location, "w+") as fd: fd.write(cert) os.chmod(location, 0444) def import_pem_cert(self, nickname, flags, location): """Import a cert form the given PEM file. The file must contain exactly one certificate. """ try: with open(location) as fd: certs = fd.read() except IOError as e: raise RuntimeError( "Failed to open %s: %s" % (location, e.strerror) ) cert, st = find_cert_from_txt(certs) self.add_single_pem_cert(nickname, flags, cert) try: find_cert_from_txt(certs, st) except RuntimeError: pass else: raise ValueError('%s contains more than one certificate' % location) def add_single_pem_cert(self, nick, flags, cert): """Import a cert in PEM format""" self.run_certutil(["-A", "-n", nick, "-t", flags, "-a"], stdin=cert) def delete_cert(self, nick): self.run_certutil(["-D", "-n", nick]) def verify_server_cert_validity(self, nickname, hostname): """Verify a certificate is valid for a SSL server with given hostname Raises a ValueError if the certificate is invalid. """ certdb = cert = None nss.nss_init(self.secdir) try: certdb = nss.get_default_certdb() cert = nss.find_cert_from_nickname(nickname) intended_usage = nss.certificateUsageSSLServer try: approved_usage = cert.verify_now(certdb, True, intended_usage) except NSPRError, e: if e.errno != -8102: raise ValueError(e.strerror) approved_usage = 0 if not approved_usage & intended_usage: raise ValueError('invalid for a SSL server') if not cert.verify_hostname(hostname): raise ValueError('invalid for server %s' % hostname) finally: del certdb, cert nss.nss_shutdown() return None class CertDB(object): """An IPA-server-specific wrapper around NSS This class knows IPA-specific details such as nssdir location, or the CA cert name. """ # TODO: Remove all selfsign code def __init__(self, realm, nssdir=NSS_DIR, fstore=None, host_name=None, subject_base=None): self.nssdb = NSSDatabase(nssdir) self.secdir = nssdir self.realm = realm self.noise_fname = self.secdir + "/noise.txt" self.passwd_fname = self.secdir + "/pwdfile.txt" self.certdb_fname = self.secdir + "/cert8.db" self.keydb_fname = self.secdir + "/key3.db" self.secmod_fname = self.secdir + "/secmod.db" self.cacert_fname = self.secdir + "/cacert.asc" self.pk12_fname = self.secdir + "/cacert.p12" self.pin_fname = self.secdir + "/pin.txt" self.pwd_conf = "/etc/httpd/conf/password.conf" self.reqdir = None self.certreq_fname = None self.certder_fname = None self.host_name = host_name self.subject_base = subject_base try: self.cwd = os.getcwd() except OSError, e: raise RuntimeError("Unable to determine the current directory: %s" % str(e)) if not subject_base: self.subject_base = DN(('O', 'IPA')) self.cacert_name = get_ca_nickname(self.realm) self.valid_months = "120" self.keysize = "1024" # We are going to set the owner of all of the cert # files to the owner of the containing directory # instead of that of the process. This works when # this is called by root for a daemon that runs as # a normal user mode = os.stat(self.secdir) self.uid = mode[stat.ST_UID] self.gid = mode[stat.ST_GID] if fstore: self.fstore = fstore else: self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') subject_base = ipautil.dn_attribute_property('_subject_base') def __del__(self): if self.reqdir is not None: shutil.rmtree(self.reqdir, ignore_errors=True) try: os.chdir(self.cwd) except: pass def setup_cert_request(self): """ Create a temporary directory to store certificate requests and certificates. This should be called before requesting certificates. This is set outside of __init__ to avoid creating a temporary directory every time we open a cert DB. """ if self.reqdir is not None: return self.reqdir = tempfile.mkdtemp('', 'ipa-', '/var/lib/ipa') self.certreq_fname = self.reqdir + "/tmpcertreq" self.certder_fname = self.reqdir + "/tmpcert.der" # When certutil makes a request it creates a file in the cwd, make # sure we are in a unique place when this happens os.chdir(self.reqdir) def set_perms(self, fname, write=False, uid=None): if uid: pent = pwd.getpwnam(uid) os.chown(fname, pent.pw_uid, pent.pw_gid) else: os.chown(fname, self.uid, self.gid) perms = stat.S_IRUSR if write: perms |= stat.S_IWUSR os.chmod(fname, perms) def gen_password(self): return sha1(ipautil.ipa_generate_password()).hexdigest() def run_certutil(self, args, stdin=None): return self.nssdb.run_certutil(args, stdin) def run_signtool(self, args, stdin=None): with open(self.passwd_fname, "r") as f: password = f.readline() new_args = ["/usr/bin/signtool", "-d", self.secdir, "-p", password] new_args = new_args + args ipautil.run(new_args, stdin) def create_noise_file(self): if ipautil.file_exists(self.noise_fname): os.remove(self.noise_fname) f = open(self.noise_fname, "w") f.write(self.gen_password()) self.set_perms(self.noise_fname) def create_passwd_file(self, passwd=None): ipautil.backup_file(self.passwd_fname) f = open(self.passwd_fname, "w") if passwd is not None: f.write("%s\n" % passwd) else: f.write(self.gen_password()) f.close() self.set_perms(self.passwd_fname) def create_certdbs(self): ipautil.backup_file(self.certdb_fname) ipautil.backup_file(self.keydb_fname) ipautil.backup_file(self.secmod_fname) self.nssdb.create_db(self.passwd_fname) self.set_perms(self.passwd_fname, write=True) def list_certs(self): """ Return a tuple of tuples containing (nickname, trust) """ return self.nssdb.list_certs() def has_nickname(self, nickname): """ Returns True if nickname exists in the certdb, False otherwise. This could also be done directly with: certutil -L -d -n ... """ certs = self.list_certs() for cert in certs: if nickname == cert[0]: return True return False def export_ca_cert(self, nickname, create_pkcs12=False): """create_pkcs12 tells us whether we should create a PKCS#12 file of the CA or not. If we are running on a replica then we won't have the private key to make a PKCS#12 file so we don't need to do that step.""" # export the CA cert for use with other apps ipautil.backup_file(self.cacert_fname) root_nicknames = self.find_root_cert(nickname) fd = open(self.cacert_fname, "w") for root in root_nicknames: (cert, stderr, returncode) = self.run_certutil(["-L", "-n", root, "-a"]) fd.write(cert) fd.close() os.chmod(self.cacert_fname, stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) if create_pkcs12: ipautil.backup_file(self.pk12_fname) ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, "-o", self.pk12_fname, "-n", self.cacert_name, "-w", self.passwd_fname, "-k", self.passwd_fname]) self.set_perms(self.pk12_fname) def load_cacert(self, cacert_fname): """ Load all the certificates from a given file. It is assumed that this file creates CA certificates. """ fd = open(cacert_fname) certs = fd.read() fd.close() ca_dn = DN(('CN','Certificate Authority'), self.subject_base) st = 0 while True: try: (cert, st) = find_cert_from_txt(certs, st) (rdn, subject_dn) = get_cert_nickname(cert) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.nssdb.add_single_pem_cert(nick, "CT,,C", cert) except RuntimeError: break def get_cert_from_db(self, nickname, pem=True): """ Retrieve a certificate from the current NSS database for nickname. pem controls whether the value returned PEM or DER-encoded. The default is the data straight from certutil -a. """ try: args = ["-L", "-n", nickname, "-a"] (cert, err, returncode) = self.run_certutil(args) if pem: return cert else: (cert, start) = find_cert_from_txt(cert, start=0) cert = x509.strip_header(cert) dercert = base64.b64decode(cert) return dercert except ipautil.CalledProcessError: return '' def track_server_cert(self, nickname, principal, password_file=None, command=None): """ Tell certmonger to track the given certificate nickname. If command is not a full path then it is prefixed with /usr/lib[64]/ipa/certmonger. """ if command is not None and not os.path.isabs(command): if sys.maxsize > 2**32L: libpath = 'lib64' else: libpath = 'lib' command = '/usr/%s/ipa/certmonger/%s' % (libpath, command) cmonger = ipaservices.knownservices.certmonger cmonger.enable() ipaservices.knownservices.messagebus.start() cmonger.start() try: (stdout, stderr, rc) = certmonger.start_tracking(nickname, self.secdir, password_file, command) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error("certmonger failed starting to track certificate: %s" % str(e)) return cmonger.stop() cert = self.get_cert_from_db(nickname) nsscert = x509.load_certificate(cert, dbdir=self.secdir) subject = str(nsscert.subject) m = re.match('New tracking request "(\d+)" added', stdout) if not m: root_logger.error('Didn\'t get new %s request, got %s' % (cmonger.service_name, stdout)) raise RuntimeError('%s did not issue new tracking request for \'%s\' in \'%s\'. Use \'ipa-getcert list\' to list existing certificates.' % (cmonger.service_name, nickname, self.secdir)) request_id = m.group(1) certmonger.add_principal(request_id, principal) certmonger.add_subject(request_id, subject) cmonger.start() def untrack_server_cert(self, nickname): """ Tell certmonger to stop tracking the given certificate nickname. """ # Always start certmonger. We can't untrack something if it isn't # running cmonger = ipaservices.knownservices.certmonger ipaservices.knownservices.messagebus.start() cmonger.start() try: certmonger.stop_tracking(self.secdir, nickname=nickname) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error("certmonger failed to stop tracking certificate: %s" % str(e)) cmonger.stop() def create_server_cert(self, nickname, hostname, other_certdb=None, subject=None): """ If we are using a dogtag CA then other_certdb contains the RA agent key that will issue our cert. You can override the certificate Subject by specifying a subject. Returns a certificate in DER format. """ cdb = other_certdb if not cdb: cdb = self if subject is None: subject=DN(('CN', hostname), self.subject_base) self.request_cert(subject) cdb.issue_server_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) fd = open(self.certder_fname, "r") dercert = fd.read() fd.close() os.unlink(self.certreq_fname) os.unlink(self.certder_fname) return dercert def create_signing_cert(self, nickname, hostname, other_certdb=None, subject=None): cdb = other_certdb if not cdb: cdb = self if subject is None: subject=DN(('CN', hostname), self.subject_base) self.request_cert(subject) cdb.issue_signing_cert(self.certreq_fname, self.certder_fname) self.add_cert(self.certder_fname, nickname) os.unlink(self.certreq_fname) os.unlink(self.certder_fname) def request_cert(self, subject, certtype="rsa", keysize="2048"): assert isinstance(subject, DN) self.create_noise_file() self.setup_cert_request() args = ["-R", "-s", str(subject), "-o", self.certreq_fname, "-k", certtype, "-g", keysize, "-z", self.noise_fname, "-f", self.passwd_fname, "-a"] (stdout, stderr, returncode) = self.run_certutil(args) os.remove(self.noise_fname) return (stdout, stderr) def issue_server_cert(self, certreq_fname, cert_fname): self.setup_cert_request() if self.host_name is None: raise RuntimeError("CA Host is not set.") f = open(certreq_fname, "r") csr = f.readlines() f.close() csr = "".join(csr) # We just want the CSR bits, make sure there is nothing else csr = pkcs10.strip_header(csr) params = {'profileId': 'caIPAserviceCert', 'cert_request_type': 'pkcs10', 'requestor_name': 'IPA Installer', 'cert_request': csr, 'xmlOutput': 'true'} # Send the request to the CA f = open(self.passwd_fname, "r") password = f.readline() f.close() result = dogtag.https_request( self.host_name, api.env.ca_ee_install_port or dogtag.configured_constants().EE_SECURE_PORT, "/ca/ee/ca/profileSubmitSSLClient", self.secdir, password, "ipaCert", **params) http_status, http_reason_phrase, http_headers, http_body = result if http_status != 200: raise CertificateOperationError( error=_('Unable to communicate with CMS (%s)') % http_reason_phrase) # The result is an XML blob. Pull the certificate out of that doc = xml.dom.minidom.parseString(http_body) item_node = doc.getElementsByTagName("b64") try: try: cert = item_node[0].childNodes[0].data except IndexError: raise RuntimeError("Certificate issuance failed") finally: doc.unlink() # base64-decode the result for uniformity cert = base64.b64decode(cert) # Write the certificate to a file. It will be imported in a later # step. This file will be read later to be imported. f = open(cert_fname, "w") f.write(cert) f.close() def issue_signing_cert(self, certreq_fname, cert_fname): self.setup_cert_request() if self.host_name is None: raise RuntimeError("CA Host is not set.") f = open(certreq_fname, "r") csr = f.readlines() f.close() csr = "".join(csr) # We just want the CSR bits, make sure there is no thing else csr = pkcs10.strip_header(csr) params = {'profileId': 'caJarSigningCert', 'cert_request_type': 'pkcs10', 'requestor_name': 'IPA Installer', 'cert_request': csr, 'xmlOutput': 'true'} # Send the request to the CA f = open(self.passwd_fname, "r") password = f.readline() f.close() result = dogtag.https_request( self.host_name, api.env.ca_ee_install_port or dogtag.configured_constants().EE_SECURE_PORT, "/ca/ee/ca/profileSubmitSSLClient", self.secdir, password, "ipaCert", **params) http_status, http_reason_phrase, http_headers, http_body = result if http_status != 200: raise RuntimeError("Unable to submit cert request") # The result is an XML blob. Pull the certificate out of that doc = xml.dom.minidom.parseString(http_body) item_node = doc.getElementsByTagName("b64") cert = item_node[0].childNodes[0].data doc.unlink() # base64-decode the cert for uniformity cert = base64.b64decode(cert) # Write the certificate to a file. It will be imported in a later # step. This file will be read later to be imported. f = open(cert_fname, "w") f.write(cert) f.close() def add_cert(self, cert_fname, nickname): """ Load a certificate from a PEM file and add minimal trust. """ args = ["-A", "-n", nickname, "-t", "u,u,u", "-i", cert_fname, "-f", self.passwd_fname] self.run_certutil(args) def delete_cert(self, nickname): self.nssdb.delete_cert(nickname) def create_pin_file(self): """ This is the format of Directory Server pin files. """ ipautil.backup_file(self.pin_fname) f = open(self.pin_fname, "w") f.write("Internal (Software) Token:") pwdfile = open(self.passwd_fname) f.write(pwdfile.read()) f.close() pwdfile.close() self.set_perms(self.pin_fname) def create_password_conf(self): """ This is the format of mod_nss pin files. """ ipautil.backup_file(self.pwd_conf) f = open(self.pwd_conf, "w") f.write("internal:") pwdfile = open(self.passwd_fname) f.write(pwdfile.read()) f.close() pwdfile.close() # TODO: replace explicit uid by a platform-specific one self.set_perms(self.pwd_conf, uid="apache") def find_root_cert(self, nickname): """ Given a nickname, return a list of the certificates that make up the trust chain. """ root_nicknames = self.nssdb.get_trust_chain(nickname) return root_nicknames def trust_root_cert(self, root_nickname): if root_nickname is None: root_logger.debug("Unable to identify root certificate to trust. Continuing but things are likely to fail.") return try: self.nssdb.trust_root_cert(root_nickname) except RuntimeError: pass def find_server_certs(self): return self.nssdb.find_server_certs() def import_pkcs12(self, pkcs12_fname, pkcs12_passwd=None): return self.nssdb.import_pkcs12(pkcs12_fname, self.passwd_fname, pkcs12_passwd=pkcs12_passwd) def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): if nickname is None: nickname = get_ca_nickname(api.env.realm) ipautil.run(["/usr/bin/pk12util", "-d", self.secdir, "-o", pkcs12_fname, "-n", nickname, "-k", self.passwd_fname, "-w", pkcs12_pwd_fname]) def export_pem_p12(self, pkcs12_fname, pkcs12_pwd_fname, nickname, pem_fname): ipautil.run(["/usr/bin/openssl", "pkcs12", "-export", "-name", nickname, "-in", pem_fname, "-out", pkcs12_fname, "-passout", "file:" + pkcs12_pwd_fname]) def create_from_cacert(self, cacert_fname, passwd=None): if ipautil.file_exists(self.certdb_fname): # We already have a cert db, see if it is for the same CA. # If it is we leave things as they are. f = open(cacert_fname, "r") newca = f.readlines() f.close() newca = "".join(newca) (newca, st) = find_cert_from_txt(newca) cacert = self.get_cert_from_db(self.cacert_name) if cacert != '': (cacert, st) = find_cert_from_txt(cacert) if newca == cacert: return # The CA certificates are different or something went wrong. Start with # a new certificate database. self.create_passwd_file(passwd) self.create_certdbs() self.load_cacert(cacert_fname) def create_from_pkcs12(self, pkcs12_fname, pkcs12_passwd, passwd=None, ca_file=None): """Create a new NSS database using the certificates in a PKCS#12 file. pkcs12_fname: the filename of the PKCS#12 file pkcs12_pwd_fname: the file containing the pin for the PKCS#12 file nickname: the nickname/friendly-name of the cert we are loading passwd: The password to use for the new NSS database we are creating The global CA may be added as well in case it wasn't included in the PKCS#12 file. Extra certs won't hurt in any case. The global CA may be specified in ca_file, as a PEM filename. """ self.create_noise_file() self.create_passwd_file(passwd) self.create_certdbs() self.import_pkcs12(pkcs12_fname, pkcs12_passwd) server_certs = self.find_server_certs() if len(server_certs) == 0: raise RuntimeError("Could not find a suitable server cert in import in %s" % pkcs12_fname) if ca_file: self.nssdb.import_pem_cert('CA', 'CT,CT,', ca_file) # We only handle one server cert nickname = server_certs[0][0] ca_names = [name for name, flags in self.nssdb.list_certs() if 'u' not in flags] if len(ca_names) == 0: raise RuntimeError("Could not find a CA cert in %s" % pkcs12_fname) self.cacert_name = ca_names[0] for ca in ca_names: self.trust_root_cert(ca) self.create_pin_file() self.export_ca_cert(nickname, False) def install_pem_from_p12(self, p12_fname, p12_passwd, pem_fname): pwd = ipautil.write_tmp_file(p12_passwd) ipautil.run(["/usr/bin/openssl", "pkcs12", "-nodes", "-in", p12_fname, "-out", pem_fname, "-passin", "file:" + pwd.name]) def publish_ca_cert(self, location): shutil.copy(self.cacert_fname, location) os.chmod(location, 0444) def export_pem_cert(self, nickname, location): return self.nssdb.export_pem_cert(nickname, location) freeipa-3.3.4/ipaserver/install/ipa_restore.py0000664000175000017500000005674012271663206021057 0ustar mkosekmkosek# Authors: Rob Crittenden # # Copyright (C) 2013 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 . # import os import sys import shutil import tempfile import time import pwd from ConfigParser import SafeConfigParser from ipalib import api, errors from ipapython import version from ipapython.ipautil import run, user_input from ipapython import admintool from ipapython.dn import DN from ipaserver.install.dsinstance import (realm_to_serverid, create_ds_group, create_ds_user, DS_USER) from ipaserver.install.cainstance import PKI_USER from ipaserver.install.replication import (wait_for_task, ReplicationManager, get_cs_replication_manager) from ipaserver.install import installutils from ipapython import services as ipaservices from ipapython import ipaldap from ipaserver.install.ipa_backup import BACKUP_DIR def recursive_chown(path, uid, gid): ''' Change ownership of all files and directories in a path. ''' for root, dirs, files in os.walk(path): for dir in dirs: os.chown(os.path.join(root, dir), uid, gid) os.chmod(os.path.join(root, dir), 0750) for file in files: os.chown(os.path.join(root, file), uid, gid) os.chmod(os.path.join(root, file), 0640) def decrypt_file(tmpdir, filename, keyring): source = filename (dest, ext) = os.path.splitext(filename) if ext != '.gpg': raise admintool.ScriptError('Trying to decrypt a non-gpg file') dest = os.path.basename(dest) dest = os.path.join(tmpdir, dest) args = ['/usr/bin/gpg', '--batch', '-o', dest] if keyring is not None: args.append('--no-default-keyring') args.append('--keyring') args.append(keyring + '.pub') args.append('--secret-keyring') args.append(keyring + '.sec') args.append('-d') args.append(source) (stdout, stderr, rc) = run(args, raiseonerr=False) if rc != 0: raise admintool.ScriptError('gpg failed: %s' % stderr) return dest class Restore(admintool.AdminTool): command_name = 'ipa-restore' log_file_name = '/var/log/iparestore.log' usage = "%prog [options] backup" description = "Restore IPA files and databases." def __init__(self, options, args): super(Restore, self).__init__(options, args) self._conn = None @classmethod def add_options(cls, parser): super(Restore, cls).add_options(parser, debug_option=True) parser.add_option("-p", "--password", dest="password", help="Directory Manager password") parser.add_option("--gpg-keyring", dest="gpg_keyring", help="The gpg key name to be used") parser.add_option("--data", dest="data_only", action="store_true", default=False, help="Restore only the data") parser.add_option("--online", dest="online", action="store_true", default=False, help="Perform the LDAP restores online, for data only.") parser.add_option("--instance", dest="instance", help="The 389-ds instance to restore (defaults to all found)") parser.add_option("--backend", dest="backend", help="The backend to restore within the instance or instances") parser.add_option('--no-logs', dest="no_logs", action="store_true", default=False, help="Do not restore log files from the backup") parser.add_option('-U', '--unattended', dest="unattended", action="store_true", default=False, help="Unattended restoration never prompts the user") def setup_logging(self, log_file_mode='a'): super(Restore, self).setup_logging(log_file_mode='a') def validate_options(self): options = self.options super(Restore, self).validate_options(needs_root=True) if options.data_only: installutils.check_server_configuration() if len(self.args) < 1: self.option_parser.error( "must provide the backup to restore") elif len(self.args) > 1: self.option_parser.error( "must provide exactly one name for the backup") dirname = self.args[0] if not os.path.isabs(dirname): self.backup_dir = os.path.join(BACKUP_DIR, dirname) else: self.backup_dir = dirname if options.gpg_keyring: if (not os.path.exists(options.gpg_keyring + '.pub') or not os.path.exists(options.gpg_keyring + '.sec')): raise admintool.ScriptError('No such key %s' % options.gpg_keyring) def ask_for_options(self): options = self.options super(Restore, self).ask_for_options() # get the directory manager password self.dirman_password = options.password if not options.password: if not options.unattended: self.dirman_password = installutils.read_password( "Directory Manager (existing master)", confirm=False, validate=False) if self.dirman_password is None: raise admintool.ScriptError( "Directory Manager password required") def run(self): options = self.options super(Restore, self).run() api.bootstrap(in_server=False, context='restore') api.finalize() self.log.info("Preparing restore from %s on %s", self.backup_dir, api.env.host) if not options.instance: instances = [] for instance in [realm_to_serverid(api.env.realm), 'PKI-IPA']: if os.path.exists('/var/lib/dirsrv/slapd-%s' % instance): instances.append(instance) else: instances = [options.instance] if options.data_only and not instances: raise admintool.ScriptError('No instances to restore to') create_ds_group() create_ds_user() pent = pwd.getpwnam(DS_USER) # Temporary directory for decrypting files before restoring self.top_dir = tempfile.mkdtemp("ipa") os.chown(self.top_dir, pent.pw_uid, pent.pw_gid) os.chmod(self.top_dir, 0750) self.dir = os.path.join(self.top_dir, "ipa") os.mkdir(self.dir, 0750) os.chown(self.dir, pent.pw_uid, pent.pw_gid) self.header = os.path.join(self.backup_dir, 'header') cwd = os.getcwd() try: dirsrv = ipaservices.knownservices.dirsrv self.read_header() # These two checks would normally be in the validate method but # we need to know the type of backup we're dealing with. if (self.backup_type != 'FULL' and not options.data_only and not instances): raise admintool.ScriptError('Cannot restore a data backup into an empty system') if (self.backup_type == 'FULL' and not options.data_only and (options.instance or options.backend)): raise admintool.ScriptError('Restore must be in data-only mode when restoring a specific instance or backend.') if self.backup_host != api.env.host: self.log.warning('Host name %s does not match backup name %s' % (api.env.host, self.backup_host)) if (not options.unattended and not user_input("Continue to restore?", False)): raise admintool.ScriptError("Aborted") if self.backup_ipa_version != str(version.VERSION): self.log.warning( "Restoring data from a different release of IPA.\n" "Data is version %s.\n" "Server is running %s." % (self.backup_ipa_version, str(version.VERSION))) if (not options.unattended and not user_input("Continue to restore?", False)): raise admintool.ScriptError("Aborted") # Big fat warning if (not options.unattended and not user_input("Restoring data will overwrite existing live data. Continue to restore?", False)): raise admintool.ScriptError("Aborted") self.log.info( "Each master will individually need to be re-initialized or") self.log.info( "re-created from this one. The replication agreements on") self.log.info( "masters running IPA 3.1 or earlier will need to be manually") self.log.info( "re-enabled. See the man page for details.") self.log.info("Disabling all replication.") self.disable_agreements() self.extract_backup(options.gpg_keyring) if options.data_only: if not options.online: self.log.info('Stopping Directory Server') dirsrv.stop(capture_output=False) else: self.log.info('Starting Directory Server') dirsrv.start(capture_output=False) else: self.log.info('Stopping IPA services') (stdout, stderr, rc) = run(['ipactl', 'stop'], raiseonerr=False) if rc not in [0, 6]: self.log.warn('Stopping IPA failed: %s' % stderr) # We do either a full file restore or we restore data. if self.backup_type == 'FULL' and not options.data_only: if options.online: raise admintool.ScriptError('File restoration cannot be done online.') self.file_restore(options.no_logs) if 'CA' in self.backup_services: self.__create_dogtag_log_dirs() # Always restore the data from ldif # If we are restoring PKI-IPA then we need to restore the # userRoot backend in it and the main IPA instance. If we # have a unified instance we need to restore both userRoot and # ipaca. for instance in instances: if os.path.exists('/var/lib/dirsrv/slapd-%s' % instance): if options.backend is None: self.ldif2db(instance, 'userRoot', online=options.online) if os.path.exists('/var/lib/dirsrv/slapd-%s/db/ipaca' % instance): self.ldif2db(instance, 'ipaca', online=options.online) else: self.ldif2db(instance, options.backend, online=options.online) else: raise admintool.ScriptError('389-ds instance %s does not exist' % instance) if options.data_only: if not options.online: self.log.info('Starting Directory Server') dirsrv.start(capture_output=False) else: # explicitly enable then disable the pki tomcatd service to # re-register its instance. FIXME, this is really wierd. ipaservices.knownservices.pki_tomcatd.enable() ipaservices.knownservices.pki_tomcatd.disable() self.log.info('Starting IPA services') run(['ipactl', 'start']) self.log.info('Restarting SSSD') sssd = ipaservices.service('sssd') sssd.restart() finally: try: os.chdir(cwd) except Exception, e: self.log.error('Cannot change directory to %s: %s' % (cwd, e)) shutil.rmtree(self.top_dir) def get_connection(self): ''' Create an ldapi connection and bind to it using autobind as root. ''' if self._conn is not None: return self._conn self._conn = ipaldap.IPAdmin(host=api.env.host, ldapi=True, protocol='ldapi', realm=api.env.realm) try: pw_name = pwd.getpwuid(os.geteuid()).pw_name self._conn.do_external_bind(pw_name) except Exception, e: raise admintool.ScriptError('Unable to bind to LDAP server: %s' % e) return self._conn def disable_agreements(self): ''' Find all replication agreements on all masters and disable them. Warn very loudly about any agreements/masters we cannot contact. ''' try: conn = self.get_connection() except Exception, e : self.log.error('Unable to get connection, skipping disabling agreements: %s' % e) return masters = [] dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) try: entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL) except Exception, e: raise admintool.ScriptError( "Failed to read master data: %s" % e) else: masters = [ent.single_value('cn') for ent in entries] for master in masters: if master == api.env.host: continue try: repl = ReplicationManager(api.env.realm, master, self.dirman_password) except Exception, e: self.log.critical("Unable to disable agreement on %s: %s" % (master, e)) master_dn = DN(('cn', master), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) try: services = repl.conn.get_entries(master_dn, repl.conn.SCOPE_ONELEVEL) except errors.NotFound: continue services_cns = [s.single_value('cn') for s in services] host_entries = repl.find_ipa_replication_agreements() hosts = [rep.single_value('nsds5replicahost', None) for rep in host_entries] for host in hosts: self.log.info('Disabling replication agreement on %s to %s' % (master, host)) repl.disable_agreement(host) if 'CA' in services_cns: try: repl = get_cs_replication_manager(api.env.realm, master, self.dirman_password) except Exception, e: self.log.critical("Unable to disable agreement on %s: %s" % (master, e)) host_entries = repl.find_ipa_replication_agreements() hosts = [rep.single_value('nsds5replicahost', None) for rep in host_entries] for host in hosts: self.log.info('Disabling CA replication agreement on %s to %s' % (master, host)) repl.hostnames = [master, host] repl.disable_agreement(host) def ldif2db(self, instance, backend, online=True): ''' Restore a LDIF backup of the data in this instance. If executed online create a task and wait for it to complete. ''' self.log.info('Restoring from %s in %s' % (backend, instance)) now = time.localtime() cn = time.strftime('import_%Y_%m_%d_%H_%M_%S') dn = DN(('cn', cn), ('cn', 'import'), ('cn', 'tasks'), ('cn', 'config')) ldifname = '%s-%s.ldif' % (instance, backend) ldiffile = os.path.join(self.dir, ldifname) if online: conn = self.get_connection() ent = conn.make_entry( dn, { 'objectClass': ['top', 'extensibleObject'], 'cn': [cn], 'nsFilename': [ldiffile], 'nsUseOneFile': ['true'], } ) ent['nsInstance'] = [backend] try: conn.add_entry(ent) except Exception, e: raise admintool.ScriptError( 'Unable to bind to LDAP server: %s' % e) self.log.info("Waiting for LDIF to finish") wait_for_task(conn, dn) else: args = ['%s/ldif2db' % self.__find_scripts_dir(instance), '-i', ldiffile] if backend is not None: args.append('-n') args.append(backend) else: args.append('-n') args.append('userRoot') (stdout, stderr, rc) = run(args, raiseonerr=False) if rc != 0: self.log.critical("ldif2db failed: %s" % stderr) def bak2db(self, instance, backend, online=True): ''' Restore a BAK backup of the data and changelog in this instance. If backend is None then all backends are restored. If executed online create a task and wait for it to complete. instance here is a loaded term. It can mean either a separate 389-ds install instance or a separate 389-ds backend. We only need to treat PKI-IPA and ipaca specially. ''' if backend is not None: self.log.info('Restoring %s in %s' % (backend, instance)) else: self.log.info('Restoring %s' % instance) cn = time.strftime('restore_%Y_%m_%d_%H_%M_%S') dn = DN(('cn', cn), ('cn', 'restore'), ('cn', 'tasks'), ('cn', 'config')) if online: conn = self.get_connection() ent = conn.make_entry( dn, { 'objectClass': ['top', 'extensibleObject'], 'cn': [cn], 'nsArchiveDir': [os.path.join(self.dir, instance)], 'nsDatabaseType': ['ldbm database'], } ) if backend is not None: ent['nsInstance'] = [backend] try: conn.add_entry(ent) except Exception, e: raise admintool.ScriptError('Unable to bind to LDAP server: %s' % e) self.log.info("Waiting for restore to finish") wait_for_task(conn, dn) else: args = ['%s/bak2db' % self.__find_scripts_dir(instance), os.path.join(self.dir, instance)] if backend is not None: args.append('-n') args.append(backend) (stdout, stderr, rc) = run(args, raiseonerr=False) if rc != 0: self.log.critical("bak2db failed: %s" % stderr) def file_restore(self, nologs=False): ''' Restore all the files in the tarball. This MUST be done offline because we directly backup the 389-ds databases. ''' self.log.info("Restoring files") cwd = os.getcwd() os.chdir('/') args = ['tar', '-xzf', os.path.join(self.dir, 'files.tar') ] if nologs: args.append('--exclude') args.append('var/log') (stdout, stderr, rc) = run(args, raiseonerr=False) if rc != 0: self.log.critical('Restoring files failed: %s', stderr) os.chdir(cwd) def read_header(self): ''' Read the backup file header that contains the meta data about this particular backup. ''' fd = open(self.header) config = SafeConfigParser() config.readfp(fd) self.backup_type = config.get('ipa', 'type') self.backup_time = config.get('ipa', 'time') self.backup_host = config.get('ipa', 'host') self.backup_ipa_version = config.get('ipa', 'ipa_version') self.backup_version = config.get('ipa', 'version') self.backup_services = config.get('ipa', 'services') def extract_backup(self, keyring=None): ''' Extract the contents of the tarball backup into a temporary location, decrypting if necessary. ''' encrypt = False filename = None if self.backup_type == 'FULL': filename = os.path.join(self.backup_dir, 'ipa-full.tar') else: filename = os.path.join(self.backup_dir, 'ipa-data.tar') if not os.path.exists(filename): if not os.path.exists(filename + '.gpg'): raise admintool.ScriptError('Unable to find backup file in %s' % self.backup_dir) else: filename = filename + '.gpg' encrypt = True if encrypt: self.log.info('Decrypting %s' % filename) filename = decrypt_file(self.dir, filename, keyring) cwd = os.getcwd() os.chdir(self.dir) args = ['tar', '-xzf', filename, '.' ] run(args) pent = pwd.getpwnam(DS_USER) os.chown(self.top_dir, pent.pw_uid, pent.pw_gid) recursive_chown(self.dir, pent.pw_uid, pent.pw_gid) if encrypt: # We can remove the decoded tarball os.unlink(filename) def __find_scripts_dir(self, instance): """ IPA stores its 389-ds scripts in a different directory than dogtag does so we need to probe for it. """ if instance != 'PKI-IPA': return os.path.join('/var/lib/dirsrv', 'scripts-%s' % instance) else: if sys.maxsize > 2**32L: libpath = 'lib64' else: libpath = 'lib' return os.path.join('/usr', libpath, 'dirsrv', 'slapd-PKI-IPA') def __create_dogtag_log_dirs(self): """ If we are doing a full restore and the dogtag log directories do not exist then tomcat will fail to start. The directory is different depending on whether we have a d9-based or a d10-based installation. We can tell based on whether there is a PKI-IPA 389-ds instance. """ if os.path.exists('/etc/dirsrv/slapd-PKI-IPA'): # dogtag 9 topdir = '/var/log/pki-ca' dirs = [topdir, '/var/log/pki-ca/signedAudit,'] else: # dogtag 10 topdir = '/var/log/pki/pki-tomcat' dirs = [topdir, '/var/log/pki/pki-tomcat/ca', '/var/log/pki/pki-tomcat/ca/archive', '/var/log/pki/pki-tomcat/ca/signedAudit',] if os.path.exists(topdir): return try: pent = pwd.getpwnam(PKI_USER) except KeyError: self.log.debug("No %s user exists, skipping CA directory creation" % PKI_USER) return self.log.debug('Creating log directories for dogtag') for dir in dirs: try: self.log.debug('Creating %s' % dir) os.mkdir(dir, 0770) os.chown(dir, pent.pw_uid, pent.pw_gid) ipaservices.restore_context(dir) except Exception, e: # This isn't so fatal as to side-track the restore self.log.error('Problem with %s: %s' % (dir, e)) freeipa-3.3.4/ipaserver/install/otpdinstance.py0000664000175000017500000000163412271663206021226 0ustar mkosekmkosek# Authors: Tomas Babej # # Copyright (C) 2013 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 . # import service class OtpdInstance(service.SimpleServiceInstance): def __init__(self): service.SimpleServiceInstance.__init__(self, "ipa-otpd")freeipa-3.3.4/ipaserver/install/ipa_replica_prepare.py0000664000175000017500000005466212271663206022532 0ustar mkosekmkosek# Authors: Karl MacMillan # Petr Viktorin # # Copyright (C) 2008-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 . # import os import shutil import tempfile from optparse import OptionGroup from ConfigParser import SafeConfigParser from ipaserver.install import certs, installutils, bindinstance, dsinstance from ipaserver.install.replication import enable_replication_version_checking from ipaserver.plugins.ldap2 import ldap2 from ipaserver.install.bindinstance import ( add_zone, add_fwd_rr, add_ptr_rr, dns_container_exists) from ipapython import ipautil, admintool, dogtag from ipapython.dn import DN from ipapython import version from ipalib import api from ipalib import errors class ReplicaPrepare(admintool.AdminTool): command_name = 'ipa-replica-prepare' usage = "%prog [options] " description = "Prepare a file for replica installation." @classmethod def add_options(cls, parser): super(ReplicaPrepare, cls).add_options(parser, debug_option=True) parser.add_option("-p", "--password", dest="password", help="Directory Manager password (for the existing master)") parser.add_option("--ip-address", dest="ip_address", type="ip", help="add A and PTR records of the future replica") parser.add_option("--reverse-zone", dest="reverse_zone", help="the reverse DNS zone to use") parser.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="do not create reverse DNS zone") parser.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", default=True, help="disables pkinit setup steps") parser.add_option("--ca", dest="ca_file", default="/root/cacert.p12", metavar="FILE", help="location of CA PKCS#12 file, default /root/cacert.p12") group = OptionGroup(parser, "SSL certificate options", "Only used if the server was installed using custom SSL certificates") group.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12", metavar="FILE", help="install certificate for the directory server") group.add_option("--http_pkcs12", dest="http_pkcs12", metavar="FILE", help="install certificate for the http server") group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12", metavar="FILE", help="install certificate for the KDC") group.add_option("--dirsrv_pin", dest="dirsrv_pin", metavar="PIN", help="PIN for the Directory Server PKCS#12 file") group.add_option("--http_pin", dest="http_pin", metavar="PIN", help="PIN for the Apache Server PKCS#12 file") group.add_option("--pkinit_pin", dest="pkinit_pin", metavar="PIN", help="PIN for the KDC pkinit PKCS#12 file") parser.add_option_group(group) def validate_options(self): options = self.options super(ReplicaPrepare, self).validate_options(needs_root=True) installutils.check_server_configuration() if not options.ip_address: if options.reverse_zone: self.option_parser.error("You cannot specify a --reverse-zone " "option without the --ip-address option") if options.no_reverse: self.option_parser.error("You cannot specify a --no-reverse " "option without the --ip-address option") elif options.reverse_zone and options.no_reverse: self.option_parser.error("You cannot specify a --reverse-zone " "option together with --no-reverse") #Automatically disable pkinit w/ dogtag until that is supported options.setup_pkinit = False # If any of the PKCS#12 options are selected, all are required. pkcs12_req = (options.dirsrv_pkcs12, options.http_pkcs12) pkcs12_opt = (options.pkinit_pkcs12,) if any(pkcs12_req + pkcs12_opt) and not all(pkcs12_req): self.option_parser.error( "--dirsrv_pkcs12 and --http_pkcs12 are required if any " "PKCS#12 options are used.") if len(self.args) < 1: self.option_parser.error( "must provide the fully-qualified name of the replica") elif len(self.args) > 1: self.option_parser.error( "must provide exactly one name for the replica") else: [self.replica_fqdn] = self.args api.bootstrap(in_server=True) api.finalize() if api.env.host == self.replica_fqdn: raise admintool.ScriptError("You can't create a replica on itself") if not api.env.enable_ra and not options.http_pkcs12: raise admintool.ScriptError( "Cannot issue certificates: a CA is not installed. Use the " "--http_pkcs12, --dirsrv_pkcs12 options to provide custom " "certificates.") config_dir = dsinstance.config_dirname( dsinstance.realm_to_serverid(api.env.realm)) if not ipautil.dir_exists(config_dir): raise admintool.ScriptError( "could not find directory instance: %s" % config_dir) def check_pkcs12(self, pkcs12_file, pkcs12_pin): installutils.check_pkcs12( pkcs12_info=(pkcs12_file, pkcs12_pin), ca_file='/etc/ipa/ca.crt', hostname=self.replica_fqdn) def ask_for_options(self): options = self.options super(ReplicaPrepare, self).ask_for_options() # get the directory manager password self.dirman_password = options.password if not options.password: self.dirman_password = installutils.read_password( "Directory Manager (existing master)", confirm=False, validate=False) if self.dirman_password is None: raise admintool.ScriptError( "Directory Manager password required") # Try out the password & get the subject base suffix = ipautil.realm_to_suffix(api.env.realm) try: conn = ldap2(shared_instance=False, base_dn=suffix) conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=self.dirman_password) dn, entry_attrs = conn.get_ipa_config() conn.disconnect() except errors.ACIError: raise admintool.ScriptError("The password provided is incorrect " "for LDAP server %s" % api.env.host) except errors.LDAPError: raise admintool.ScriptError( "Unable to connect to LDAP server %s" % api.env.host) except errors.DatabaseError, e: raise admintool.ScriptError(e.desc) self.subject_base = entry_attrs.get( 'ipacertificatesubjectbase', [None])[0] if self.subject_base is not None: self.subject_base = DN(self.subject_base) # Validate more options using the password try: installutils.verify_fqdn(self.replica_fqdn, local_hostname=False) except installutils.BadHostError, e: msg = str(e) if isinstance(e, installutils.HostLookupError): if options.ip_address is None: if dns_container_exists( api.env.host, api.env.basedn, dm_password=self.dirman_password, ldapi=True, realm=api.env.realm): self.log.info('Add the --ip-address argument to ' 'create a DNS entry.') raise else: # The host doesn't exist in DNS but we're adding it. pass else: raise if options.ip_address: if not dns_container_exists(api.env.host, api.env.basedn, dm_password=self.dirman_password, ldapi=True, realm=api.env.realm): raise admintool.ScriptError("You can't add a DNS record " "because DNS is not set up.") if options.reverse_zone and not bindinstance.verify_reverse_zone( options.reverse_zone, options.ip_address): raise admintool.ScriptError("Invalid reverse zone") if options.http_pkcs12: if options.http_pin is None: options.http_pin = installutils.read_password( "Enter %s unlock" % options.http_pkcs12, confirm=False, validate=False) if options.http_pin is None: raise admintool.ScriptError( "%s unlock password required" % options.http_pkcs12) self.check_pkcs12(options.http_pkcs12, options.http_pin) if options.dirsrv_pkcs12: if options.dirsrv_pin is None: options.dirsrv_pin = installutils.read_password( "Enter %s unlock" % options.dirsrv_pkcs12, confirm=False, validate=False) if options.dirsrv_pin is None: raise admintool.ScriptError( "%s unlock password required" % options.dirsrv_pkcs12) self.check_pkcs12(options.dirsrv_pkcs12, options.dirsrv_pin) if options.pkinit_pkcs12: if options.pkinit_pin is None: options.pkinit_pin = installutils.read_password( "Enter %s unlock" % options.pkinit_pkcs12, confirm=False, validate=False) if options.pkinit_pin is None: raise admintool.ScriptError( "%s unlock password required" % options.pkinit_pkcs12) if (not ipautil.file_exists( dogtag.configured_constants().CS_CFG_PATH) and options.dirsrv_pin is None): self.log.info("If you installed IPA with your own certificates " "using PKCS#12 files you must provide PKCS#12 files for any " "replicas you create as well.") raise admintool.ScriptError("The replica must be created on the " "primary IPA server.") def run(self): options = self.options super(ReplicaPrepare, self).run() self.log.info("Preparing replica for %s from %s", self.replica_fqdn, api.env.host) enable_replication_version_checking(api.env.host, api.env.realm, self.dirman_password) self.top_dir = tempfile.mkdtemp("ipa") self.dir = os.path.join(self.top_dir, "realm_info") os.mkdir(self.dir, 0700) try: self.copy_ds_certificate() self.copy_httpd_certificate() if options.setup_pkinit: self.copy_pkinit_certificate() self.copy_misc_files() self.save_config() self.package_replica_file() finally: shutil.rmtree(self.top_dir) if options.ip_address: self.add_dns_records() def copy_ds_certificate(self): options = self.options passwd_fname = os.path.join(self.dir, "dirsrv_pin.txt") with open(passwd_fname, "w") as fd: fd.write("%s\n" % (options.dirsrv_pin or '')) if options.dirsrv_pkcs12: self.log.info( "Copying SSL certificate for the Directory Server from %s", options.dirsrv_pkcs12) self.copy_info_file(options.dirsrv_pkcs12, "dscert.p12") else: if ipautil.file_exists(options.ca_file): # Since it is possible that the Directory Manager password # has changed since ipa-server-install, we need to regenerate # the CA PKCS#12 file and update the pki admin user password self.regenerate_ca_file(options.ca_file) self.update_pki_admin_password() self.copy_info_file(options.ca_file, "cacert.p12") else: raise admintool.ScriptError("Root CA PKCS#12 not " "found in %s" % options.ca_file) self.log.info( "Creating SSL certificate for the Directory Server") self.export_certdb("dscert", passwd_fname) if not options.dirsrv_pkcs12: self.log.info( "Creating SSL certificate for the dogtag Directory Server") self.export_certdb("dogtagcert", passwd_fname) self.log.info("Saving dogtag Directory Server port") port_fname = os.path.join( self.dir, "dogtag_directory_port.txt") with open(port_fname, "w") as fd: fd.write("%s\n" % str(dogtag.configured_constants().DS_PORT)) def copy_httpd_certificate(self): options = self.options passwd_fname = os.path.join(self.dir, "http_pin.txt") with open(passwd_fname, "w") as fd: fd.write("%s\n" % (options.http_pin or '')) if options.http_pkcs12: self.log.info( "Copying SSL certificate for the Web Server from %s", options.http_pkcs12) self.copy_info_file(options.http_pkcs12, "httpcert.p12") else: self.log.info("Creating SSL certificate for the Web Server") self.export_certdb("httpcert", passwd_fname) self.log.info("Exporting RA certificate") self.export_ra_pkcs12() def copy_pkinit_certificate(self): options = self.options passwd_fname = os.path.join(self.dir, "pkinit_pin.txt") with open(passwd_fname, "w") as fd: fd.write("%s\n" % (options.pkinit_pin or '')) if options.pkinit_pkcs12: self.log.info( "Copying SSL certificate for the KDC from %s", options.pkinit_pkcs12) self.copy_info_file(options.pkinit_pkcs12, "pkinitcert.p12") else: self.log.info("Creating SSL certificate for the KDC") self.export_certdb("pkinitcert", passwd_fname, is_kdc=True) def copy_misc_files(self): self.log.info("Copying additional files") self.copy_info_file("/etc/ipa/ca.crt", "ca.crt") preferences_filename = "/usr/share/ipa/html/preferences.html" if ipautil.file_exists(preferences_filename): self.copy_info_file(preferences_filename, "preferences.html") self.copy_info_file("/usr/share/ipa/html/krb.js", "krb.js") self.copy_info_file( "/usr/share/ipa/html/kerberosauth.xpi", "kerberosauth.xpi") jar_filename = "/usr/share/ipa/html/configure.jar" if ipautil.file_exists(jar_filename): self.copy_info_file(jar_filename, "configure.jar") cacert_filename = "/var/kerberos/krb5kdc/cacert.pem" if ipautil.file_exists(cacert_filename): self.copy_info_file(cacert_filename, "cacert.pem") def save_config(self): self.log.info("Finalizing configuration") config = SafeConfigParser() config.add_section("realm") config.set("realm", "realm_name", api.env.realm) config.set("realm", "master_host_name", api.env.host) config.set("realm", "domain_name", api.env.domain) config.set("realm", "destination_host", self.replica_fqdn) config.set("realm", "subject_base", str(self.subject_base)) config.set("realm", "version", str(version.NUM_VERSION)) with open(os.path.join(self.dir, "realm_info"), "w") as fd: config.write(fd) def package_replica_file(self): replicafile = "/var/lib/ipa/replica-info-%s" % self.replica_fqdn encfile = "%s.gpg" % replicafile self.log.info("Packaging replica information into %s", encfile) ipautil.run( ["/bin/tar", "cf", replicafile, "-C", self.top_dir, "realm_info"]) ipautil.encrypt_file( replicafile, encfile, self.dirman_password, self.top_dir) os.chmod(encfile, 0600) installutils.remove_file(replicafile) def add_dns_records(self): options = self.options self.log.info("Adding DNS records for %s", self.replica_fqdn) api.Backend.ldap2.connect( bind_dn=DN(('cn', 'Directory Manager')), bind_pw=self.dirman_password) name, domain = self.replica_fqdn.split(".", 1) ip = options.ip_address ip_address = str(ip) if options.reverse_zone: reverse_zone = bindinstance.normalize_zone(options.reverse_zone) else: reverse_zone = bindinstance.find_reverse_zone(ip) if reverse_zone is None and not options.no_reverse: reverse_zone = bindinstance.get_reverse_zone_default(ip) try: add_zone(domain) except errors.PublicError, e: raise admintool.ScriptError( "Could not create forward DNS zone for the replica: %s" % e) try: add_fwd_rr(domain, name, ip_address) except errors.PublicError, e: raise admintool.ScriptError( "Could not add forward DNS record for the replica: %s" % e) if reverse_zone is not None: self.log.info("Using reverse zone %s", reverse_zone) try: add_zone(reverse_zone) except errors.PublicError, e: raise admintool.ScriptError( "Could not create reverse DNS zone for replica: %s" % e) try: add_ptr_rr(reverse_zone, ip_address, self.replica_fqdn) except errors.PublicError, e: raise admintool.ScriptError( "Could not add reverse DNS record for the replica: %s" % e) def copy_info_file(self, source, dest): """Copy a file into the info directory :param source: The source file (an absolute path) :param dest: The destination file (relative to the info directory) """ dest_path = os.path.join(self.dir, dest) self.log.debug('Copying %s to %s', source, dest_path) try: shutil.copy(source, dest_path) except IOError, e: raise admintool.ScriptError("File copy failed: %s" % e) def remove_info_file(self, filename): """Remove a file from the info directory :param filename: The unneeded file (relative to the info directory) """ installutils.remove_file(os.path.join(self.dir, filename)) def export_certdb(self, fname, passwd_fname, is_kdc=False): """Export a cert database :param fname: The file to export to (relative to the info directory) :param passwd_fname: File that holds the cert DB password :param is_kdc: True if we're exporting KDC certs """ options = self.options hostname = self.replica_fqdn subject_base = self.subject_base if is_kdc: nickname = "KDC-Cert" else: nickname = "Server-Cert" try: db = certs.CertDB( api.env.realm, nssdir=self.dir, subject_base=subject_base) db.create_passwd_file() ca_db = certs.CertDB( api.env.realm, host_name=api.env.host, subject_base=subject_base) db.create_from_cacert(ca_db.cacert_fname) db.create_server_cert(nickname, hostname, ca_db) pkcs12_fname = os.path.join(self.dir, fname + ".p12") try: if is_kdc: ca_db.export_pem_p12(pkcs12_fname, passwd_fname, nickname, os.path.join(self.dir, "kdc.pem")) else: db.export_pkcs12(pkcs12_fname, passwd_fname, nickname) except ipautil.CalledProcessError, e: self.log.info("error exporting Server certificate: %s", e) installutils.remove_file(pkcs12_fname) installutils.remove_file(passwd_fname) self.remove_info_file("cert8.db") self.remove_info_file("key3.db") self.remove_info_file("secmod.db") self.remove_info_file("noise.txt") if is_kdc: self.remove_info_file("kdc.pem") orig_filename = passwd_fname + ".orig" if ipautil.file_exists(orig_filename): installutils.remove_file(orig_filename) except errors.CertificateOperationError, e: raise admintool.ScriptError(str(e)) def export_ra_pkcs12(self): agent_fd, agent_name = tempfile.mkstemp() os.write(agent_fd, self.dirman_password) os.close(agent_fd) try: db = certs.CertDB(api.env.realm, host_name=api.env.host) if db.has_nickname("ipaCert"): pkcs12_fname = os.path.join(self.dir, "ra.p12") db.export_pkcs12(pkcs12_fname, agent_name, "ipaCert") finally: os.remove(agent_name) def update_pki_admin_password(self): ldap = ldap2(shared_instance=False) ldap.connect( bind_dn=DN(('cn', 'directory manager')), bind_pw=self.dirman_password ) dn = DN('uid=admin', 'ou=people', 'o=ipaca') ldap.modify_password(dn, self.dirman_password) ldap.disconnect() def regenerate_ca_file(self, ca_file): dm_pwd_fd = ipautil.write_tmp_file(self.dirman_password) keydb_pwd = '' with open('/etc/pki/pki-tomcat/password.conf') as f: for line in f.readlines(): key, value = line.strip().split('=') if key == 'internal': keydb_pwd = value break keydb_pwd_fd = ipautil.write_tmp_file(keydb_pwd) ipautil.run([ '/usr/bin/PKCS12Export', '-d', '/etc/pki/pki-tomcat/alias/', '-p', keydb_pwd_fd.name, '-w', dm_pwd_fd.name, '-o', ca_file ]) freeipa-3.3.4/ipaserver/install/ipa_ldap_updater.py0000664000175000017500000001503612271663206022031 0ustar mkosekmkosek# Authors: Rob Crittenden # Petr Viktorin # # 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 . # # Documentation can be found at http://freeipa.org/page/LdapUpdate # TODO # save undo files? import os import sys 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 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, debug_option=True) 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 " + "(implied when no input files are given)") 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, **kwargs): options = self.options super(LDAPUpdater, self).validate_options(**kwargs) 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: try: installutils.check_server_configuration() except RuntimeError, e: print unicode(e) sys.exit(1) elif not os.path.exists('/etc/ipa/default.conf'): print "IPA is not configured on this system." sys.exit(1) if options.password: pw = ipautil.template_file(options.password, []) self.dirman_password = pw.strip() else: self.dirman_password = None def setup_logging(self): super(LDAPUpdater, self).setup_logging(log_file_mode='a') def run(self): super(LDAPUpdater, self).run() api.bootstrap(in_server=True, context='updates') api.finalize() def handle_error(self, exception): return installutils.handle_error(exception, self.log_file_name) class LDAPUpdater_Upgrade(LDAPUpdater): 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(needs_root=True) 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.log.info('Update complete, changes to be made, test mode') return 2 class LDAPUpdater_NonUpgrade(LDAPUpdater): log_file_name = '/var/log/ipaupgrade.log' 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 os.getegid() != 0: if self.run_plugins: raise admintool.ScriptError( 'Plugins can only be run as root.', 1) else: # Can't log to the default file as non-root self.log_file_name = None 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, ordered=True) if modified and options.test: self.log.info('Update complete, changes to be made, test mode') return 2 freeipa-3.3.4/ipaserver/install/cainstance.py0000664000175000017500000022210512271663206020641 0ustar mkosekmkosek# Authors: Rob Crittenden # Ade Lee # Andrew Wnuk # # Copyright (C) 2009 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 . # import pwd import os import sys import re import time import ldap import base64 import array import tempfile import binascii import shutil import httplib import urllib import xml.dom.minidom import stat import syslog import ConfigParser from ipapython import dogtag from ipapython.certdb import get_ca_nickname from ipapython import certmonger from ipalib import pkcs10, x509 from ipalib import errors from ipapython.dn import DN import subprocess import traceback from ipapython import ipautil from ipapython import services as ipaservices from ipapython import ipaldap from ipaserver.install import service from ipaserver.install import installutils from ipaserver.install import dsinstance from ipaserver.install import certs from ipaserver.install.installutils import stopped_service from ipaserver.plugins import ldap2 from ipapython.ipa_log_manager import * HTTPD_CONFD = "/etc/httpd/conf.d/" DEFAULT_DSPORT = dogtag.install_constants.DS_PORT PKI_USER = "pkiuser" PKI_DS_USER = dogtag.install_constants.DS_USER # When IPA is installed with DNS support, this CNAME should hold all IPA # replicas with CA configured IPA_CA_RECORD = "ipa-ca" # We need to reset the template because the CA uses the regular boot # information INF_TEMPLATE = """ [General] FullMachineName= $FQDN SuiteSpotUserID= $USER SuiteSpotGroup= $GROUP ServerRoot= $SERVER_ROOT [slapd] ServerPort= $DSPORT ServerIdentifier= $SERVERID Suffix= $SUFFIX RootDN= cn=Directory Manager RootDNPwd= $PASSWORD ConfigFile = /usr/share/pki/ca/conf/database.ldif """ def check_inst(): """ Validate that the appropriate dogtag/RHCS packages have been installed. """ # Check for a couple of binaries we need if not os.path.exists(dogtag.install_constants.SPAWN_BINARY): return False if not os.path.exists(dogtag.install_constants.DESTROY_BINARY): return False # This is the template tomcat file for a CA if not os.path.exists('/usr/share/pki/ca/conf/server.xml'): return False return True def get_preop_pin(instance_root, instance_name): # Only used for Dogtag 9 preop_pin = None filename = instance_root + "/" + instance_name + "/conf/CS.cfg" # read the config file and get the preop pin try: f=open(filename) except IOError, e: root_logger.error("Cannot open configuration file." + str(e)) raise e data = f.read() data = data.split('\n') pattern = re.compile("preop.pin=(.*)" ) for line in data: match = re.search(pattern, line) if (match): preop_pin=match.group(1) break if preop_pin is None: raise RuntimeError("Unable to find preop.pin in %s. Is your CA already configured?" % filename) return preop_pin def import_pkcs12(input_file, input_passwd, cert_database, cert_passwd): ipautil.run(["/usr/bin/pk12util", "-d", cert_database, "-i", input_file, "-k", cert_passwd, "-w", input_passwd]) def get_value(s): """ Parse out a name/value pair from a Javascript variable. """ try: expr = s.split('=',1) value = expr[1] value = value.replace('\"', '') value = value.replace(';','') value = value.replace('\\n','\n') value = value.replace('\\r','\r') return value except IndexError: return None def find_substring(data, value): """ Scan through a list looking for a string that starts with value. """ for d in data: if d.startswith(value): return get_value(d) def get_defList(data): """ Return a dictionary of defList name/value pairs. A certificate signing request is specified as a series of these. """ varname = None value = None skip = False defdict = {} for d in data: if d.startswith("defList = new Object"): varname = None value = None skip = False if d.startswith("defList.defId"): varname = get_value(d) if d.startswith("defList.defVal"): value = get_value(d) if skip: varname = None value = None skip = False if d.startswith("defList.defConstraint"): ctype = get_value(d) if ctype == "readonly": skip = True if varname and value: defdict[varname] = value varname = None value = None return defdict def get_outputList(data): """ Return a dictionary of outputList name/value pairs. The output from issuing a certificate is a series of these. """ varname = None value = None outputdict = {} for d in data: if d.startswith("outputList = new"): varname = None value = None if d.startswith("outputList.outputId"): varname = get_value(d) if d.startswith("outputList.outputVal"): value = get_value(d) if varname and value: outputdict[varname] = value varname = None value = None return outputdict def get_crl_files(path=None): """ Traverse dogtag's CRL files in default CRL publish directory or in chosen target directory. @param path Custom target directory """ if path is None: path = dogtag.configured_constants().CRL_PUBLISH_PATH files = os.listdir(path) for f in files: if f == "MasterCRL.bin": yield os.path.join(path, f) elif f.endswith(".der"): yield os.path.join(path, f) def is_step_one_done(): '''Read CS.cfg and determine if step one of an external CA install is done ''' path = dogtag.install_constants.CS_CFG_PATH if not os.path.exists(path): return False test = installutils.get_directive(path, 'preop.ca.type', '=') if test == "otherca": return True return False class CADSInstance(service.Service): """Certificate Authority DS instance The CA DS was used with Dogtag 9. Only upgraded installations still use it. Thus this class only does uninstallation. """ def __init__(self, host_name=None, realm_name=None, domain_name=None, dm_password=None, dogtag_constants=None): service.Service.__init__(self, "pkids", service_desc="directory server for the CA", dm_password=dm_password, ldapi=False, autobind=service.DISABLED) self.serverid = "PKI-IPA" self.realm = realm_name self.sub_dict = None self.domain = domain_name self.fqdn = host_name self.dercert = None self.pkcs12_info = None self.ds_port = None self.master_host = None self.nickname = 'Server-Cert' self.subject_base = None def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring CA directory server") enabled = self.restore_state("enabled") serverid = self.restore_state("serverid") # Just eat this state if it exists running = self.restore_state("running") if not enabled is None and not enabled: ipaservices.knownservices.dirsrv.disable() if not serverid is None: # drop the trailing / off the config_dirname so the directory # will match what is in certmonger dirname = dsinstance.config_dirname(serverid)[:-1] dsdb = certs.CertDB(self.realm, nssdir=dirname) dsdb.untrack_server_cert("Server-Cert") dsinstance.erase_ds_instance_data(serverid) user_exists = self.restore_state("user_exists") # At one time we removed this user on uninstall. That can potentially # orphan files, or worse, if another useradd runs in the intermim, # cause files to have a new owner. def stop_tracking_certificates(dogtag_constants): """Stop tracking our certificates. Called on uninstall. """ cmonger = ipaservices.knownservices.certmonger ipaservices.knownservices.messagebus.start() cmonger.start() for nickname in ['Server-Cert cert-pki-ca', 'auditSigningCert cert-pki-ca', 'ocspSigningCert cert-pki-ca', 'subsystemCert cert-pki-ca']: try: certmonger.stop_tracking( dogtag_constants.ALIAS_DIR, nickname=nickname) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to stop tracking certificate: %s" % str(e)) try: certmonger.stop_tracking('/etc/httpd/alias', nickname='ipaCert') except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to stop tracking certificate: %s" % str(e)) cmonger.stop() class CAInstance(service.Service): """ When using a dogtag CA the DS database contains just the server cert for DS. The mod_nss database will contain the RA agent cert that will be used to do authenticated requests against dogtag. This is done because we use python-nss and will inherit the opened NSS database in mod_python. In nsslib.py we do an nssinit but this will return success if the database is already initialized. It doesn't care if the database is different or not. external is a state machine: 0 = not an externally signed CA 1 = generating CSR to be signed 2 = have signed cert, continue installation """ def __init__(self, realm, ra_db, dogtag_constants=None): if dogtag_constants is None: dogtag_constants = dogtag.configured_constants() service.Service.__init__(self, '%sd' % dogtag_constants.PKI_INSTANCE_NAME, service_desc="certificate server" ) self.dogtag_constants = dogtag_constants self.realm = realm self.dm_password = None self.admin_password = None self.fqdn = None self.domain = None self.pkcs12_info = None self.clone = False # for external CAs self.external = 0 self.csr_file = None self.cert_file = None self.cert_chain_file = None self.create_ra_agent_db = True # The same database is used for mod_nss because the NSS context # will already have been initialized by Apache by the time # mod_python wants to do things. self.canickname = get_ca_nickname(realm) self.basedn = DN(('o', 'ipaca')) self.ca_agent_db = tempfile.mkdtemp(prefix = "tmp-") self.ra_agent_db = ra_db self.ra_agent_pwd = self.ra_agent_db + "/pwdfile.txt" self.ds_port = DEFAULT_DSPORT self.security_domain_name = "IPA" self.server_root = dogtag_constants.SERVER_ROOT self.ra_cert = None self.requestId = None def __del__(self): shutil.rmtree(self.ca_agent_db, ignore_errors=True) def is_installed(self): """ Installing with an external CA is a two-step process. This is used to determine if the first step has been done. Returns True/False """ return os.path.exists(os.path.join( self.server_root, self.dogtag_constants.PKI_INSTANCE_NAME)) def configure_instance(self, host_name, domain, dm_password, admin_password, ds_port=DEFAULT_DSPORT, pkcs12_info=None, master_host=None, csr_file=None, cert_file=None, cert_chain_file=None, master_replication_port=None, subject_base=None): """Create a CA instance. For Dogtag 9, this may involve creating the pki-ca instance. To create a clone, pass in pkcs12_info. Creating a CA with an external signer is a 2-step process. In step 1 we generate a CSR. In step 2 we are given the cert and chain and actually proceed to create the CA. For step 1 set csr_file. For step 2 set cert_file and cert_chain_file. """ self.fqdn = host_name self.domain = domain self.dm_password = dm_password self.admin_password = admin_password self.ds_port = ds_port self.pkcs12_info = pkcs12_info if self.pkcs12_info is not None: self.clone = True self.master_host = master_host self.master_replication_port = master_replication_port if subject_base is None: self.subject_base = DN(('O', self.realm)) else: self.subject_base = subject_base # Determine if we are installing as an externally-signed CA and # what stage we're in. if csr_file is not None: self.csr_file=csr_file self.external=1 elif cert_file is not None: self.cert_file=cert_file self.cert_chain_file=cert_chain_file self.external=2 self.step("creating certificate server user", self.__create_ca_user) if self.dogtag_constants.DOGTAG_VERSION >= 10: self.step("configuring certificate server instance", self.__spawn_instance) else: if not ipautil.dir_exists("/var/lib/pki-ca"): self.step("creating pki-ca instance", self.create_instance) self.step("configuring certificate server instance", self.__configure_instance) self.step("stopping certificate server instance to update CS.cfg", self.__stop) self.step("disabling nonces", self.__disable_nonce) self.step("set up CRL publishing", self.__enable_crl_publish) self.step("starting certificate server instance", self.__start) # Step 1 of external is getting a CSR so we don't need to do these # steps until we get a cert back from the external CA. if self.external != 1: if self.dogtag_constants.DOGTAG_VERSION < 10 and not self.clone: self.step("creating CA agent PKCS#12 file in /root", self.__create_ca_agent_pkcs12) if self.create_ra_agent_db: self.step("creating RA agent certificate database", self.__create_ra_agent_db) self.step("importing CA chain to RA certificate database", self.__import_ca_chain) self.step("fixing RA database permissions", self.fix_ra_perms) self.step("setting up signing cert profile", self.__setup_sign_profile) self.step("set certificate subject base", self.__set_subject_in_config) self.step("enabling Subject Key Identifier", self.enable_subject_key_identifier) self.step("enabling CRL and OCSP extensions for certificates", self.__set_crl_ocsp_extensions) self.step("setting audit signing renewal to 2 years", self.set_audit_renewal) self.step("configuring certificate server to start on boot", self.__enable) if not self.clone: self.step("restarting certificate server", self.__restart_instance) self.step("requesting RA certificate from CA", self.__request_ra_certificate) self.step("issuing RA agent certificate", self.__issue_ra_cert) self.step("adding RA agent as a trusted user", self.__configure_ra) self.step("configure certificate renewals", self.configure_renewal) else: self.step("configure certmonger for renewals", self.configure_certmonger_renewal) self.step("configure clone certificate renewals", self.configure_clone_renewal) self.step("configure Server-Cert certificate renewal", self.track_servercert) self.step("Configure HTTP to proxy connections", self.__http_proxy) self.start_creation(runtime=210) def __stop(self): self.stop() def __start(self): self.start() def __spawn_instance(self): """ Create and configure a new CA instance using pkispawn. pkispawn requires a configuration file with IPA-specific parameters. """ # Create an empty and secured file (cfg_fd, cfg_file) = tempfile.mkstemp() os.close(cfg_fd) pent = pwd.getpwnam(PKI_USER) os.chown(cfg_file, pent.pw_uid, pent.pw_gid) # Create CA configuration config = ConfigParser.ConfigParser() config.optionxform = str config.add_section("CA") # Server config.set("CA", "pki_security_domain_name", self.security_domain_name) config.set("CA", "pki_enable_proxy", "True") config.set("CA", "pki_restart_configured_instance", "False") config.set("CA", "pki_backup_keys", "True") config.set("CA", "pki_backup_password", self.admin_password) # Client security database config.set("CA", "pki_client_database_dir", self.ca_agent_db) config.set("CA", "pki_client_database_password", self.admin_password) config.set("CA", "pki_client_database_purge", "False") config.set("CA", "pki_client_pkcs12_password", self.admin_password) # Administrator config.set("CA", "pki_admin_name", "admin") config.set("CA", "pki_admin_uid", "admin") config.set("CA", "pki_admin_email", "root@localhost") config.set("CA", "pki_admin_password", self.admin_password) config.set("CA", "pki_admin_nickname", "ipa-ca-agent") config.set("CA", "pki_admin_subject_dn", str(DN(('cn', 'ipa-ca-agent'), self.subject_base))) config.set("CA", "pki_client_admin_cert_p12", "/root/ca-agent.p12") # Directory server config.set("CA", "pki_ds_ldap_port", str(self.ds_port)) config.set("CA", "pki_ds_password", self.dm_password) config.set("CA", "pki_ds_base_dn", self.basedn) config.set("CA", "pki_ds_database", "ipaca") # Certificate subject DN's config.set("CA", "pki_subsystem_subject_dn", str(DN(('cn', 'CA Subsystem'), self.subject_base))) config.set("CA", "pki_ocsp_signing_subject_dn", str(DN(('cn', 'OCSP Subsystem'), self.subject_base))) config.set("CA", "pki_ssl_server_subject_dn", str(DN(('cn', self.fqdn), self.subject_base))) config.set("CA", "pki_audit_signing_subject_dn", str(DN(('cn', 'CA Audit'), self.subject_base))) config.set("CA", "pki_ca_signing_subject_dn", str(DN(('cn', 'Certificate Authority'), self.subject_base))) # Certificate nicknames config.set("CA", "pki_subsystem_nickname", "subsystemCert cert-pki-ca") config.set("CA", "pki_ocsp_signing_nickname", "ocspSigningCert cert-pki-ca") config.set("CA", "pki_ssl_server_nickname", "Server-Cert cert-pki-ca") config.set("CA", "pki_audit_signing_nickname", "auditSigningCert cert-pki-ca") config.set("CA", "pki_ca_signing_nickname", "caSigningCert cert-pki-ca") if (self.clone): cafile = self.pkcs12_info[0] shutil.copy(cafile, "/tmp/ca.p12") pent = pwd.getpwnam(PKI_USER) os.chown("/tmp/ca.p12", pent.pw_uid, pent.pw_gid) # Security domain registration config.set("CA", "pki_security_domain_hostname", self.master_host) config.set("CA", "pki_security_domain_https_port", "443") config.set("CA", "pki_security_domain_user", "admin") config.set("CA", "pki_security_domain_password", self.admin_password) # Clone config.set("CA", "pki_clone", "True") config.set("CA", "pki_clone_pkcs12_path", "/tmp/ca.p12") config.set("CA", "pki_clone_pkcs12_password", self.dm_password) config.set("CA", "pki_clone_replication_security", "TLS") config.set("CA", "pki_clone_replication_master_port", str(self.master_replication_port)) config.set("CA", "pki_clone_replication_clone_port", dogtag.install_constants.DS_PORT) config.set("CA", "pki_clone_replicate_schema", "False") config.set("CA", "pki_clone_uri", "https://%s" % ipautil.format_netloc(self.master_host, 443)) # External CA if self.external == 1: config.set("CA", "pki_external", "True") config.set("CA", "pki_external_csr_path", self.csr_file) elif self.external == 2: config.set("CA", "pki_external", "True") config.set("CA", "pki_external_ca_cert_path", self.cert_file) config.set("CA", "pki_external_ca_cert_chain_path", self.cert_chain_file) config.set("CA", "pki_external_step_two", "True") # Generate configuration file with open(cfg_file, "wb") as f: config.write(f) # Define the things we don't want logged nolog = (self.admin_password, self.dm_password,) args = ["/usr/sbin/pkispawn", "-s", "CA", "-f", cfg_file ] with open(cfg_file) as f: root_logger.debug( 'Contents of pkispawn configuration file (%s):\n%s' % (cfg_file, ipautil.nolog_replace(f.read(), nolog))) try: ipautil.run(args, nolog=nolog) except ipautil.CalledProcessError, e: root_logger.critical("failed to configure ca instance %s" % e) raise RuntimeError('Configuration of CA failed') finally: os.remove(cfg_file) if self.external == 1: print "The next step is to get %s signed by your CA and re-run ipa-server-install as:" % self.csr_file print "ipa-server-install --external_cert_file=/path/to/signed_certificate --external_ca_file=/path/to/external_ca_certificate" sys.exit(0) else: shutil.move("/var/lib/pki/pki-tomcat/alias/ca_backup_keys.p12", \ "/root/cacert.p12") root_logger.debug("completed creating ca instance") def create_instance(self): """ If for some reason the instance doesn't exist, create a new one." """ # Only used for Dogtag 9 args = ['/usr/bin/pkicreate', '-pki_instance_root', '/var/lib', '-pki_instance_name', self.dogtag_constants.PKI_INSTANCE_NAME, '-subsystem_type', 'ca', '-agent_secure_port', str(self.dogtag_constants.AGENT_SECURE_PORT), '-ee_secure_port', str(self.dogtag_constants.EE_SECURE_PORT), '-admin_secure_port', str(self.dogtag_constants.ADMIN_SECURE_PORT), '-ee_secure_client_auth_port', str(self.dogtag_constants.EE_CLIENT_AUTH_PORT), '-unsecure_port', str(self.dogtag_constants.UNSECURE_PORT), '-tomcat_server_port', str(self.dogtag_constants.TOMCAT_SERVER_PORT), '-redirect', 'conf=/etc/pki-ca', '-redirect', 'logs=/var/log/pki-ca', '-enable_proxy' ] ipautil.run(args, env={'PKI_HOSTNAME':self.fqdn}) def __enable(self): self.backup_state("enabled", self.is_enabled()) # 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 # We need to install DS before we can actually ldap_enable a service. # so actual enablement is delayed. def __create_ca_user(self): try: pwd.getpwnam(PKI_USER) root_logger.debug("ca user %s exists" % PKI_USER) except KeyError: root_logger.debug("adding ca user %s" % PKI_USER) args = ["/usr/sbin/useradd", "-c", "CA System User", "-d", "/var/lib", "-s", "/sbin/nologin", "-M", "-r", PKI_USER] try: ipautil.run(args) root_logger.debug("done adding user") except ipautil.CalledProcessError, e: root_logger.critical("failed to add user %s" % e) def __configure_instance(self): # Only used for Dogtag 9 preop_pin = get_preop_pin( self.server_root, self.dogtag_constants.PKI_INSTANCE_NAME) try: args = ["/usr/bin/perl", "/usr/bin/pkisilent", "ConfigureCA", "-cs_hostname", self.fqdn, "-cs_port", str(self.dogtag_constants.ADMIN_SECURE_PORT), "-client_certdb_dir", self.ca_agent_db, "-client_certdb_pwd", self.admin_password, "-preop_pin" , preop_pin, "-domain_name", self.security_domain_name, "-admin_user", "admin", "-admin_email", "root@localhost", "-admin_password", self.admin_password, "-agent_name", "ipa-ca-agent", "-agent_key_size", "2048", "-agent_key_type", "rsa", "-agent_cert_subject", str(DN(('CN', 'ipa-ca-agent'), self.subject_base)), "-ldap_host", self.fqdn, "-ldap_port", str(self.ds_port), "-bind_dn", "cn=Directory Manager", "-bind_password", self.dm_password, "-base_dn", str(self.basedn), "-db_name", "ipaca", "-key_size", "2048", "-key_type", "rsa", "-key_algorithm", "SHA256withRSA", "-save_p12", "true", "-backup_pwd", self.admin_password, "-subsystem_name", self.service_name, "-token_name", "internal", "-ca_subsystem_cert_subject_name", str(DN(('CN', 'CA Subsystem'), self.subject_base)), "-ca_subsystem_cert_subject_name", str(DN(('CN', 'CA Subsystem'), self.subject_base)), "-ca_ocsp_cert_subject_name", str(DN(('CN', 'OCSP Subsystem'), self.subject_base)), "-ca_server_cert_subject_name", str(DN(('CN', self.fqdn), self.subject_base)), "-ca_audit_signing_cert_subject_name", str(DN(('CN', 'CA Audit'), self.subject_base)), "-ca_sign_cert_subject_name", str(DN(('CN', 'Certificate Authority'), self.subject_base)) ] if self.external == 1: args.append("-external") args.append("true") args.append("-ext_csr_file") args.append(self.csr_file) elif self.external == 2: args.append("-external") args.append("true") args.append("-ext_ca_cert_file") args.append(self.cert_file) args.append("-ext_ca_cert_chain_file") args.append(self.cert_chain_file) else: args.append("-external") args.append("false") if (self.clone): """sd = security domain --> all CS systems get registered to a security domain. This is set to the hostname and port of the master CA. """ # The install wizard expects the file to be here. cafile = self.pkcs12_info[0] shutil.copy(cafile, "/var/lib/pki-ca/alias/ca.p12") pent = pwd.getpwnam(PKI_USER) os.chown("/var/lib/pki-ca/alias/ca.p12", pent.pw_uid, pent.pw_gid ) args.append("-clone") args.append("true") args.append("-clone_p12_file") args.append("ca.p12") args.append("-clone_p12_password") args.append(self.dm_password) args.append("-sd_hostname") args.append(self.master_host) args.append("-sd_admin_port") args.append("443") args.append("-sd_admin_name") args.append("admin") args.append("-sd_admin_password") args.append(self.admin_password) args.append("-clone_master_port") args.append(str(self.master_replication_port)) args.append("-clone_start_tls") args.append("true") args.append("-clone_uri") args.append("https://%s" % ipautil.format_netloc(self.master_host, 443)) else: args.append("-clone") args.append("false") # Define the things we don't want logged nolog = (self.admin_password, self.dm_password,) ipautil.run(args, env={'PKI_HOSTNAME':self.fqdn}, nolog=nolog) except ipautil.CalledProcessError, e: root_logger.critical("failed to configure ca instance %s" % e) raise RuntimeError('Configuration of CA failed') if self.external == 1: print "The next step is to get %s signed by your CA and re-run ipa-server-install as:" % self.csr_file print "ipa-server-install --external_cert_file=/path/to/signed_certificate --external_ca_file=/path/to/external_ca_certificate" sys.exit(0) # pkisilent makes a copy of the CA PKCS#12 file for us but gives # it a lousy name. if ipautil.file_exists("/root/tmp-ca.p12"): shutil.move("/root/tmp-ca.p12", "/root/cacert.p12") root_logger.debug("completed creating ca instance") def __restart_instance(self): try: self.restart(self.dogtag_constants.PKI_INSTANCE_NAME) except Exception: # TODO: roll back here? root_logger.debug(traceback.format_exc()) root_logger.critical("Failed to restart the certificate server. See the installation log for details.") def __disable_nonce(self): # Turn off Nonces update_result = installutils.update_file( self.dogtag_constants.CS_CFG_PATH, 'ca.enableNonces=true', 'ca.enableNonces=false') if update_result != 0: raise RuntimeError("Disabling nonces failed") pent = pwd.getpwnam(PKI_USER) os.chown(self.dogtag_constants.CS_CFG_PATH, pent.pw_uid, pent.pw_gid) def __issue_ra_cert(self): # The CA certificate is in the agent DB but isn't trusted (admin_fd, admin_name) = tempfile.mkstemp() os.write(admin_fd, self.admin_password) os.close(admin_fd) # Look thru the cert chain to get all the certs we need to add # trust for p = subprocess.Popen(["/usr/bin/certutil", "-d", self.ca_agent_db, "-O", "-n", "ipa-ca-agent"], stdout=subprocess.PIPE) chain = p.stdout.read() chain = chain.split("\n") root_nickname=[] for i in xrange(len(chain)): m = re.match('\ *"(.*)" \[.*', chain[i]) if m: nick = m.groups(0)[0] if nick != "ipa-ca-agent" and nick[:7] != "Builtin": root_nickname.append(m.groups()[0]) try: for nick in root_nickname: self.__run_certutil( ['-M', '-t', 'CT,C,C', '-n', nick], database=self.ca_agent_db, pwd_file=self.admin_password) finally: os.remove(admin_name) # Retrieve the certificate request so we can get the values needed # to issue a certificate. Use sslget here because this is a # temporary database and nsslib doesn't currently support gracefully # opening and closing an NSS database. This would leave the installer # process stuck using this database during the entire cycle. We need # to use the final RA agent database when issuing certs for DS and # mod_nss. args = [ '/usr/bin/sslget', '-v', '-n', 'ipa-ca-agent', '-p', self.admin_password, '-d', self.ca_agent_db, '-r', '/ca/agent/ca/profileReview?requestId=%s' % self.requestId, '%s' % ipautil.format_netloc( self.fqdn, self.dogtag_constants.AGENT_SECURE_PORT), ] (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) data = stdout.split(self.dogtag_constants.RACERT_LINE_SEP) params = get_defList(data) params['requestId'] = find_substring(data, "requestId") params['op'] = 'approve' params['submit'] = 'submit' params['requestNotes'] = '' params = urllib.urlencode(params) # Now issue the RA certificate. args = [ '/usr/bin/sslget', '-v', '-n', 'ipa-ca-agent', '-p', self.admin_password, '-d', self.ca_agent_db, '-e', params, '-r', '/ca/agent/ca/profileProcess', '%s' % ipautil.format_netloc( self.fqdn, self.dogtag_constants.AGENT_SECURE_PORT), ] (stdout, stderr, returncode) = ipautil.run(args, nolog=(self.admin_password,)) data = stdout.split(self.dogtag_constants.RACERT_LINE_SEP) outputList = get_outputList(data) self.ra_cert = outputList['b64_cert'] # Strip certificate headers and convert it to proper line ending self.ra_cert = x509.strip_header(self.ra_cert) self.ra_cert = "\n".join(line.strip() for line in self.ra_cert.splitlines() if line.strip()) # Add the new RA cert to the database in /etc/httpd/alias (agent_fd, agent_name) = tempfile.mkstemp() os.write(agent_fd, self.ra_cert) os.close(agent_fd) try: self.__run_certutil( ['-A', '-t', 'u,u,u', '-n', 'ipaCert', '-a', '-i', agent_name] ) finally: os.remove(agent_name) def import_ra_cert(self, rafile): """ Cloned RAs will use the same RA agent cert as the master so we need to import from a PKCS#12 file. Used when setting up replication """ # Add the new RA cert to the database in /etc/httpd/alias (agent_fd, agent_name) = tempfile.mkstemp() os.write(agent_fd, self.dm_password) os.close(agent_fd) try: import_pkcs12(rafile, agent_name, self.ra_agent_db, self.ra_agent_pwd) finally: os.remove(agent_name) self.configure_agent_renewal() def configure_agent_renewal(self): """ Set up the agent cert for renewal. No need to make any changes to the dogtag LDAP here since the originator will do that so we only call restart_httpd after retrieving the cert. On upgrades this needs to be called from ipa-upgradeconfig. """ try: certmonger.dogtag_start_tracking('dogtag-ipa-retrieve-agent-submit', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', None, 'restart_httpd') except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to start tracking certificate: %s" % str(e)) def __configure_ra(self): # Create an RA user in the CA LDAP server and add that user to # the appropriate groups so it can issue certificates without # manual intervention. conn = ipaldap.IPAdmin(self.fqdn, self.ds_port) conn.do_simple_bind(DN(('cn', 'Directory Manager')), self.dm_password) decoded = base64.b64decode(self.ra_cert) entry_dn = DN(('uid', "ipara"), ('ou', 'People'), self.basedn) entry = [ ('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'cmsuser']), ('uid', "ipara"), ('sn', "ipara"), ('cn', "ipara"), ('usertype', "agentType"), ('userstate', "1"), ('userCertificate', decoded), ('description', '2;%s;%s;%s' % \ (str(self.requestId), DN(('CN', 'Certificate Authority'), self.subject_base), DN(('CN', 'IPA RA'), self.subject_base))), ] conn.add_entry(entry_dn, entry) dn = DN(('cn', 'Certificate Manager Agents'), ('ou', 'groups'), self.basedn) modlist = [(0, 'uniqueMember', '%s' % entry_dn)] conn.modify_s(dn, modlist) dn = DN(('cn', 'Registration Manager Agents'), ('ou', 'groups'), self.basedn) modlist = [(0, 'uniqueMember', '%s' % entry_dn)] conn.modify_s(dn, modlist) conn.unbind() def __run_certutil(self, args, database=None, pwd_file=None,stdin=None): if not database: database = self.ra_agent_db if not pwd_file: pwd_file = self.ra_agent_pwd new_args = ["/usr/bin/certutil", "-d", database, "-f", pwd_file] new_args = new_args + args return ipautil.run(new_args, stdin, nolog=(pwd_file,)) def __create_ra_agent_db(self): if ipautil.file_exists(self.ra_agent_db + "/cert8.db"): ipautil.backup_file(self.ra_agent_db + "/cert8.db") ipautil.backup_file(self.ra_agent_db + "/key3.db") ipautil.backup_file(self.ra_agent_db + "/secmod.db") ipautil.backup_file(self.ra_agent_db + "/pwdfile.txt") if not ipautil.dir_exists(self.ra_agent_db): os.mkdir(self.ra_agent_db) # Create the password file for this db hex_str = binascii.hexlify(os.urandom(10)) f = os.open(self.ra_agent_pwd, os.O_CREAT | os.O_RDWR) os.write(f, hex_str) os.close(f) os.chmod(self.ra_agent_pwd, stat.S_IRUSR) (stdout, stderr, returncode) = self.__run_certutil(["-N"]) def __get_ca_chain(self): try: return dogtag.get_ca_certchain(ca_host=self.fqdn, dogtag_constants=self.dogtag_constants) except Exception, e: raise RuntimeError("Unable to retrieve CA chain: %s" % str(e)) def __create_ca_agent_pkcs12(self): # Only used for Dogtag 9 (pwd_fd, pwd_name) = tempfile.mkstemp() os.write(pwd_fd, self.admin_password) os.close(pwd_fd) try: ipautil.run(["/usr/bin/pk12util", "-n", "ipa-ca-agent", "-o", "/root/ca-agent.p12", "-d", self.ca_agent_db, "-k", pwd_name, "-w", pwd_name]) finally: os.remove(pwd_name) def __import_ca_chain(self): chain = self.__get_ca_chain() # If this chain contains multiple certs then certutil will only import # the first one. So we have to pull them all out and import them # separately. Unfortunately no NSS tool can do this so we have to # use openssl. # Convert to DER because the chain comes back as one long string which # makes openssl throw up. data = base64.b64decode(chain) (certlist, stderr, returncode) = ipautil.run(["/usr/bin/openssl", "pkcs7", "-inform", "DER", "-print_certs", ], stdin=data) # Ok, now we have all the certificates in certs, walk thru it # and pull out each certificate and add it to our database st = 1 en = 0 subid = 0 ca_dn = DN(('CN','Certificate Authority'), self.subject_base) while st > 0: st = certlist.find('-----BEGIN', en) en = certlist.find('-----END', en+1) if st > 0: try: (chain_fd, chain_name) = tempfile.mkstemp() os.write(chain_fd, certlist[st:en+25]) os.close(chain_fd) (rdn, subject_dn) = certs.get_cert_nickname(certlist[st:en+25]) if subject_dn == ca_dn: nick = get_ca_nickname(self.realm) else: nick = str(subject_dn) self.__run_certutil( ['-A', '-t', 'CT,C,C', '-n', nick, '-a', '-i', chain_name] ) finally: os.remove(chain_name) subid = subid + 1 def __request_ra_certificate(self): # Create a noise file for generating our private key noise = array.array('B', os.urandom(128)) (noise_fd, noise_name) = tempfile.mkstemp() os.write(noise_fd, noise) os.close(noise_fd) # Generate our CSR. The result gets put into stdout try: (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", str(DN(('CN', 'IPA RA'), self.subject_base)), "-z", noise_name, "-a"]) finally: os.remove(noise_name) csr = pkcs10.strip_header(stdout) # Send the request to the CA conn = httplib.HTTPConnection( self.fqdn, self.dogtag_constants.UNSECURE_PORT) params = urllib.urlencode({'profileId': 'caServerCert', 'cert_request_type': 'pkcs10', 'requestor_name': 'IPA Installer', 'cert_request': csr, 'xmlOutput': 'true'}) headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"} conn.request("POST", "/ca/ee/ca/profileSubmit", params, headers) res = conn.getresponse() if res.status == 200: data = res.read() conn.close() doc = xml.dom.minidom.parseString(data) item_node = doc.getElementsByTagName("RequestId") self.requestId = item_node[0].childNodes[0].data doc.unlink() self.requestId = self.requestId.strip() if self.requestId is None: raise RuntimeError("Unable to determine RA certificate requestId") else: conn.close() raise RuntimeError("Unable to submit RA cert request") def fix_ra_perms(self): os.chmod(self.ra_agent_db + "/cert8.db", 0640) os.chmod(self.ra_agent_db + "/key3.db", 0640) os.chmod(self.ra_agent_db + "/secmod.db", 0640) pent = pwd.getpwnam("apache") os.chown(self.ra_agent_db + "/cert8.db", 0, pent.pw_gid ) os.chown(self.ra_agent_db + "/key3.db", 0, pent.pw_gid ) os.chown(self.ra_agent_db + "/secmod.db", 0, pent.pw_gid ) os.chown(self.ra_agent_pwd, pent.pw_uid, pent.pw_gid) def __setup_sign_profile(self): # Tell the profile to automatically issue certs for RAs installutils.set_directive(self.dogtag_constants.SIGN_PROFILE, 'auth.instance_id', 'raCertAuth', quotes=False, separator='=') def prepare_crl_publish_dir(self): """ Prepare target directory for CRL publishing Returns a path to the CRL publishing directory """ publishdir = self.dogtag_constants.CRL_PUBLISH_PATH if not os.path.exists(publishdir): os.mkdir(publishdir) os.chmod(publishdir, 0775) pent = pwd.getpwnam(PKI_USER) os.chown(publishdir, 0, pent.pw_gid) ipaservices.restore_context(publishdir) return publishdir def __set_crl_ocsp_extensions(self): self.set_crl_ocsp_extensions(self.domain, self.fqdn) def set_crl_ocsp_extensions(self, domain, fqdn): """ Configure CRL and OCSP extensions in default IPA certificate profile if not done already. """ changed = False # OCSP extension ocsp_url = 'http://%s.%s/ca/ocsp' % (IPA_CA_RECORD, ipautil.format_netloc(domain)) ocsp_location_0 = installutils.get_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.5.default.params.authInfoAccessADLocation_0', separator='=') if ocsp_location_0 != ocsp_url: # Set the first OCSP URI installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.5.default.params.authInfoAccessADLocation_0', ocsp_url, quotes=False, separator='=') changed = True ocsp_profile_count = installutils.get_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.5.default.params.authInfoAccessNumADs', separator='=') if ocsp_profile_count != '1': installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.5.default.params.authInfoAccessNumADs', '1', quotes=False, separator='=') changed = True # CRL extension crl_url = 'http://%s.%s/ipa/crl/MasterCRL.bin'% (IPA_CA_RECORD, ipautil.format_netloc(domain)) crl_point_0 = installutils.get_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsPointName_0', separator='=') if crl_point_0 != crl_url: installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsIssuerName_0', 'CN=Certificate Authority,o=ipaca', quotes=False, separator='=') installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsIssuerType_0', 'DirectoryName', quotes=False, separator='=') installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsPointName_0', crl_url, quotes=False, separator='=') changed = True crl_profile_count = installutils.get_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsNum', separator='=') if crl_profile_count != '1': installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.9.default.params.crlDistPointsNum', '1', quotes=False, separator='=') changed = True # CRL extension is not enabled by default setlist = installutils.get_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.list', separator='=') new_set_list = None if setlist == '1,2,3,4,5,6,7,8': new_set_list = '1,2,3,4,5,6,7,8,9' elif setlist == '1,2,3,4,5,6,7,8,10': new_set_list = '1,2,3,4,5,6,7,8,9,10' if new_set_list: installutils.set_directive(self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.list', new_set_list, quotes=False, separator='=') changed = True return changed def __enable_crl_publish(self): """ Enable file-based CRL publishing and disable LDAP publishing. https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Certificate_System/8.0/html/Admin_Guide/Setting_up_Publishing.html """ caconfig = self.dogtag_constants.CS_CFG_PATH publishdir = self.prepare_crl_publish_dir() # Enable file publishing, disable LDAP installutils.set_directive(caconfig, 'ca.publish.enable', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.ldappublish.enable', 'false', quotes=False, separator='=') # Create the file publisher, der only, not b64 installutils.set_directive(caconfig, 'ca.publish.publisher.impl.FileBasedPublisher.class','com.netscape.cms.publish.publishers.FileBasedPublisher', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.crlLinkExt', 'bin', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', publishdir, quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.latestCrlLink', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.pluginName', 'FileBasedPublisher', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.timeStamp', 'LocalTime', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.zipCRLs', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.zipLevel', '9', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.b64', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.publisher.instance.FileBaseCRLPublisher.Filename.der', 'true', quotes=False, separator='=') # The publishing rule installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.enable', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.mapper', 'NoMap', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.pluginName', 'Rule', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.predicate=', '', quotes=False, separator='') installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.publisher', 'FileBaseCRLPublisher', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.FileCrlRule.type', 'crl', quotes=False, separator='=') # Now disable LDAP publishing installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapCaCertRule.enable', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapCrlRule.enable', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapUserCertRule.enable', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.publish.rule.instance.LdapXCertRule.enable', 'false', quotes=False, separator='=') # If we are the initial master then we are the CRL generator, otherwise # we point to that master for CRLs. if not self.clone: # These next two are defaults, but I want to be explicit that the # initial master is the CRL generator. installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLCache', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLUpdates', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.listenToCloneModifications', 'true', quotes=False, separator='=') else: installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLCache', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.crl.MasterCRL.enableCRLUpdates', 'false', quotes=False, separator='=') installutils.set_directive(caconfig, 'ca.listenToCloneModifications', 'false', quotes=False, separator='=') def __set_subject_in_config(self): # dogtag ships with an IPA-specific profile that forces a subject # format. We need to update that template with our base subject if installutils.update_file(self.dogtag_constants.IPA_SERVICE_PROFILE, 'OU=pki-ipa, O=IPA', str(self.subject_base)): print "Updating subject_base in CA template failed" def enable_client_auth_to_db(self): """ Enable client auth connection to the internal db. """ caconfig = dogtag.install_constants.CS_CFG_PATH with stopped_service(self.dogtag_constants.SERVICE_NAME, instance_name=self.dogtag_constants.PKI_INSTANCE_NAME): # Enable file publishing, disable LDAP installutils.set_directive(caconfig, 'authz.instance.DirAclAuthz.ldap.ldapauth.authtype', 'SslClientAuth', quotes=False, separator='=') installutils.set_directive(caconfig, 'authz.instance.DirAclAuthz.ldap.ldapauth.bindDN', 'uid=pkidbuser,ou=people,o=ipa-ca', quotes=False, separator='=') installutils.set_directive(caconfig, 'authz.instance.DirAclAuthz.ldap.ldapauth.clientCertNickname', 'subsystemCert cert-pki-ca', quotes=False, separator='=') installutils.set_directive(caconfig, 'authz.instance.DirAclAuthz.ldap.ldapconn.port', str(dogtag.install_constants.DS_SECURE_PORT), quotes=False, separator='=') installutils.set_directive(caconfig, 'authz.instance.DirAclAuthz.ldap.ldapconn.secureConn', 'true', quotes=False, separator='=') installutils.set_directive(caconfig, 'internaldb.ldapauth.authtype', 'SslClientAuth', quotes=False, separator='=') installutils.set_directive(caconfig, 'internaldb.ldapauth.bindDN', 'uid=pkidbuser,ou=people,o=ipa-ca', quotes=False, separator='=') installutils.set_directive(caconfig, 'internaldb.ldapauth.clientCertNickname', 'subsystemCert cert-pki-ca', quotes=False, separator='=') installutils.set_directive(caconfig, 'internaldb.ldapconn.port', str(dogtag.install_constants.DS_SECURE_PORT), quotes=False, separator='=') installutils.set_directive(caconfig, 'internaldb.ldapconn.secureConn', 'true', quotes=False, separator='=') def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring CA") enabled = self.restore_state("enabled") if not enabled is None and not enabled: self.disable() try: if self.dogtag_constants.DOGTAG_VERSION >= 10: ipautil.run(["/usr/sbin/pkidestroy", "-i", self.dogtag_constants.PKI_INSTANCE_NAME, "-s", "CA"]) else: ipautil.run(["/usr/bin/pkiremove", "-pki_instance_root=/var/lib", "-pki_instance_name=%s" % self.dogtag_constants.PKI_INSTANCE_NAME, "--force"]) except ipautil.CalledProcessError, e: root_logger.critical("failed to uninstall CA instance %s" % e) # At one time we removed this user on uninstall. That can potentially # orphan files, or worse, if another useradd runs in the intermim, # cause files to have a new owner. user_exists = self.restore_state("user_exists") installutils.remove_file("/var/lib/certmonger/cas/ca_renewal") # remove CRL files root_logger.info("Remove old CRL files") for f in get_crl_files(): root_logger.debug("Remove %s", f) installutils.remove_file(f) # remove CRL directory root_logger.info("Remove CRL directory") if os.path.exists(self.dogtag_constants.CRL_PUBLISH_PATH): try: shutil.rmtree(self.dogtag_constants.CRL_PUBLISH_PATH) except OSError, e: root_logger.warning("Error while removing CRL publish " "directory: %s" % e) def publish_ca_cert(self, location): args = ["-L", "-n", self.canickname, "-a"] (cert, err, returncode) = self.__run_certutil(args) fd = open(location, "w+") fd.write(cert) fd.close() os.chmod(location, 0444) def __http_proxy(self): template_filename = ipautil.SHARE_DIR + "ipa-pki-proxy.conf" sub_dict = dict( DOGTAG_PORT=self.dogtag_constants.AJP_PORT, CLONE='' if self.clone else '#', FQDN=self.fqdn, ) template = ipautil.template_file(template_filename, sub_dict) with open(HTTPD_CONFD + "ipa-pki-proxy.conf", "w") as fd: fd.write(template) def __get_ca_pin(self): try: return certmonger.get_pin('internal', dogtag_constants=self.dogtag_constants) except IOError, e: raise RuntimeError( 'Unable to determine PIN for CA instance: %s' % str(e)) def track_servercert(self): """ Specifically do not tell certmonger to restart the CA. This will be done by the renewal script, renew_ca_cert once all the subsystem certificates are renewed. """ pin = self.__get_ca_pin() try: certmonger.dogtag_start_tracking( 'dogtag-ipa-renew-agent', 'Server-Cert cert-pki-ca', pin, None, self.dogtag_constants.ALIAS_DIR, None, None) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to start tracking certificate: %s" % str(e)) def configure_renewal(self): cmonger = ipaservices.knownservices.certmonger cmonger.enable() ipaservices.knownservices.messagebus.start() cmonger.start() pin = self.__get_ca_pin() # Server-Cert cert-pki-ca is renewed per-server for nickname in ['auditSigningCert cert-pki-ca', 'ocspSigningCert cert-pki-ca', 'subsystemCert cert-pki-ca']: try: certmonger.dogtag_start_tracking( 'dogtag-ipa-renew-agent', nickname, pin, None, self.dogtag_constants.ALIAS_DIR, 'stop_pkicad', 'renew_ca_cert "%s"' % nickname) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to start tracking certificate: %s" % str(e)) # Set up the agent cert for renewal try: certmonger.dogtag_start_tracking('dogtag-ipa-renew-agent', 'ipaCert', None, '/etc/httpd/alias/pwdfile.txt', '/etc/httpd/alias', None, 'renew_ra_cert') except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to start tracking certificate: %s" % str(e)) def configure_certmonger_renewal(self): """ Create a new CA type for certmonger that will retrieve updated certificates from the dogtag master server. """ target_fname = '/var/lib/certmonger/cas/ca_renewal' if ipautil.file_exists(target_fname): # This CA can be configured either during initial CA installation # if the replica is created with --setup-ca or when Apache is # being configured if not. return txt = ipautil.template_file(ipautil.SHARE_DIR + "ca_renewal", dict()) fd = open(target_fname, "w") fd.write(txt) fd.close() os.chmod(target_fname, 0600) ipaservices.restore_context(target_fname) cmonger = ipaservices.knownservices.certmonger cmonger.enable() ipaservices.knownservices.messagebus.start() cmonger.restart() def configure_clone_renewal(self): """ The actual renewal is done on the master. On the clone side we use a separate certmonger CA that polls LDAP to see if an updated certificate is available. If it is then it gets installed. """ pin = self.__get_ca_pin() # Server-Cert cert-pki-ca is renewed per-server for nickname in ['auditSigningCert cert-pki-ca', 'ocspSigningCert cert-pki-ca', 'subsystemCert cert-pki-ca']: try: certmonger.dogtag_start_tracking( 'dogtag-ipa-retrieve-agent-submit', nickname, pin, None, self.dogtag_constants.ALIAS_DIR, 'stop_pkicad', 'restart_pkicad "%s"' % nickname) except (ipautil.CalledProcessError, RuntimeError), e: root_logger.error( "certmonger failed to start tracking certificate: %s" % str(e)) # The agent renewal is configured in import_ra_cert which is called # after the HTTP instance is created. def enable_subject_key_identifier(self): """ See if Subject Key Identifier is set in the profile and if not, add it. """ setlist = installutils.get_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.list', separator='=') # this is the default setting from pki-ca/pki-tomcat. Don't touch it # if a user has manually modified it. if setlist == '1,2,3,4,5,6,7,8' or setlist == '1,2,3,4,5,6,7,8,9': setlist = setlist + ',10' installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.list', setlist, quotes=False, separator='=') installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.10.constraint.class_id', 'noConstraintImpl', quotes=False, separator='=') installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.10.constraint.name', 'No Constraint', quotes=False, separator='=') installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.10.default.class_id', 'subjectKeyIdentifierExtDefaultImpl', quotes=False, separator='=') installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.10.default.name', 'Subject Key Identifier Extension Default', quotes=False, separator='=') installutils.set_directive( self.dogtag_constants.IPA_SERVICE_PROFILE, 'policyset.serverCertSet.10.default.params.critical', 'false', quotes=False, separator='=') return True # No update was done return False def set_audit_renewal(self): """ The default renewal time for the audit signing certificate is six months rather than two years. Fix it. This is BZ 843979. """ # Check the default validity period of the audit signing cert # and set it to 2 years if it is 6 months. range = installutils.get_directive( '%s/caSignedLogCert.cfg' % self.dogtag_constants.SERVICE_PROFILE_DIR, 'policyset.caLogSigningSet.2.default.params.range', separator='=' ) root_logger.debug('caSignedLogCert.cfg profile validity range is %s' % range) if range == "180": installutils.set_directive( '%s/caSignedLogCert.cfg' % self.dogtag_constants.SERVICE_PROFILE_DIR, 'policyset.caLogSigningSet.2.default.params.range', '720', quotes=False, separator='=' ) installutils.set_directive( '%s/caSignedLogCert.cfg' % self.dogtag_constants.SERVICE_PROFILE_DIR, 'policyset.caLogSigningSet.2.constraint.params.range', '720', quotes=False, separator='=' ) root_logger.debug('updated caSignedLogCert.cfg profile validity range to 720') return True return False def is_master(self): """ There are some tasks that are only done on a single dogtag master. By default this is the first one installed. Use this to determine if that is the case. If users have changed their topology so the initial master is either gone or no longer performing certain duties then it is their responsibility to handle changes on upgrades. """ master = installutils.get_directive( self.dogtag_constants.CS_CFG_PATH, 'subsystem.select', '=') return master == 'New' def replica_ca_install_check(config, master_ds_port): if not config.setup_ca: return cafile = config.dir + "/cacert.p12" if not ipautil.file_exists(cafile): # Replica of old "self-signed" master - CA won't be installed return master_ds_port = int(master_ds_port) # Exit if we have an old-style (Dogtag 9) CA already installed ca = CAInstance(config.realm_name, certs.NSS_DIR, dogtag_constants=dogtag.Dogtag9Constants) if ca.is_installed(): root_logger.info('Dogtag 9 style CA instance found') sys.exit("A CA is already configured on this system.") if master_ds_port != dogtag.Dogtag9Constants.DS_PORT: root_logger.debug( 'Installing CA Replica from master with a merged database') return # Check if the master has the necessary schema in its CA instance ca_ldap_url = 'ldap://%s:%s' % (config.master_host_name, master_ds_port) objectclass = 'ipaObject' root_logger.debug('Checking if IPA schema is present in %s', ca_ldap_url) try: connection = ldap2.IPASimpleLDAPObject( ca_ldap_url, force_schema_updates=False) connection.start_tls_s() connection.simple_bind_s(DN(('cn', 'Directory Manager')), config.dirman_password) rschema = connection.schema result = rschema.get_obj(ldap.schema.models.ObjectClass, objectclass) except Exception: root_logger.critical( 'CA DS schema check failed. Make sure the PKI service on the ' 'remote master is operational.') raise if result: root_logger.debug('Check OK') else: root_logger.critical( 'The master CA directory server does not have necessary schema. ' 'Please copy the following script to all CA masters and run it ' 'on them: %s\n' 'If you are certain that this is a false positive, use ' '--skip-schema-check.', os.path.join(ipautil.SHARE_DIR, 'copy-schema-to-ca.py')) exit('IPA schema missing on master CA directory server') def install_replica_ca(config, master_ds_port, postinstall=False): """ Install a CA on a replica. There are two modes of doing this controlled: - While the replica is being installed - Post-replica installation config is a ReplicaConfig object Returns a tuple of the CA and CADS instances """ cafile = config.dir + "/cacert.p12" if not ipautil.file_exists(cafile): # Replica of old "self-signed" master - skip installing CA return None if not config.setup_ca: # We aren't configuring the CA in this step but we still need # a minimum amount of information on the CA for this IPA install. ca = CAInstance(config.realm_name, certs.NSS_DIR, dogtag_constants=dogtag.install_constants) ca.dm_password = config.dirman_password ca.subject_base = config.subject_base return ca ca = CAInstance(config.realm_name, certs.NSS_DIR, dogtag_constants=dogtag.install_constants) ca.dm_password = config.dirman_password ca.subject_base = config.subject_base if ca.is_installed(): sys.exit("A CA is already configured on this system.") pkcs12_info = None if ipautil.file_exists(config.dir + "/dogtagcert.p12"): pkcs12_info = (config.dir + "/dogtagcert.p12", config.dir + "/dirsrv_pin.txt") ca = CAInstance(config.realm_name, certs.NSS_DIR, dogtag_constants=dogtag.install_constants) if postinstall: # If installing this afterward the Apache NSS database already # exists, don't remove it. ca.create_ra_agent_db = False ca.configure_instance(config.host_name, config.domain_name, config.dirman_password, config.dirman_password, pkcs12_info=(cafile,), master_host=config.master_host_name, master_replication_port=master_ds_port, subject_base=config.subject_base) # Restart httpd since we changed it's config and added ipa-pki-proxy.conf # Without the restart, CA service status check would fail due to missing # proxy if postinstall: ipaservices.knownservices.httpd.restart() # The dogtag DS instance needs to be restarted after installation. # The procedure for this is: stop dogtag, stop DS, start DS, start # dogtag # # # The service_name trickery is due to the service naming we do # internally. In the case of the dogtag DS the name doesn't match the # unix service. service.print_msg("Restarting the directory and certificate servers") ca.stop(dogtag.install_constants.PKI_INSTANCE_NAME) ipaservices.knownservices.dirsrv.restart() ca.start(dogtag.install_constants.PKI_INSTANCE_NAME) return ca def update_cert_config(nickname, cert, dogtag_constants=None): """ When renewing a CA subsystem certificate the configuration file needs to get the new certificate as well. nickname is one of the known nicknames. cert is a DER-encoded certificate. """ if dogtag_constants is None: dogtag_constants = dogtag.configured_constants() # The cert directive to update per nickname directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert', 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert', 'caSigningCert cert-pki-ca': 'ca.signing.cert', 'subsystemCert cert-pki-ca': 'ca.subsystem.cert', 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'} with stopped_service(dogtag_constants.SERVICE_NAME, instance_name=dogtag_constants.PKI_INSTANCE_NAME): installutils.set_directive(dogtag.configured_constants().CS_CFG_PATH, directives[nickname], base64.b64encode(cert), quotes=False, separator='=') def update_people_entry(uid, dercert): """ Update the userCerticate for an entry in the dogtag ou=People. This is needed when a certificate is renewed. uid: uid of user to update dercert: An X509.3 certificate in DER format Logging is done via syslog Returns True or False """ dn = DN(('uid',uid),('ou','People'),('o','ipaca')) serial_number = x509.get_serial_number(dercert, datatype=x509.DER) subject = x509.get_subject(dercert, datatype=x509.DER) issuer = x509.get_issuer(dercert, datatype=x509.DER) attempts = 0 dogtag_uri='ldap://localhost:%d' % DEFAULT_DSPORT updated = False try: dm_password = certmonger.get_pin('internaldb') except IOError, e: syslog.syslog(syslog.LOG_ERR, 'Unable to determine PIN for CA instance: %s' % e) return False while attempts < 10: conn = None try: conn = ldap2.ldap2(shared_instance=False, ldap_uri=dogtag_uri) conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate']) entry_attrs['usercertificate'].append(dercert) entry_attrs['description'] = '2;%d;%s;%s' % (serial_number, issuer, subject) conn.update_entry(dn, entry_attrs) updated = True break except errors.NetworkError: syslog.syslog(syslog.LOG_ERR, 'Connection to %s failed, sleeping 30s' % dogtag_uri) time.sleep(30) attempts += 1 except errors.EmptyModlist: updated = True break except Exception, e: syslog.syslog(syslog.LOG_ERR, 'Updating %s entry failed: %s' % (str(dn), e)) break finally: if conn.isconnected(): conn.disconnect() if not updated: syslog.syslog(syslog.LOG_ERR, 'Update failed.') return False return True if __name__ == "__main__": standard_logging_setup("install.log") ds = dsinstance.DsInstance() ca = CAInstance("EXAMPLE.COM", "/etc/httpd/alias") ca.configure_instance("catest.example.com", "example.com", "password", "password") freeipa-3.3.4/ipaserver/install/service.py0000664000175000017500000003637712271663206020207 0ustar mkosekmkosek# Authors: Karl MacMillan # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import sys import os, socket import tempfile import pwd import time import datetime from ipapython import sysrestore, ipautil, dogtag, ipaldap from ipapython import services as ipaservices from ipapython.dn import DN from ipapython.ipa_log_manager import * from ipalib import errors 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 = { 'KDC': ('krb5kdc', 10), 'KPASSWD': ('kadmin', 20), 'DNS': ('named', 30), 'MEMCACHE': ('ipa_memcached', 39), 'HTTP': ('httpd', 40), 'CA': ('%sd' % dogtag.configured_constants().PKI_INSTANCE_NAME, 50), 'ADTRUST': ('smb', 60), 'EXTID': ('winbind', 70), 'OTPD': ('ipa-otpd', 80), } def print_msg(message, output_fd=sys.stdout): root_logger.debug(message) output_fd.write(message) output_fd.write("\n") output_fd.flush() class Service(object): def __init__(self, service_name, service_desc=None, sstore=None, dm_password=None, ldapi=True, autobind=AUTO): self.service_name = service_name self.service_desc = service_desc 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 if sstore: self.sstore = sstore else: self.sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') self.realm = None self.suffix = DN() self.principal = None self.dercert = None def ldap_connect(self): # 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 self.admin_conn = conn def ldap_disconnect(self): self.admin_conn.unbind() self.admin_conn = None def _ldap_mod(self, ldif, sub_dict = None): pw_name = None fd = None path = ipautil.SHARE_DIR + ldif nologlist=[] if sub_dict is not None: txt = ipautil.template_file(path, sub_dict) fd = ipautil.write_tmp_file(txt) path = fd.name # do not log passwords if sub_dict.has_key('PASSWORD'): nologlist.append(sub_dict['PASSWORD']) 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.ldap_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: # always try GSSAPI auth when not using DM password or not being root if os.getegid() != 0: auth_parms = ["-Y", "GSSAPI"] args += auth_parms try: try: ipautil.run(args, nolog=nologlist) except ipautil.CalledProcessError, e: root_logger.critical("Failed to load %s: %s" % (ldif, str(e))) finally: if pw_name: os.remove(pw_name) if fd is not None: fd.close() def move_service(self, principal): """ Used to move a principal entry created by kadmin.local from cn=kerberos to cn=services """ dn = DN(('krbprincipalname', principal), ('cn', self.realm), ('cn', 'kerberos'), self.suffix) try: entry = self.admin_conn.get_entry(dn) except errors.NotFound: # There is no service in the wrong location, nothing to do. # This can happen when installing a replica return None newdn = DN(('krbprincipalname', principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix) hostdn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix) self.admin_conn.delete_entry(entry) entry.dn = newdn classes = entry.get("objectclass") classes = classes + ["ipaobject", "ipaservice", "pkiuser"] entry["objectclass"] = list(set(classes)) entry["ipauniqueid"] = ['autogenerate'] entry["managedby"] = [hostdn] self.admin_conn.add_entry(entry) return newdn def add_simple_service(self, principal): """ Add a very basic IPA service. The principal needs to be fully-formed: service/host@REALM """ if not self.admin_conn: self.ldap_connect() dn = DN(('krbprincipalname', principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix) hostdn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix) entry = self.admin_conn.make_entry( dn, objectclass=[ "krbprincipal", "krbprincipalaux", "krbticketpolicyaux", "ipaobject", "ipaservice", "pkiuser"], krbprincipalname=[principal], ipauniqueid=['autogenerate'], managedby=[hostdn], ) self.admin_conn.add_entry(entry) return dn def add_cert_to_service(self): """ Add a certificate to a service This server cert should be in DER format. """ # 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 = DN(('krbprincipalname', self.principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix) entry = self.admin_conn.get_entry(dn) entry.setdefault('userCertificate', []).append(self.dercert) try: self.admin_conn.update_entry(entry) except Exception, e: root_logger.critical("Could not add certificate to service %s entry: %s" % (self.principal, str(e))) def is_configured(self): return self.sstore.has_state(self.service_name) def set_output(self, fd): self.output_fd = fd 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, wait=True): self.service.start(instance_name, capture_output=capture_output, wait=wait) 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() def install(self): self.service.install() def remove(self): self.service.remove() def enable(self): self.service.enable() def disable(self): self.service.disable() def is_enabled(self): return self.service.is_enabled() def backup_state(self, key, value): self.sstore.backup_state(self.service_name, key, value) def restore_state(self, key): return self.sstore.restore_state(self.service_name, key) def get_state(self, key): return self.sstore.get_state(self.service_name, key) def print_msg(self, message): print_msg(message, self.output_fd) def step(self, message, method): self.steps.append((message, method)) def start_creation(self, start_message=None, end_message=None, show_service_name=True, runtime=-1): """ Starts creation of the service. Use start_message and end_message for explicit messages at the beggining / end of the process. Otherwise they are generated using the service description (or service name, if the description has not been provided). Use show_service_name to include service name in generated descriptions. """ if start_message is None: # no other info than mandatory service_name provided, use that if self.service_desc is None: start_message = "Configuring %s" % self.service_name # description should be more accurate than service name else: start_message = "Configuring %s" % self.service_desc if show_service_name: start_message = "%s (%s)" % (start_message, self.service_name) if end_message is None: if self.service_desc is None: if show_service_name: end_message = "Done configuring %s." % self.service_name else: end_message = "Done." else: if show_service_name: end_message = "Done configuring %s (%s)." % ( self.service_desc, self.service_name) else: end_message = "Done configuring %s." % self.service_desc if runtime > 0: plural='' est = time.localtime(runtime) if est.tm_min > 0: if est.tm_min > 1: plural = 's' if est.tm_sec > 0: self.print_msg('%s: Estimated time %d minute%s %d seconds' % (start_message, est.tm_min, plural, est.tm_sec)) else: self.print_msg('%s: Estimated time %d minute%s' % (start_message, est.tm_min, plural)) else: if est.tm_sec > 1: plural = 's' self.print_msg('%s: Estimated time %d second%s' % (start_message, est.tm_sec, plural)) else: self.print_msg(start_message) step = 0 for (message, method) in self.steps: self.print_msg(" [%d/%d]: %s" % (step+1, len(self.steps), message)) s = datetime.datetime.now() method() e = datetime.datetime.now() d = e - s root_logger.debug(" duration: %d seconds" % d.seconds) step += 1 self.print_msg(end_message) self.steps = [] def ldap_enable(self, name, fqdn, dm_password, ldap_suffix): assert isinstance(ldap_suffix, DN) self.disable() if not self.admin_conn: self.ldap_connect() entry_name = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix) order = SERVICE_LIST[name][1] entry = self.admin_conn.make_entry( entry_name, objectclass=["nsContainer", "ipaConfigObject"], cn=[name], ipaconfigstring=[ "enabledService", "startOrder " + str(order)], ) try: self.admin_conn.add_entry(entry) except (errors.DuplicateEntry), e: root_logger.debug("failed to add %s Service startup entry" % name) raise e class SimpleServiceInstance(Service): 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) self.start_creation("Configuring %s" % self.service_name) suffix = ipautil.dn_attribute_property('_ldap_suffix') def __start(self): self.backup_state("running", self.is_running()) self.restart() def __enable(self): self.enable() self.backup_state("enabled", self.is_enabled()) if self.gensvc_name == None: self.enable() else: self.ldap_enable(self.gensvc_name, self.fqdn, self.dm_password, self.suffix) def uninstall(self): if self.is_configured(): self.print_msg("Unconfiguring %s" % self.service_name) running = self.restore_state("running") enabled = not self.restore_state("enabled") if not running is None and not running: self.stop() if not enabled is None and not enabled: self.disable() self.remove() freeipa-3.3.4/ipaserver/install/sysupgrade.py0000664000175000017500000000276212202434255020716 0ustar mkosekmkosek# Authors: Martin Kosek # # 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 . # import os import os.path from ipapython import sysrestore from ipapython.ipa_log_manager import * STATEFILE_DIR = '/var/lib/ipa/sysupgrade' STATEFILE_FILE = 'sysupgrade.state' _sstore = sysrestore.StateFile(STATEFILE_DIR, STATEFILE_FILE) def get_upgrade_state(module, state): global _sstore return _sstore.get_state(module, state) def set_upgrade_state(module, state, value): global _sstore _sstore.backup_state(module, state, value) def remove_upgrade_state(module, state): global _sstore _sstore.delete_state(module, state) def remove_upgrade_file(): try: os.remove(os.path.join(STATEFILE_DIR, STATEFILE_FILE)) except Exception, e: root_logger.debug('Cannot remove sysupgrade state file: %s', e) freeipa-3.3.4/ipaserver/install/ldapupdate.py0000664000175000017500000011521312271663206020655 0ustar mkosekmkosek# Authors: Rob Crittenden # # 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 . # # Documentation can be found at http://freeipa.org/page/LdapUpdate # TODO # save undo files? UPDATES_DIR="/usr/share/ipa/updates/" import sys import uuid import platform import time import os import pwd import fnmatch import csv import inspect import re import krbV import ldap from ldap.schema.models import ObjectClass, AttributeType from ipaserver.install import installutils from ipapython import ipautil, ipaldap from ipalib import errors from ipalib import api from ipapython.dn import DN from ipapython.ipa_log_manager import * from ipaserver.install.plugins import PRE_UPDATE, POST_UPDATE from ipaserver.plugins import ldap2 class BadSyntax(installutils.ScriptError): def __init__(self, value): self.value = value self.msg = "LDAPUpdate: syntax error: \n %s" % value self.rval = 1 def __str__(self): return repr(self.value) def safe_output(attr, values): """ Sanitizes values we do not want logged, like passwords. This should be called in all debug statements that output values. This list does not necessarily need to be exhaustive given the limited scope of types of values that the updater manages. This only supports lists, tuples and strings. If you pass a dict you may get a string back. """ sensitive_attributes = ['krbmkey', 'userpassword', 'passwordhistory', 'krbprincipalkey', 'sambalmpassword', 'sambantpassword', 'ipanthash'] if attr.lower() in sensitive_attributes: if type(values) in (tuple, list): # try to still look a little like what is in LDAP return ['XXXXXXX'] * len(values) else: return 'XXXXXXXX' else: return values class LDAPUpdate: action_keywords = ["default", "add", "remove", "only", "onlyifexist", "deleteentry", "replace", "addifnew", "addifexist"] def __init__(self, dm_password, sub_dict={}, live_run=True, online=True, ldapi=False, plugins=False): ''' :parameters: dm_password Directory Manager password sub_dict substitution dictionary live_run Apply the changes or just test online Do an online LDAP update or use an experimental LDIF updater ldapi Bind using ldapi. This assumes autobind is enabled. plugins execute the pre/post update plugins Data Structure Example: ----------------------- dn_by_rdn_count = { 3: 'cn=config,dc=example,dc=com': 4: 'cn=bob,ou=people,dc=example,dc=com', } all_updates = { 'dn': 'cn=config,dc=example,dc=com': { 'dn': 'cn=config,dc=example,dc=com', 'default': ['attr1':default1'], 'updates': ['action:attr1:value1', 'action:attr2:value2] }, 'dn': 'cn=bob,ou=people,dc=example,dc=com': { 'dn': 'cn=bob,ou=people,dc=example,dc=com', 'default': ['attr3':default3'], 'updates': ['action:attr3:value3', 'action:attr4:value4], } } The default and update lists are "dispositions" ''' log_mgr.get_logger(self, True) self.sub_dict = sub_dict self.live_run = live_run self.dm_password = dm_password self.conn = None self.modified = False self.online = online self.ldapi = ldapi self.plugins = plugins self.pw_name = pwd.getpwuid(os.geteuid()).pw_name self.realm = None suffix = None if sub_dict.get("REALM"): self.realm = sub_dict["REALM"] else: krbctx = krbV.default_context() try: self.realm = krbctx.default_realm suffix = ipautil.realm_to_suffix(self.realm) except krbV.Krb5Error: self.realm = None suffix = None if suffix is not None: assert isinstance(suffix, DN) domain = ipautil.get_domain_name() libarch = self._identify_arch() fqdn = installutils.get_fqdn() if fqdn is None: raise RuntimeError("Unable to determine hostname") fqhn = fqdn # Save this for the sub_dict variable if self.ldapi: fqdn = "ldapi://%%2fvar%%2frun%%2fslapd-%s.socket" % "-".join( self.realm.split(".") ) if not self.sub_dict.get("REALM") and self.realm is not None: self.sub_dict["REALM"] = self.realm if not self.sub_dict.get("FQDN"): self.sub_dict["FQDN"] = fqhn if not self.sub_dict.get("DOMAIN"): self.sub_dict["DOMAIN"] = domain if not self.sub_dict.get("SUFFIX") and suffix is not None: self.sub_dict["SUFFIX"] = suffix if not self.sub_dict.get("ESCAPED_SUFFIX"): self.sub_dict["ESCAPED_SUFFIX"] = str(suffix) if not self.sub_dict.get("LIBARCH"): self.sub_dict["LIBARCH"] = libarch if not self.sub_dict.get("TIME"): self.sub_dict["TIME"] = int(time.time()) if not self.sub_dict.get("DOMAIN") and domain is not None: self.sub_dict["DOMAIN"] = domain if online: # Try out the connection/password try: conn = ipaldap.IPAdmin(fqdn, ldapi=self.ldapi, realm=self.realm) if self.dm_password: conn.do_simple_bind(binddn=DN(('cn', 'directory manager')), bindpw=self.dm_password) elif os.getegid() == 0: try: # autobind conn.do_external_bind(self.pw_name) except errors.NotFound: # Fall back conn.do_sasl_gssapi_bind() else: conn.do_sasl_gssapi_bind() conn.unbind() except (ldap.CONNECT_ERROR, ldap.SERVER_DOWN): raise RuntimeError("Unable to connect to LDAP server %s" % fqdn) except ldap.INVALID_CREDENTIALS: raise RuntimeError("The password provided is incorrect for LDAP server %s" % fqdn) except ldap.LOCAL_ERROR, e: raise RuntimeError('%s' % e.args[0].get('info', '').strip()) else: raise RuntimeError("Offline updates are not supported.") # The following 2 functions were taken from the Python # documentation at http://docs.python.org/library/csv.html def _utf_8_encoder(self, unicode_csv_data): for line in unicode_csv_data: yield line.encode('utf-8') def _unicode_csv_reader(self, unicode_csv_data, quote_char="'", dialect=csv.excel, **kwargs): # csv.py doesn't do Unicode; encode temporarily as UTF-8: csv_reader = csv.reader(self._utf_8_encoder(unicode_csv_data), dialect=dialect, delimiter=',', quotechar=quote_char, skipinitialspace=True, **kwargs) for row in csv_reader: # decode UTF-8 back to Unicode, cell by cell: yield [unicode(cell, 'utf-8') for cell in row] def _identify_arch(self): """On multi-arch systems some libraries may be in /lib64, /usr/lib64, etc. Determine if a suffix is needed based on the current architecture. """ bits = platform.architecture()[0] if bits == "64bit": return "64" else: return "" def _template_str(self, s): try: return ipautil.template_str(s, self.sub_dict) except KeyError, e: raise BadSyntax("Unknown template keyword %s" % e) def _parse_values(self, line): """Parse a comma-separated string into separate values and convert them into a list. This should handle quoted-strings with embedded commas """ if line[0] == "'": quote_char = "'" else: quote_char = '"' reader = self._unicode_csv_reader([line], quote_char) value = [] for row in reader: value = value + row return value def read_file(self, filename): if filename == '-': fd = sys.stdin else: fd = open(filename) text = fd.readlines() if fd != sys.stdin: fd.close() return text def _entry_to_entity(self, ent): entry = ent.copy() entry.commit() return entry def _combine_updates(self, all_updates, update): 'Combine a new update with the list of total updates' dn = update.get('dn') assert isinstance(dn, DN) if not all_updates.get(dn): all_updates[dn] = update return existing_update = all_updates[dn] if 'default' in update: disposition_list = existing_update.setdefault('default', []) disposition_list.extend(update['default']) elif 'updates' in update: disposition_list = existing_update.setdefault('updates', []) disposition_list.extend(update['updates']) else: self.debug("Unknown key in updates %s" % update.keys()) def merge_updates(self, all_updates, updates): ''' Add the new_update dict to the all_updates dict. If an entry in the new_update already has an entry in all_updates merge the two entries sensibly assuming the new entries take precedence. Otherwise just add the new entry. ''' for new_update in updates: for new_dn, new_entry in new_update.iteritems(): existing_entry = all_updates.get(new_dn) if existing_entry: # If the existing entry is marked for deletion but the # new entry is not also a delete then clear the delete # flag otherwise the newer update will be lost. if existing_entry.has_key('deleteentry') and not new_entry.has_key('deleteentry'): self.warning("ldapupdate: entry '%s' previously marked for deletion but" + " this subsequent update reestablishes it: %s", new_dn, new_entry) del existing_entry['deleteentry'] existing_entry.update(new_entry) else: all_updates[new_dn] = new_entry def parse_update_file(self, data_source_name, source_data, all_updates): """Parse the update file into a dictonary of lists and apply the update for each DN in the file.""" update = {} logical_line = "" action = "" dn = None lcount = 0 def emit_item(logical_line): ''' Given a logical line containing an item to process perform the following: * Strip leading & trailing whitespace * Substitute any variables * Get the action, attribute, and value * Each update has one list per disposition, append to specified disposition list ''' logical_line = logical_line.strip() if logical_line == '': return # Perform variable substitution on constructued line logical_line = self._template_str(logical_line) items = logical_line.split(':', 2) if len(items) == 0: raise BadSyntax, "Bad formatting on line %s:%d: %s" % (data_source_name, lcount, logical_line) action = items[0].strip().lower() if action not in self.action_keywords: raise BadSyntax, "Unknown update action '%s', data source=%s" % (action, data_source_name) if action == 'deleteentry': new_value = None disposition = "deleteentry" else: if len(items) != 3: raise BadSyntax, "Bad formatting on line %s:%d: %s" % (data_source_name, lcount, logical_line) attr = items[1].strip() value = items[2].strip() if action == "default": new_value = attr + ":" + value disposition = "default" else: new_value = action + ":" + attr + ":" + value disposition = "updates" disposition_list = update.setdefault(disposition, []) disposition_list.append(new_value) def emit_update(update): ''' When processing a dn is completed emit the update by merging it into the set of all updates. ''' self._combine_updates(all_updates, update) # Iterate over source input lines for source_line in source_data: lcount += 1 # strip trailing whitespace and newline source_line = source_line.rstrip() # skip comments and empty lines if source_line.startswith('#') or source_line == '': continue if source_line.lower().startswith('dn:'): # Starting new dn if dn is not None: # Emit previous dn emit_item(logical_line) logical_line = '' emit_update(update) update = {} dn = source_line[3:].strip() dn = DN(self._template_str(dn)) update['dn'] = dn else: # Process items belonging to dn if dn is None: raise BadSyntax, "dn is not defined in the update, data source=%s" % (data_source_name) # If continuation line, append to existing logical line & continue, # otherwise flush the previous item. if source_line.startswith(' '): logical_line += source_line[1:] continue else: emit_item(logical_line) logical_line = '' logical_line = source_line if dn is not None: emit_item(logical_line) logical_line = '' emit_update(update) update = {} return all_updates def create_index_task(self, attribute): """Create a task to update an index for an attribute""" # Sleep a bit to ensure previous operations are complete if self.live_run: time.sleep(5) 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')) e = self.conn.make_entry( dn, objectClass=['top', 'extensibleObject'], cn=[cn], nsInstance=['userRoot'], nsIndexAttribute=[attribute], ) self.info("Creating task to index attribute: %s", attribute) self.debug("Task id: %s", dn) if self.live_run: self.conn.add_entry(e) return dn def monitor_index_task(self, dn): """Give a task DN monitor it and wait until it has completed (or failed) """ assert isinstance(dn, DN) if not self.live_run: # If not doing this live there is nothing to monitor return # Pause for a moment to give the task time to be created time.sleep(1) attrlist = ['nstaskstatus', 'nstaskexitcode'] entry = None while True: try: entry = self.conn.get_entry(dn, attrlist) except errors.NotFound, e: self.error("Task not found: %s", dn) return except errors.DatabaseError, e: self.error("Task lookup failure %s", e) return status = entry.single_value('nstaskstatus', None) if status is None: # task doesn't have a status yet time.sleep(1) continue if status.lower().find("finished") > -1: self.info("Indexing finished") break self.debug("Indexing in progress") time.sleep(1) return def _create_default_entry(self, dn, default): """Create the default entry from the values provided. The return type is ipaldap.LDAPEntry """ assert isinstance(dn, DN) entry = self.conn.make_entry(dn) if not default: # This means that the entire entry needs to be created with add return self._entry_to_entity(entry) for item in default: # We already do syntax-parsing so this is safe (attr, value) = item.split(':',1) e = entry.get(attr) if e: # multi-valued attribute e = list(e) e.append(value) else: e = [value] entry[attr] = e return self._entry_to_entity(entry) def _get_entry(self, dn): """Retrieve an object from LDAP. The return type is ipaldap.LDAPEntry """ assert isinstance(dn, DN) searchfilter="objectclass=*" sattrs = ["*", "aci", "attributeTypes", "objectClasses"] scope = ldap.SCOPE_BASE return self.conn.get_entries(dn, scope, searchfilter, sattrs) def _apply_update_disposition(self, updates, entry): """ updates is a list of changes to apply entry is the thing to apply them to Returns the modified entry """ if not updates: return entry only = {} for update in updates: # We already do syntax-parsing so this is safe (action, attr, update_values) = update.split(':',2) update_values = self._parse_values(update_values) # If the attribute is known to be a DN convert it to a DN object. # This has to be done after _parse_values() due to quoting and comma separated lists. if self.conn.has_dn_syntax(attr): update_values = [DN(x) for x in update_values] entry_values = entry.get(attr) if not isinstance(entry_values, list): if entry_values is None: entry_values = [] else: entry_values = [entry_values] # Replacing objectClassess needs a special handling and # normalization of OC definitions to avoid update failures for # example when X-ORIGIN is the only difference schema_update = False schema_elem_class = None schema_elem_name = None if action == "replace" and entry.dn == DN(('cn', 'schema')): if attr.lower() == "objectclasses": schema_elem_class = ObjectClass schema_elem_name = "ObjectClass" elif attr.lower() == "attributetypes": schema_elem_class = AttributeType schema_elem_name = "AttributeType" if schema_elem_class is not None: schema_update = True oid_index = {} # build the OID index for replacing for schema_elem in entry_values: try: schema_elem_object = schema_elem_class(str(schema_elem)) except Exception, e: self.error('replace: cannot parse %s "%s": %s', schema_elem_name, schema_elem, e) continue # In a corner case, there may be more representations of # the same objectclass/attributetype due to the previous updates # We want to replace them all oid_index.setdefault(schema_elem_object.oid, []).append(schema_elem) for update_value in update_values: if action == 'remove': self.debug("remove: '%s' from %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr,entry_values)) try: entry_values.remove(update_value) except ValueError: self.warning("remove: '%s' not in %s", update_value, attr) pass entry[attr] = entry_values self.debug('remove: updated value %s', safe_output(attr, entry_values)) elif action == 'add': self.debug("add: '%s' to %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr, entry_values)) # Remove it, ignoring errors so we can blindly add it later try: entry_values.remove(update_value) except ValueError: pass entry_values.append(update_value) self.debug('add: updated value %s', safe_output(attr, entry_values)) entry[attr] = entry_values elif action == 'addifnew': self.debug("addifnew: '%s' to %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr, entry_values)) # Only add the attribute if it doesn't exist. Only works # with single-value attributes. if len(entry_values) == 0: entry_values.append(update_value) self.debug('addifnew: set %s to %s', attr, safe_output(attr, entry_values)) entry[attr] = entry_values elif action == 'addifexist': self.debug("addifexist: '%s' to %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr, entry_values)) # Only add the attribute if the entry doesn't exist. We # determine this based on whether it has an objectclass if entry.get('objectclass'): entry_values.append(update_value) self.debug('addifexist: set %s to %s', attr, safe_output(attr, entry_values)) entry[attr] = entry_values elif action == 'only': self.debug("only: set %s to '%s', current value %s", attr, safe_output(attr, update_value), safe_output(attr, entry_values)) if only.get(attr): entry_values.append(update_value) else: entry_values = [update_value] only[attr] = True entry[attr] = entry_values self.debug('only: updated value %s', safe_output(attr, entry_values)) elif action == 'onlyifexist': self.debug("onlyifexist: '%s' to %s, current value %s", safe_output(attr, update_value), attr, safe_output(attr, entry_values)) # Only set the attribute if the entry exist's. We # determine this based on whether it has an objectclass if entry.get('objectclass'): if only.get(attr): entry_values.append(update_value) else: entry_values = [update_value] only[attr] = True self.debug('onlyifexist: set %s to %s', attr, safe_output(attr, entry_values)) entry[attr] = entry_values elif action == 'deleteentry': # skip this update type, it occurs in __delete_entries() return None elif action == 'replace': # value has the format "old::new" try: (old, new) = update_value.split('::', 1) except ValueError: raise BadSyntax, "bad syntax in replace, needs to be in the format old::new in %s" % update_value try: if schema_update: try: schema_elem_old = schema_elem_class(str(old)) except Exception, e: self.error('replace: cannot parse replaced %s "%s": %s', schema_elem_name, old, e) continue replaced_values = [] for schema_elem in oid_index.get(schema_elem_old.oid, []): schema_elem_object = schema_elem_class(str(schema_elem)) if str(schema_elem_old).lower() == str(schema_elem_object).lower(): # compare normalized values replaced_values.append(schema_elem) self.debug('replace: replace %s "%s" with "%s"', schema_elem_name, safe_output(attr, old), safe_output(attr, new)) if not replaced_values: self.debug('replace: no match for replaced %s "%s"', schema_elem_name, safe_output(attr, old)) continue for value in replaced_values: entry_values.remove(value) else: entry_values.remove(old) entry_values.append(new) self.debug('replace: updated value %s', safe_output(attr, entry_values)) entry[attr] = entry_values except ValueError: self.debug('replace: %s not found, skipping', safe_output(attr, old)) return entry def print_entity(self, e, message=None): """The entity object currently lacks a str() method""" self.debug("---------------------------------------------") if message: self.debug("%s", message) self.debug("dn: %s", e.dn) for a, value in e.items(): if isinstance(value, (list, tuple)): self.debug('%s:', a) for l in value: self.debug("\t%s", safe_output(a, l)) else: self.debug('%s: %s', a, safe_output(a, value)) def is_schema_updated(self, s): """Compare the schema in 's' with the current schema in the DS to see if anything has changed. This should account for syntax differences (like added parens that make no difference but are detected as a change by generateModList()). This doesn't handle re-ordering of attributes. They are still detected as changes, so foo $ bar != bar $ foo. return True if the schema has changed return False if it has not """ signature = inspect.getargspec(ldap.schema.SubSchema.__init__) if 'check_uniqueness' in signature.args: s = ldap.schema.SubSchema(s, check_uniqueness=0) else: s = ldap.schema.SubSchema(s) s = s.ldap_entry() # Get a fresh copy and convert into a SubSchema n = self._get_entry(DN(('cn', 'schema')))[0] # Convert IPA data types back to strings d = dict() for k,v in n.data.items(): d[k] = [str(x) for x in v] # Convert to subschema dict n = ldap.schema.SubSchema(d) n = n.ldap_entry() # Are they equal? if s == n: return False else: return True def _update_record(self, update): found = False # If the entry is going to be deleted no point in processing it. if update.has_key('deleteentry'): return new_entry = self._create_default_entry(update.get('dn'), update.get('default')) try: e = self._get_entry(new_entry.dn) if len(e) > 1: # we should only ever get back one entry raise BadSyntax, "More than 1 entry returned on a dn search!? %s" % new_entry.dn entry = self._entry_to_entity(e[0]) found = True self.info("Updating existing entry: %s", entry.dn) except errors.NotFound: # Doesn't exist, start with the default entry entry = new_entry self.info("New entry: %s", entry.dn) except errors.DatabaseError: # Doesn't exist, start with the default entry entry = new_entry self.info("New entry, using default value: %s", entry.dn) self.print_entity(entry, "Initial value") # Bring this entry up to date entry = self._apply_update_disposition(update.get('updates'), entry) if entry is None: # It might be None if it is just deleting an entry return self.print_entity(entry, "Final value after applying updates") added = False updated = False if not found: # New entries get their orig_data set to the entry itself. We want to # empty that so that everything appears new when generating the # modlist # entry.orig_data = {} try: if self.live_run: if len(entry): # addifexist may result in an entry with only a # dn defined. In that case there is nothing to do. # It means the entry doesn't exist, so skip it. try: self.conn.add_entry(entry) except errors.NotFound: # parent entry of the added entry does not exist # this may not be an error (e.g. entries in NIS container) self.info("Parent DN of %s may not exist, cannot create the entry", entry.dn) return added = True self.modified = True except Exception, e: self.error("Add failure %s", e) else: # Update LDAP try: changes = self.conn.generateModList(entry.origDataDict(), entry.toDict()) if (entry.dn == DN(('cn', 'schema'))): d = dict() e = entry.toDict() for k,v in e.items(): d[k] = [str(x) for x in v] updated = self.is_schema_updated(d) else: if len(changes) >= 1: updated = True safe_changes = [] for (type, attr, values) in changes: safe_changes.append((type, attr, safe_output(attr, values))) self.debug("%s" % safe_changes) self.debug("Live %d, updated %d" % (self.live_run, updated)) if self.live_run and updated: self.conn.updateEntry(entry.dn, entry.origDataDict(), entry.toDict()) self.info("Done") except errors.EmptyModlist: self.info("Entry already up-to-date") updated = False except errors.DatabaseError, e: self.error("Update failed: %s", e) updated = False except errors.ACIError, e: self.error("Update failed: %s", e) updated = False if updated: self.modified = True if entry.dn.endswith(DN(('cn', 'index'), ('cn', 'userRoot'), ('cn', 'ldbm database'), ('cn', 'plugins'), ('cn', 'config'))) and (added or updated): taskid = self.create_index_task(entry.single_value('cn')) self.monitor_index_task(taskid) return def _delete_record(self, updates): """ Run through all the updates again looking for any that should be deleted. This must use a reversed list so that the longest entries are considered first so we don't end up trying to delete a parent and child in the wrong order. """ if not updates.has_key('deleteentry'): return dn = updates['dn'] try: self.info("Deleting entry %s", dn) if self.live_run: self.conn.delete_entry(dn) self.modified = True except errors.NotFound, e: self.info("%s did not exist:%s", dn, e) self.modified = True except errors.DatabaseError, e: self.error("Delete failed: %s", e) def get_all_files(self, root, recursive=False): """Get all update files""" f = [] for path, subdirs, files in os.walk(root): for name in files: if fnmatch.fnmatch(name, "*.update"): f.append(os.path.join(path, name)) if not recursive: break f.sort() return f def create_connection(self): if self.online: if self.ldapi: self.conn = ipaldap.IPAdmin(ldapi=True, realm=self.realm) else: self.conn = ipaldap.IPAdmin(self.sub_dict['FQDN'], ldapi=False, realm=self.realm) try: if self.dm_password: self.conn.do_simple_bind(binddn=DN(('cn', 'directory manager')), bindpw=self.dm_password) elif os.getegid() == 0: try: # autobind self.conn.do_external_bind(self.pw_name) except errors.NotFound: # Fall back self.conn.do_sasl_gssapi_bind() else: self.conn.do_sasl_gssapi_bind() except ldap.LOCAL_ERROR, e: raise RuntimeError('%s' % e.args[0].get('info', '').strip()) else: raise RuntimeError("Offline updates are not supported.") def _run_updates(self, all_updates): # For adds and updates we want to apply updates from shortest # to greatest length of the DN. cn=schema must always go first to add # new objectClasses and attributeTypes # For deletes we want the reverse def update_sort_key(dn_update): dn, update = dn_update assert isinstance(dn, DN) return dn != DN(('cn', 'schema')), len(dn) sorted_updates = sorted(all_updates.iteritems(), key=update_sort_key) for dn, update in sorted_updates: self._update_record(update) # Now run the deletes in reversed order sorted_updates.reverse() for dn, update in sorted_updates: self._delete_record(update) def update(self, files, ordered=False): """Execute the update. files is a list of the update files to use. If ordered is True then the updates the file must be of the form ##-name.update where ## is an integer between 10 and 89. The changes are applied to LDAP at the end of each value divisible by 10, so after 20, 30, etc. returns True if anything was changed, otherwise False """ pat = re.compile(r'(\d+)-.*\.update') all_updates = {} r = 20 if self.plugins: self.info('PRE_UPDATE') updates = api.Backend.updateclient.update(PRE_UPDATE, self.dm_password, self.ldapi, self.live_run) self.merge_updates(all_updates, updates) try: self.create_connection() if ordered and all_updates: # flush out PRE_UPDATE plugin updates before we begin self._run_updates(all_updates) all_updates = {} for f in files: name = os.path.basename(f) if ordered: m = pat.match(name) if not m: raise RuntimeError("Filename does not match format #-name.update: %s" % f) index = int(m.group(1)) if index < 10 or index > 90: raise RuntimeError("Index not legal range: %d" % index) if index >= r: self._run_updates(all_updates) all_updates = {} r += 10 try: self.info("Parsing update file '%s'" % f) data = self.read_file(f) except Exception, e: self.error("error reading update file '%s'", f) sys.exit(e) self.parse_update_file(f, data, all_updates) self._run_updates(all_updates) finally: if self.conn: self.conn.unbind() if self.plugins: self.info('POST_UPDATE') all_updates = {} updates = api.Backend.updateclient.update(POST_UPDATE, self.dm_password, self.ldapi, self.live_run) self.merge_updates(all_updates, updates) self._run_updates(all_updates) return self.modified def update_from_dict(self, updates): """ Apply updates internally as opposed to from a file. updates is a dictionary containing the updates """ if not self.conn: self.create_connection() self._run_updates(updates) return self.modified freeipa-3.3.4/ipaserver/install/ipa_server_certinstall.py0000664000175000017500000001452512271663206023301 0ustar mkosekmkosek#! /usr/bin/python # Authors: Karl MacMillan # Jan Cholasta # # Copyright (C) 2007-2013 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 . # import sys import os import os.path import pwd import optparse from ipapython import admintool from ipapython.dn import DN from ipapython.ipautil import user_input, write_tmp_file from ipalib import api, errors from ipaserver.install import certs, dsinstance, httpinstance, installutils from ipaserver.plugins.ldap2 import ldap2 CACERT = "/etc/ipa/ca.crt" class ServerCertInstall(admintool.AdminTool): command_name = 'ipa-server-certinstall' usage = "%prog <-d|-w> [options] " description = "Install new SSL server certificates." @classmethod def add_options(cls, parser): super(ServerCertInstall, cls).add_options(parser) parser.add_option( "-d", "--dirsrv", dest="dirsrv", action="store_true", default=False, help="install certificate for the directory server") parser.add_option( "-w", "--http", dest="http", action="store_true", default=False, help="install certificate for the http server") parser.add_option( "--pin", dest="pin", help="The password of the PKCS#12 file") parser.add_option( "--dirsrv_pin", "--http_pin", dest="pin", help=optparse.SUPPRESS_HELP) parser.add_option( "-p", "--dirman-password", dest="dirman_password", help="Directory Manager password") def validate_options(self): super(ServerCertInstall, self).validate_options(needs_root=True) installutils.check_server_configuration() if not self.options.dirsrv and not self.options.http: self.option_parser.error("you must specify dirsrv and/or http") if len(self.args) != 1: self.option_parser.error("you must provide a pkcs12 filename") def ask_for_options(self): super(ServerCertInstall, self).ask_for_options() if self.options.dirsrv and not self.options.dirman_password: self.options.dirman_password = installutils.read_password( "Directory Manager", confirm=False, validate=False, retry=False) if self.options.dirman_password is None: raise admintool.ScriptError( "Directory Manager password required") if self.options.pin is None: self.options.pin = installutils.read_password( "Enter %s unlock" % self.args[0], confirm=False, validate=False) if self.options.pin is None: raise admintool.ScriptError( "%s unlock password required" % self.args[0]) def run(self): api.bootstrap(in_server=True) api.finalize() self.pkcs12_fname = self.args[0] if self.options.dirsrv: self.install_dirsrv_cert() if self.options.http: self.install_http_cert() def install_dirsrv_cert(self): serverid = dsinstance.realm_to_serverid(api.env.realm) dirname = dsinstance.config_dirname(serverid) conn = ldap2(shared_instance=False, base_dn='') conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=self.options.dirman_password) entry = conn.get_entry(DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')), ['nssslpersonalityssl']) old_cert = entry.single_value('nssslpersonalityssl') server_cert = self.import_cert(dirname, self.options.pin, old_cert, 'ldap/%s' % api.env.host, 'restart_dirsrv %s' % serverid) entry['nssslpersonalityssl'] = [server_cert] try: conn.update_entry(entry) except errors.EmptyModlist: pass conn.disconnect() def install_http_cert(self): dirname = certs.NSS_DIR old_cert = installutils.get_directive(httpinstance.NSS_CONF, 'NSSNickname') server_cert = self.import_cert(dirname, self.options.pin, old_cert, 'HTTP/%s' % api.env.host, 'restart_httpd') installutils.set_directive(httpinstance.NSS_CONF, 'NSSNickname', server_cert) # Fix the database permissions os.chmod(os.path.join(dirname, 'cert8.db'), 0640) os.chmod(os.path.join(dirname, 'key3.db'), 0640) os.chmod(os.path.join(dirname, 'secmod.db'), 0640) pent = pwd.getpwnam("apache") os.chown(os.path.join(dirname, 'cert8.db'), 0, pent.pw_gid) os.chown(os.path.join(dirname, 'key3.db'), 0, pent.pw_gid) os.chown(os.path.join(dirname, 'secmod.db'), 0, pent.pw_gid) def import_cert(self, dirname, pkcs12_passwd, old_cert, principal, command): server_cert = installutils.check_pkcs12( pkcs12_info=(self.pkcs12_fname, pkcs12_passwd), ca_file=CACERT, hostname=api.env.host) cdb = certs.CertDB(api.env.realm, nssdir=dirname) try: if api.env.enable_ra: cdb.untrack_server_cert(old_cert) cdb.delete_cert(old_cert) cdb.import_pkcs12(self.pkcs12_fname, pkcs12_passwd) if api.env.enable_ra: cdb.track_server_cert(server_cert, principal, cdb.passwd_fname, command) except RuntimeError, e: raise admintool.ScriptError(str(e)) return server_cert freeipa-3.3.4/ipaserver/rpcserver.py0000664000175000017500000013021212271663206017073 0ustar mkosekmkosek# Authors: # Jason Gerard DeRose # # 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 . """ RPC server. Also see the `ipalib.rpc` module. """ from xml.sax.saxutils import escape from xmlrpclib import Fault from wsgiref.util import shift_path_info import base64 import os import string import datetime from decimal import Decimal import urlparse import time import json from ipalib import plugable, capabilities from ipalib.backend import Executioner from ipalib.errors import PublicError, InternalError, CommandError, JSONError, ConversionError, CCacheError, RefererError, InvalidSessionPassword, NotFound, ACIError, ExecutionError from ipalib.request import context, Connection, destroy_context from ipalib.rpc import xml_dumps, xml_loads from ipalib.util import parse_time_duration, normalize_name from ipapython.dn import DN from ipaserver.plugins.ldap2 import ldap2 from ipalib.session import session_mgr, AuthManager, get_ipa_ccache_name, load_ccache_data, bind_ipa_ccache, release_ipa_ccache, fmt_time, default_max_session_duration from ipalib.backend import Backend from ipalib.krb_utils import krb5_parse_ccache, KRB5_CCache, krb_ticket_expiration_threshold, krb5_format_principal_name from ipapython import ipautil from ipapython.version import VERSION from ipalib.text import _ HTTP_STATUS_SUCCESS = '200 Success' HTTP_STATUS_SERVER_ERROR = '500 Internal Server Error' _not_found_template = """ 404 Not Found

Not Found

The requested URL %(url)s was not found on this server.

""" _bad_request_template = """ 400 Bad Request

Bad Request

%(message)s

""" _internal_error_template = """ 500 Internal Server Error

Internal Server Error

%(message)s

""" _unauthorized_template = """ 401 Unauthorized

Invalid Authentication

%(message)s

""" _pwchange_template = """ 200 Success

%(title)s

%(message)s

""" class HTTP_Status(plugable.Plugin): def not_found(self, environ, start_response, url, message): """ Return a 404 Not Found error. """ status = '404 Not Found' response_headers = [('Content-Type', 'text/html; charset=utf-8')] self.info('%s: URL="%s", %s', status, url, message) start_response(status, response_headers) output = _not_found_template % dict(url=escape(url)) return [output] def bad_request(self, environ, start_response, message): """ Return a 400 Bad Request error. """ status = '400 Bad Request' response_headers = [('Content-Type', 'text/html; charset=utf-8')] self.info('%s: %s', status, message) start_response(status, response_headers) output = _bad_request_template % dict(message=escape(message)) return [output] def internal_error(self, environ, start_response, message): """ Return a 500 Internal Server Error. """ status = HTTP_STATUS_SERVER_ERROR response_headers = [('Content-Type', 'text/html; charset=utf-8')] self.error('%s: %s', status, message) start_response(status, response_headers) output = _internal_error_template % dict(message=escape(message)) return [output] def unauthorized(self, environ, start_response, message, reason): """ Return a 401 Unauthorized error. """ status = '401 Unauthorized' response_headers = [('Content-Type', 'text/html; charset=utf-8')] if reason: response_headers.append(('X-IPA-Rejection-Reason', reason)) self.info('%s: %s', status, message) start_response(status, response_headers) output = _unauthorized_template % dict(message=escape(message)) return [output] def read_input(environ): """ Read the request body from environ['wsgi.input']. """ try: length = int(environ.get('CONTENT_LENGTH')) except (ValueError, TypeError): return return environ['wsgi.input'].read(length) def params_2_args_options(params): if len(params) == 0: return (tuple(), dict()) if len(params) == 1: return (params[0], dict()) return (params[0], params[1]) def nicify_query(query, encoding='utf-8'): if not query: return for (key, value) in query.iteritems(): if len(value) == 0: yield (key, None) elif len(value) == 1: yield (key, value[0].decode(encoding)) else: yield (key, tuple(v.decode(encoding) for v in value)) def extract_query(environ): """ Return the query as a ``dict``, or ``None`` if no query is presest. """ qstr = None if environ['REQUEST_METHOD'] == 'POST': if environ['CONTENT_TYPE'] == 'application/x-www-form-urlencoded': qstr = read_input(environ) elif environ['REQUEST_METHOD'] == 'GET': qstr = environ['QUERY_STRING'] if qstr: query = dict(nicify_query( urlparse.parse_qs(qstr)#, keep_blank_values=True) )) else: query = {} environ['wsgi.query'] = query return query class wsgi_dispatch(Executioner, HTTP_Status): """ WSGI routing middleware and entry point into IPA server. The `wsgi_dispatch` plugin is the entry point into the IPA server. It dispatchs the request to the appropriate wsgi application handler which is specific to the authentication and RPC mechanism. """ def __init__(self): super(wsgi_dispatch, self).__init__() self.__apps = {} def __iter__(self): for key in sorted(self.__apps): yield key def __getitem__(self, key): return self.__apps[key] def __contains__(self, key): return key in self.__apps def __call__(self, environ, start_response): self.debug('WSGI wsgi_dispatch.__call__:') try: return self.route(environ, start_response) finally: destroy_context() def _on_finalize(self): self.url = self.env['mount_ipa'] super(wsgi_dispatch, self)._on_finalize() def route(self, environ, start_response): key = environ.get('PATH_INFO') if key in self.__apps: app = self.__apps[key] return app(environ, start_response) url = environ['SCRIPT_NAME'] + environ['PATH_INFO'] return self.not_found(environ, start_response, url, 'URL fragment "%s" does not have a handler' % (key)) def mount(self, app, key): """ Mount the WSGI application *app* at *key*. """ # if self.__islocked__(): # raise StandardError('%s.mount(): locked, cannot mount %r at %r' % ( # self.name, app, key) # ) if key in self.__apps: raise StandardError('%s.mount(): cannot replace %r with %r at %r' % ( self.name, self.__apps[key], app, key) ) self.debug('Mounting %r at %r', app, key) self.__apps[key] = app class WSGIExecutioner(Executioner): """ Base class for execution backends with a WSGI application interface. """ content_type = None key = '' def set_api(self, api): super(WSGIExecutioner, self).set_api(api) if 'wsgi_dispatch' in self.api.Backend: self.api.Backend.wsgi_dispatch.mount(self, self.key) def _on_finalize(self): self.url = self.env.mount_ipa + self.key super(WSGIExecutioner, self)._on_finalize() def wsgi_execute(self, environ): result = None error = None _id = None lang = os.environ['LANG'] name = None args = () options = {} if not 'HTTP_REFERER' in environ: return self.marshal(result, RefererError(referer='missing'), _id) if not environ['HTTP_REFERER'].startswith('https://%s/ipa' % self.api.env.host) and not self.env.in_tree: return self.marshal(result, RefererError(referer=environ['HTTP_REFERER']), _id) try: if ('HTTP_ACCEPT_LANGUAGE' in environ): lang_reg_w_q = environ['HTTP_ACCEPT_LANGUAGE'].split(',')[0] lang_reg = lang_reg_w_q.split(';')[0] lang_ = lang_reg.split('-')[0] if '-' in lang_reg: reg = lang_reg.split('-')[1].upper(); else: reg = lang_.upper() os.environ['LANG'] = '%s_%s' % (lang_, reg) if ( environ.get('CONTENT_TYPE', '').startswith(self.content_type) and environ['REQUEST_METHOD'] == 'POST' ): data = read_input(environ) (name, args, options, _id) = self.unmarshal(data) else: (name, args, options, _id) = self.simple_unmarshal(environ) if name not in self.Command: raise CommandError(name=name) result = self.Command[name](*args, **options) except PublicError, e: error = e except StandardError, e: self.exception( 'non-public: %s: %s', e.__class__.__name__, str(e) ) error = InternalError() finally: os.environ['LANG'] = lang if name and name in self.Command: try: params = self.Command[name].args_options_2_params(*args, **options) except Exception, e: self.info( 'exception %s caught when converting options: %s', e.__class__.__name__, str(e) ) # get at least some context of what is going on params = options principal = getattr(context, 'principal', 'UNKNOWN') if error: self.info('%s: %s(%s): %s', principal, name, ', '.join(self.Command[name]._repr_iter(**params)), e.__class__.__name__) else: self.info('%s: %s(%s): SUCCESS', principal, name, ', '.join(self.Command[name]._repr_iter(**params))) else: self.info('%s: %s', context.principal, e.__class__.__name__) return self.marshal(result, error, _id) def simple_unmarshal(self, environ): name = environ['PATH_INFO'].strip('/') options = extract_query(environ) return (name, tuple(), options, None) def __call__(self, environ, start_response): """ WSGI application for execution. """ self.debug('WSGI WSGIExecutioner.__call__:') try: status = HTTP_STATUS_SUCCESS response = self.wsgi_execute(environ) headers = [('Content-Type', self.content_type + '; charset=utf-8')] except StandardError, e: self.exception('WSGI %s.__call__():', self.name) status = HTTP_STATUS_SERVER_ERROR response = status headers = [('Content-Type', 'text/plain; charset=utf-8')] session_data = getattr(context, 'session_data', None) if session_data is not None: # Send session cookie back and store session data # FIXME: the URL path should be retreived from somewhere (but where?), not hardcoded session_cookie = session_mgr.generate_cookie('/ipa', session_data['session_id'], session_data['session_expiration_timestamp']) headers.append(('Set-Cookie', session_cookie)) start_response(status, headers) return [response] def unmarshal(self, data): raise NotImplementedError('%s.unmarshal()' % self.fullname) def marshal(self, result, error, _id=None): raise NotImplementedError('%s.marshal()' % self.fullname) def json_encode_binary(val): ''' JSON cannot encode binary values. We encode binary values in Python str objects and text in Python unicode objects. In order to allow a binary object to be passed through JSON we base64 encode it thus converting it to text which JSON can transport. To assure we recognize the value is a base64 encoded representation of the original binary value and not confuse it with other text we convert the binary value to a dict in this form: {'__base64__' : base64_encoding_of_binary_value} This modification of the original input value cannot be done "in place" as one might first assume (e.g. replacing any binary items in a container (e.g. list, tuple, dict) with the base64 dict because the container might be an immutable object (i.e. a tuple). Therefore this function returns a copy of any container objects it encounters with tuples replaced by lists. This is O.K. because the JSON encoding will map both lists and tuples to JSON arrays. ''' if isinstance(val, dict): new_dict = {} for k,v in val.items(): new_dict[k] = json_encode_binary(v) return new_dict elif isinstance(val, (list, tuple)): new_list = [json_encode_binary(v) for v in val] return new_list elif isinstance(val, str): return {'__base64__' : base64.b64encode(val)} elif isinstance(val, Decimal): return {'__base64__' : base64.b64encode(str(val))} elif isinstance(val, DN): return str(val) else: return val def json_decode_binary(val): ''' JSON cannot transport binary data. In order to transport binary data we convert binary data to a form like this: {'__base64__' : base64_encoding_of_binary_value} see json_encode_binary() After JSON had decoded the JSON stream back into a Python object we must recursively scan the object looking for any dicts which might represent binary values and replace the dict containing the base64 encoding of the binary value with the decoded binary value. Unlike the encoding problem where the input might consist of immutable object, all JSON decoded container are mutable so the conversion could be done in place. However we don't modify objects in place because of side effects which may be dangerous. Thus we elect to spend a few more cycles and avoid the possibility of unintended side effects in favor of robustness. ''' if isinstance(val, dict): if val.has_key('__base64__'): return base64.b64decode(val['__base64__']) else: new_dict = {} for k,v in val.items(): if isinstance(v, dict) and v.has_key('__base64__'): new_dict[k] = base64.b64decode(v['__base64__']) else: new_dict[k] = json_decode_binary(v) return new_dict elif isinstance(val, list): new_list = [] n = len(val) i = 0 while i < n: v = val[i] if isinstance(v, dict) and v.has_key('__base64__'): binary_val = base64.b64decode(v['__base64__']) new_list.append(binary_val) else: new_list.append(json_decode_binary(v)) i += 1 return new_list else: if isinstance(val, basestring): try: return val.decode('utf-8') except UnicodeDecodeError: raise ConversionError( name=val, error='incorrect type' ) else: return val class jsonserver(WSGIExecutioner, HTTP_Status): """ JSON RPC server. For information on the JSON-RPC spec, see: http://json-rpc.org/wiki/specification """ content_type = 'application/json' def __call__(self, environ, start_response): ''' ''' self.debug('WSGI jsonserver.__call__:') response = super(jsonserver, self).__call__(environ, start_response) return response def marshal(self, result, error, _id=None): if error: assert isinstance(error, PublicError) error = dict( code=error.errno, message=error.strerror, name=error.__class__.__name__, ) principal = getattr(context, 'principal', 'UNKNOWN') response = dict( result=result, error=error, id=_id, principal=unicode(principal), version=unicode(VERSION), ) response = json_encode_binary(response) return json.dumps(response, sort_keys=True, indent=4) def unmarshal(self, data): try: d = json.loads(data) except ValueError, e: raise JSONError(error=e) if not isinstance(d, dict): raise JSONError(error=_('Request must be a dict')) if 'method' not in d: raise JSONError(error=_('Request is missing "method"')) if 'params' not in d: raise JSONError(error=_('Request is missing "params"')) d = json_decode_binary(d) method = d['method'] params = d['params'] _id = d.get('id') if not isinstance(params, (list, tuple)): raise JSONError(error=_('params must be a list')) if len(params) != 2: raise JSONError(error=_('params must contain [args, options]')) args = params[0] if not isinstance(args, (list, tuple)): raise JSONError(error=_('params[0] (aka args) must be a list')) options = params[1] if not isinstance(options, dict): raise JSONError(error=_('params[1] (aka options) must be a dict')) options = dict((str(k), v) for (k, v) in options.iteritems()) return (method, args, options, _id) class AuthManagerKerb(AuthManager): ''' Instances of the AuthManger class are used to handle authentication events delivered by the SessionManager. This class specifcally handles the management of Kerbeos credentials which may be stored in the session. ''' def __init__(self, name): super(AuthManagerKerb, self).__init__(name) def logout(self, session_data): ''' The current user has requested to be logged out. To accomplish this we remove the user's kerberos credentials from their session. This does not destroy the session, it just prevents it from being used for fast authentication. Because the credentials are no longer in the session cache any future attempt will require the acquisition of credentials using one of the login mechanisms. ''' if session_data.has_key('ccache_data'): self.debug('AuthManager.logout.%s: deleting ccache_data', self.name) del session_data['ccache_data'] else: self.error('AuthManager.logout.%s: session_data does not contain ccache_data', self.name) class KerberosSession(object): ''' Functionally shared by all RPC handlers using both sessions and Kerberos. This class must be implemented as a mixin class rather than the more obvious technique of subclassing because the classes needing this do not share a common base class. ''' def kerb_session_on_finalize(self): ''' Initialize values from the Env configuration. Why do it this way and not simply reference api.env.session_auth_duration? Because that config item cannot be used directly, it must be parsed and converted to an integer. It would be inefficient to reparse it on every request. So we parse it once and store the result in the class instance. ''' # Set the session expiration time try: seconds = parse_time_duration(self.api.env.session_auth_duration) self.session_auth_duration = int(seconds) self.debug("session_auth_duration: %s", datetime.timedelta(seconds=self.session_auth_duration)) except Exception, e: self.session_auth_duration = default_max_session_duration self.error('unable to parse session_auth_duration, defaulting to %d: %s', self.session_auth_duration, e) def update_session_expiration(self, session_data, krb_endtime): ''' Each time a session is created or accessed we need to update it's expiration time. The expiration time is set inside the session_data. :parameters: session_data The session data whose expiration is being updatded. krb_endtime The UNIX timestamp for when the Kerberos credentials expire. :returns: None ''' # Account for clock skew and/or give us some time leeway krb_expiration = krb_endtime - krb_ticket_expiration_threshold # Set the session expiration time session_mgr.set_session_expiration_time(session_data, duration=self.session_auth_duration, max_age=krb_expiration, duration_type=self.api.env.session_duration_type) def finalize_kerberos_acquisition(self, who, ccache_name, environ, start_response, headers=None): if headers is None: headers = [] # Retrieve the session data (or newly create) session_data = session_mgr.load_session_data(environ.get('HTTP_COOKIE')) session_id = session_data['session_id'] self.debug('finalize_kerberos_acquisition: %s ccache_name="%s" session_id="%s"', who, ccache_name, session_id) # Copy the ccache file contents into the session data session_data['ccache_data'] = load_ccache_data(ccache_name) # Set when the session will expire cc = KRB5_CCache(ccache_name) endtime = cc.endtime(self.api.env.host, self.api.env.realm) self.update_session_expiration(session_data, endtime) # Store the session data now that it's been updated with the ccache session_mgr.store_session_data(session_data) # The request is finished with the ccache, destroy it. release_ipa_ccache(ccache_name) # Return success and set session cookie session_cookie = session_mgr.generate_cookie('/ipa', session_id, session_data['session_expiration_timestamp']) headers.append(('Set-Cookie', session_cookie)) start_response(HTTP_STATUS_SUCCESS, headers) return [''] class xmlserver(WSGIExecutioner, HTTP_Status, KerberosSession): """ Execution backend plugin for XML-RPC server. Also see the `ipalib.rpc.xmlclient` plugin. """ content_type = 'text/xml' key = '/xml' def _on_finalize(self): self.__system = { 'system.listMethods': self.listMethods, 'system.methodSignature': self.methodSignature, 'system.methodHelp': self.methodHelp, } super(xmlserver, self)._on_finalize() self.kerb_session_on_finalize() def __call__(self, environ, start_response): ''' ''' self.debug('WSGI xmlserver.__call__:') user_ccache=environ.get('KRB5CCNAME') headers = [('Content-Type', 'text/xml; charset=utf-8')] if user_ccache is None: self.internal_error(environ, start_response, 'xmlserver.__call__: KRB5CCNAME not defined in HTTP request environment') return self.marshal(None, CCacheError()) try: self.create_context(ccache=user_ccache) response = super(xmlserver, self).__call__(environ, start_response) if getattr(context, 'session_data', None) is None and \ self.env.context != 'lite': self.finalize_kerberos_acquisition('xmlserver', user_ccache, environ, start_response, headers) except PublicError, e: status = HTTP_STATUS_SUCCESS response = status start_response(status, headers) return self.marshal(None, e) finally: destroy_context() return response def listMethods(self, *params): return tuple(name.decode('UTF-8') for name in self.Command) def methodSignature(self, *params): return u'methodSignature not implemented' def methodHelp(self, *params): return u'methodHelp not implemented' def unmarshal(self, data): (params, name) = xml_loads(data) (args, options) = params_2_args_options(params) if 'version' not in options: # Keep backwards compatibility with client containing # bug https://fedorahosted.org/freeipa/ticket/3294: # If `version` is not given in XML-RPC, assume an old version options['version'] = capabilities.VERSION_WITHOUT_CAPABILITIES return (name, args, options, None) def marshal(self, result, error, _id=None): if error: self.debug('response: %s: %s', error.__class__.__name__, str(error)) response = Fault(error.errno, error.strerror) else: if isinstance(result, dict): self.debug('response: entries returned %d', result.get('count', 1)) response = (result,) return xml_dumps(response, methodresponse=True) class jsonserver_session(jsonserver, KerberosSession): """ JSON RPC server protected with session auth. """ key = '/session/json' def __init__(self): super(jsonserver_session, self).__init__() auth_mgr = AuthManagerKerb(self.__class__.__name__) session_mgr.auth_mgr.register(auth_mgr.name, auth_mgr) def _on_finalize(self): super(jsonserver_session, self)._on_finalize() self.kerb_session_on_finalize() def need_login(self, start_response): status = '401 Unauthorized' headers = [] response = '' self.debug('jsonserver_session: %s need login', status) start_response(status, headers) return [response] def __call__(self, environ, start_response): ''' ''' self.debug('WSGI jsonserver_session.__call__:') # Load the session data session_data = session_mgr.load_session_data(environ.get('HTTP_COOKIE')) session_id = session_data['session_id'] self.debug('jsonserver_session.__call__: session_id=%s start_timestamp=%s access_timestamp=%s expiration_timestamp=%s', session_id, fmt_time(session_data['session_start_timestamp']), fmt_time(session_data['session_access_timestamp']), fmt_time(session_data['session_expiration_timestamp'])) ccache_data = session_data.get('ccache_data') # Redirect to login if no Kerberos credentials if ccache_data is None: self.debug('no ccache, need login') return self.need_login(start_response) ipa_ccache_name = bind_ipa_ccache(ccache_data) # Redirect to login if Kerberos credentials are expired cc = KRB5_CCache(ipa_ccache_name) if not cc.valid(self.api.env.host, self.api.env.realm): self.debug('ccache expired, deleting session, need login') # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) return self.need_login(start_response) # Update the session expiration based on the Kerberos expiration endtime = cc.endtime(self.api.env.host, self.api.env.realm) self.update_session_expiration(session_data, endtime) # Store the session data in the per-thread context setattr(context, 'session_data', session_data) # This may fail if a ticket from wrong realm was handled via browser try: self.create_context(ccache=ipa_ccache_name) except ACIError, e: return self.unauthorized(environ, start_response, str(e), 'denied') try: response = super(jsonserver_session, self).__call__(environ, start_response) finally: # Kerberos may have updated the ccache data during the # execution of the command therefore we need refresh our # copy of it in the session data so the next command sees # the same state of the ccache. # # However we must be careful not to restore the ccache # data in the session data if it was explicitly deleted # during the execution of the command. For example the # logout command removes the ccache data from the session # data to invalidate the session credentials. if session_data.has_key('ccache_data'): session_data['ccache_data'] = load_ccache_data(ipa_ccache_name) # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) # Store the session data. session_mgr.store_session_data(session_data) destroy_context() return response class jsonserver_kerb(jsonserver): """ JSON RPC server protected with kerberos auth. """ key = '/json' def __call__(self, environ, start_response): ''' ''' self.debug('WSGI jsonserver_kerb.__call__:') user_ccache=environ.get('KRB5CCNAME') if user_ccache is None: self.internal_error(environ, start_response, 'jsonserver_kerb.__call__: KRB5CCNAME not defined in HTTP request environment') return self.marshal(None, CCacheError()) self.create_context(ccache=user_ccache) try: response = super(jsonserver_kerb, self).__call__(environ, start_response) finally: destroy_context() return response class login_kerberos(Backend, KerberosSession, HTTP_Status): key = '/session/login_kerberos' def __init__(self): super(login_kerberos, self).__init__() def _on_finalize(self): super(login_kerberos, self)._on_finalize() self.api.Backend.wsgi_dispatch.mount(self, self.key) self.kerb_session_on_finalize() def __call__(self, environ, start_response): self.debug('WSGI login_kerberos.__call__:') # Get the ccache created by mod_auth_kerb user_ccache_name=environ.get('KRB5CCNAME') if user_ccache_name is None: return self.internal_error(environ, start_response, 'login_kerberos: KRB5CCNAME not defined in HTTP request environment') return self.finalize_kerberos_acquisition('login_kerberos', user_ccache_name, environ, start_response) class login_password(Backend, KerberosSession, HTTP_Status): content_type = 'text/plain' key = '/session/login_password' def __init__(self): super(login_password, self).__init__() def _on_finalize(self): super(login_password, self)._on_finalize() self.api.Backend.wsgi_dispatch.mount(self, self.key) self.kerb_session_on_finalize() def __call__(self, environ, start_response): self.debug('WSGI login_password.__call__:') # Get the user and password parameters from the request content_type = environ.get('CONTENT_TYPE', '').lower() if not content_type.startswith('application/x-www-form-urlencoded'): return self.bad_request(environ, start_response, "Content-Type must be application/x-www-form-urlencoded") method = environ.get('REQUEST_METHOD', '').upper() if method == 'POST': query_string = read_input(environ) else: return self.bad_request(environ, start_response, "HTTP request method must be POST") try: query_dict = urlparse.parse_qs(query_string) except Exception, e: return self.bad_request(environ, start_response, "cannot parse query data") user = query_dict.get('user', None) if user is not None: if len(user) == 1: user = user[0] else: return self.bad_request(environ, start_response, "more than one user parameter") else: return self.bad_request(environ, start_response, "no user specified") # allows login in the form user@SERVER_REALM or user@server_realm # FIXME: uppercasing may be removed when better handling of UPN # is introduced parts = normalize_name(user) if "domain" in parts: # username is of the form user@SERVER_REALM or user@server_realm # check whether the realm is server's realm # Users from other realms are not supported # (they do not have necessary LDAP entry, LDAP connect will fail) if parts["domain"].upper()==self.api.env.realm: user=parts["name"] else: return self.unauthorized(environ, start_response, '', 'denied') elif "flatname" in parts: # username is of the form NetBIOS\user return self.unauthorized(environ, start_response, '', 'denied') else: # username is of the form user or of some wild form, e.g. # user@REALM1@REALM2 or NetBIOS1\NetBIOS2\user (see normalize_name) # wild form username will fail at kinit, so nothing needs to be done pass password = query_dict.get('password', None) if password is not None: if len(password) == 1: password = password[0] else: return self.bad_request(environ, start_response, "more than one password parameter") else: return self.bad_request(environ, start_response, "no password specified") # Get the ccache we'll use and attempt to get credentials in it with user,password ipa_ccache_name = get_ipa_ccache_name() reason = 'invalid-password' try: self.kinit(user, self.api.env.realm, password, ipa_ccache_name) except InvalidSessionPassword, e: # Ok, now why is this bad. Is the password simply bad or is the # password expired? try: dn = DN(('uid', user), self.api.env.container_user, self.api.env.basedn) conn = ldap2(shared_instance=False, ldap_uri=self.api.env.ldap_uri) conn.connect(bind_dn=dn, bind_pw=password) # password is ok, must be expired, lets double-check (userdn, entry_attrs) = conn.get_entry(dn, ['krbpasswordexpiration']) if 'krbpasswordexpiration' in entry_attrs: expiration = entry_attrs['krbpasswordexpiration'][0] try: exp = time.strptime(expiration, '%Y%m%d%H%M%SZ') if exp <= time.gmtime(): reason = 'password-expired' except ValueError, v: self.error('Unable to convert %s to a time string' % expiration) except Exception: # It doesn't really matter how we got here but the user's # password is not accepted or the user is unknown. pass finally: if conn.isconnected(): conn.destroy_connection() return self.unauthorized(environ, start_response, str(e), reason) return self.finalize_kerberos_acquisition('login_password', ipa_ccache_name, environ, start_response) def kinit(self, user, realm, password, ccache_name): # Format the user as a kerberos principal principal = krb5_format_principal_name(user, realm) (stdout, stderr, returncode) = ipautil.run(['/usr/bin/kinit', principal], env={'KRB5CCNAME':ccache_name}, stdin=password, raiseonerr=False) self.debug('kinit: principal=%s returncode=%s, stderr="%s"', principal, returncode, stderr) if returncode != 0: raise InvalidSessionPassword(principal=principal, message=unicode(stderr)) class change_password(Backend, HTTP_Status): content_type = 'text/plain' key = '/session/change_password' def __init__(self): super(change_password, self).__init__() def _on_finalize(self): super(change_password, self)._on_finalize() self.api.Backend.wsgi_dispatch.mount(self, self.key) def __call__(self, environ, start_response): self.info('WSGI change_password.__call__:') # Get the user and password parameters from the request content_type = environ.get('CONTENT_TYPE', '').lower() if not content_type.startswith('application/x-www-form-urlencoded'): return self.bad_request(environ, start_response, "Content-Type must be application/x-www-form-urlencoded") method = environ.get('REQUEST_METHOD', '').upper() if method == 'POST': query_string = read_input(environ) else: return self.bad_request(environ, start_response, "HTTP request method must be POST") try: query_dict = urlparse.parse_qs(query_string) except Exception, e: return self.bad_request(environ, start_response, "cannot parse query data") data = {} for field in ('user', 'old_password', 'new_password'): value = query_dict.get(field, None) if value is not None: if len(value) == 1: data[field] = value[0] else: return self.bad_request(environ, start_response, "more than one %s parameter" % field) else: return self.bad_request(environ, start_response, "no %s specified" % field) # start building the response self.info("WSGI change_password: start password change of user '%s'", data['user']) status = HTTP_STATUS_SUCCESS response_headers = [('Content-Type', 'text/html; charset=utf-8')] title = 'Password change rejected' result = 'error' policy_error = None bind_dn = DN((self.api.Object.user.primary_key.name, data['user']), self.api.env.container_user, self.api.env.basedn) try: conn = ldap2(shared_instance=False, ldap_uri=self.api.env.ldap_uri) conn.connect(bind_dn=bind_dn, bind_pw=data['old_password']) except (NotFound, ACIError): result = 'invalid-password' message = 'The old password or username is not correct.' except Exception, e: message = "Could not connect to LDAP server." self.error("change_password: cannot authenticate '%s' to LDAP server: %s", data['user'], str(e)) else: try: conn.modify_password(bind_dn, data['new_password'], data['old_password']) except ExecutionError, e: result = 'policy-error' policy_error = escape(str(e)) message = "Password change was rejected: %s" % escape(str(e)) except Exception, e: message = "Could not change the password" self.error("change_password: cannot change password of '%s': %s", data['user'], str(e)) else: result = 'ok' title = "Password change successful" message = "Password was changed." finally: if conn.isconnected(): conn.destroy_connection() self.info('%s: %s', status, message) response_headers.append(('X-IPA-Pwchange-Result', result)) if policy_error: response_headers.append(('X-IPA-Pwchange-Policy-Error', policy_error)) start_response(status, response_headers) output = _pwchange_template % dict(title=str(title), message=str(message)) return [output] class xmlserver_session(xmlserver, KerberosSession): """ XML RPC server protected with session auth. """ key = '/session/xml' def __init__(self): super(xmlserver_session, self).__init__() auth_mgr = AuthManagerKerb(self.__class__.__name__) session_mgr.auth_mgr.register(auth_mgr.name, auth_mgr) def _on_finalize(self): super(xmlserver_session, self)._on_finalize() self.kerb_session_on_finalize() def need_login(self, start_response): status = '401 Unauthorized' headers = [] response = '' self.debug('xmlserver_session: %s need login', status) start_response(status, headers) return [response] def __call__(self, environ, start_response): ''' ''' self.debug('WSGI xmlserver_session.__call__:') # Load the session data session_data = session_mgr.load_session_data(environ.get('HTTP_COOKIE')) session_id = session_data['session_id'] self.debug('xmlserver_session.__call__: session_id=%s start_timestamp=%s access_timestamp=%s expiration_timestamp=%s', session_id, fmt_time(session_data['session_start_timestamp']), fmt_time(session_data['session_access_timestamp']), fmt_time(session_data['session_expiration_timestamp'])) ccache_data = session_data.get('ccache_data') # Redirect to /ipa/xml if no Kerberos credentials if ccache_data is None: self.debug('xmlserver_session.__call_: no ccache, need TGT') return self.need_login(start_response) ipa_ccache_name = bind_ipa_ccache(ccache_data) # Redirect to /ipa/xml if Kerberos credentials are expired cc = KRB5_CCache(ipa_ccache_name) if not cc.valid(self.api.env.host, self.api.env.realm): self.debug('xmlserver_session.__call_: ccache expired, deleting session, need login') # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) return self.need_login(start_response) # Update the session expiration based on the Kerberos expiration endtime = cc.endtime(self.api.env.host, self.api.env.realm) self.update_session_expiration(session_data, endtime) # Store the session data in the per-thread context setattr(context, 'session_data', session_data) environ['KRB5CCNAME'] = ipa_ccache_name try: response = super(xmlserver_session, self).__call__(environ, start_response) finally: # Kerberos may have updated the ccache data during the # execution of the command therefore we need refresh our # copy of it in the session data so the next command sees # the same state of the ccache. # # However we must be careful not to restore the ccache # data in the session data if it was explicitly deleted # during the execution of the command. For example the # logout command removes the ccache data from the session # data to invalidate the session credentials. if session_data.has_key('ccache_data'): session_data['ccache_data'] = load_ccache_data(ipa_ccache_name) # The request is finished with the ccache, destroy it. release_ipa_ccache(ipa_ccache_name) # Store the session data. session_mgr.store_session_data(session_data) destroy_context() return response freeipa-3.3.4/autogen.sh0000775000175000017500000000006112202434255014477 0ustar mkosekmkosek#!/bin/sh autoreconf -i -f ./configure ${1+"$@"} freeipa-3.3.4/setup.py0000775000175000017500000000567312271663206014237 0ustar mkosekmkosek#!/usr/bin/python # Authors: # Jason Gerard DeRose # # 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 . """ Python-level packaging using distutils. """ from distutils.core import setup from distutils.command.install_data import install_data as _install_data from distutils.util import change_root, convert_path from distutils import log from types import StringType import ipalib import os class install_data(_install_data): """Override the built-in install_data to gzip files once they are installed. """ def run(self): # install_data is a classic class so super() won't work. Call it # directly to copy the files first. _install_data.run(self) # Now gzip them for f in self.data_files: if type(f) is StringType: # it's a simple file f = convert_path(f) cmd = '/bin/gzip %s/%s' % (self.install_dir, f) log.info("gzipping %s/%s" % (self.install_dir, f)) os.system(cmd) else: # it's a tuple with path and a list of files dir = convert_path(f[0]) if not os.path.isabs(dir): dir = os.path.join(self.install_dir, dir) elif self.root: dir = change_root(self.root, dir) if f[1] == []: # If there are no files listed the user must be # trying to create an empty directory. So nothing # to do here. pass else: # gzip the files for data in f[1]: data = convert_path(data) cmd = '/bin/gzip %s/%s' % (dir, data) log.info("gzipping %s/%s" % (dir, data)) os.system(cmd) setup( name='freeipa', version=ipalib.__version__, license='GPLv3+', url='http://freeipa.org/', packages=[ 'ipalib', 'ipalib.plugins', 'ipaserver', 'ipaserver.advise', 'ipaserver.advise.plugins', 'ipaserver.plugins', 'ipaserver.install', 'ipaserver.install.plugins', ], scripts=['ipa'], data_files = [('share/man/man1', ["ipa.1"])], ) freeipa-3.3.4/init/0000775000175000017500000000000012202434255013444 5ustar mkosekmkosekfreeipa-3.3.4/init/SystemV/0000775000175000017500000000000012202434255015056 5ustar mkosekmkosekfreeipa-3.3.4/init/SystemV/ipa_memcached.init0000775000175000017500000000444412202434255020513 0ustar mkosekmkosek#! /bin/sh # # chkconfig: - 55 45 # description: The ipa_memcached daemon is a memory cache service for IPA # processname: memcached # config: /etc/sysconfig/ipa_memcached # pidfile: /var/run/ipa_memcached/ipa_memcached.pid # Standard LSB functions #. /lib/lsb/init-functions # Source function library. . /etc/init.d/functions SOCKET_PATH=/var/run/ipa_memcached/ipa_memcached USER=apache PIDFILE=/var/run/ipa_memcached/ipa_memcached.pid MAXCONN=1024 CACHESIZE=64 OPTIONS="" if [ -f /etc/sysconfig/ipa_memcached ];then . /etc/sysconfig/ipa_memcached fi # Check that networking is up. . /etc/sysconfig/network if [ "$NETWORKING" = "no" ] then exit 0 fi prog="ipa_memcached" pidfile=${PIDFILE-/var/run/ipa_memcached/ipa_memcached.pid} lockfile=${LOCKFILE-/var/lock/subsys/ipa_memcached} start () { echo -n $"Starting $prog: " # Ensure that $pidfile directory has proper permissions and exists piddir=`dirname $pidfile` if [ ! -d $piddir ]; then mkdir $piddir fi if [ "`stat -c %U $piddir`" != "$USER" ]; then chown $USER $piddir fi daemon --pidfile ${pidfile} /usr/bin/memcached -d -s ${SOCKET_PATH} -u ${USER} -m ${CACHESIZE} -c ${MAXCONN} -P ${pidfile} ${OPTIONS} RETVAL=$? echo [ $RETVAL -eq 0 ] && touch ${lockfile} return $RETVAL } stop () { echo -n $"Stopping $prog: " killproc -p ${pidfile} $prog RETVAL=$? echo if [ $RETVAL -eq 0 ] ; then rm -f ${lockfile} ${pidfile} fi return $RETVAL } restart () { stop start } reload() { restart } force_reload() { restart } rh_status() { # run checks to determine if the service is running or use generic status status -p ${pidfile} $prog } rh_status_q() { rh_status >/dev/null 2>&1 } # See how we were called. case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac exit $? freeipa-3.3.4/init/SystemV/ipa.init0000664000175000017500000000144612202434255016521 0ustar mkosekmkosek#!/bin/sh # # ipa This starts and stops ipa controlled daemons # # chkconfig: - 21 79 # description: IPA Server # configdir: /etc/ipa/ # export SYSTEMCTL_SKIP_REDIRECT=1 # Source function library. if [ -f /etc/rc.d/init.d/functions ] ; then . /etc/rc.d/init.d/functions fi # Source networking configuration. if [ -f /etc/sysconfig/network ] ; then . /etc/sysconfig/network fi # Check that networking is up. if [ "${NETWORKING}" = "no" ] then echo "Networking is down" exit 0 fi case "$1" in start|stop|restart|status) /usr/sbin/ipactl $1 ;; condrestart) /sbin/service dirsrv status RETVAL=$? [ $RETVAL = 0 ] && /usr/sbin/ipactl restart ;; *) echo "Usage: $0 {start|stop|status|restart|condrestart}" exit 2 esac freeipa-3.3.4/init/ipa_memcached.conf0000664000175000017500000000014012202434255017045 0ustar mkosekmkosekSOCKET_PATH=/var/run/ipa_memcached/ipa_memcached USER=apache MAXCONN=1024 CACHESIZE=64 OPTIONS= freeipa-3.3.4/init/systemd/0000775000175000017500000000000012271663206015142 5ustar mkosekmkosekfreeipa-3.3.4/init/systemd/ipa.service0000664000175000017500000000036712271663206017303 0ustar mkosekmkosek[Unit] Description=Identity, Policy, Audit Requires=network.target After=network.target [Service] Type=oneshot ExecStart=/usr/sbin/ipactl start ExecStop=/usr/sbin/ipactl stop RemainAfterExit=yes TimeoutSec=0 [Install] WantedBy=multi-user.target freeipa-3.3.4/init/systemd/ipa_memcached.service0000664000175000017500000000060312202434255021254 0ustar mkosekmkosek[Unit] Description=IPA memcached daemon, increases IPA server performance After=network.target [Service] Type=forking EnvironmentFile=/etc/sysconfig/ipa_memcached PIDFile=/var/run/ipa_memcached/ipa_memcached.pid ExecStart=/usr/bin/memcached -d -s $SOCKET_PATH -u $USER -m $CACHESIZE -c $MAXCONN -P /var/run/ipa_memcached/ipa_memcached.pid $OPTIONS [Install] WantedBy=multi-user.target freeipa-3.3.4/init/systemd/ipa.conf.tmpfiles0000664000175000017500000000011212202434255020370 0ustar mkosekmkosekd /var/run/ipa_memcached 0700 apache apache d /var/run/ipa 0700 root root freeipa-3.3.4/Contributors.txt0000664000175000017500000000246612271663206015755 0ustar mkosekmkosek# -*- coding: utf-8 -*- The following people have contributed to the FreeIPA project. (Listed in alphabetical order within category) Developers: Jr Aquino Tomas Babej Alexander Bokovoy Jan Cholasta Rob Crittenden Nalin Dahyabhai John Dennis Endi Dewata Jakub Hrozek Martin Kosek Nathan Kinder Ana Krivokapic Nathaniel McCallum Lynn Root Rich Megginson Simo Sorce Petr Viktorin Petr Vobornik Andrew Wnuk Adam Young Documentation: Ella Deon Lackey Testing: Jenny Galipeau Michael Gregg Suzanne Hillman Chandrasekar Kannan Gowrishankar Rajaiyan Yi Zhang Translators: Héctor Daniel Cabrera Yuri Chornoivan Teguh DC Piotr DrÄ…g Jérôme Fenal Gundachandru Jake Li Andrew Martynov Sankarshan Mukhopadhyay Wiki, Solution and Idea Contributors: James Hogarth Dale Macartney Viji V Nair Ryan Thompson David Zeuthen Graphic Design and User Interaction Design: Kyle Baker Máirín Duffy Management: Scott Haines Bob Lord Dmitri Pal Kevin Unthank Karl Wirth Past and Occasional Contributors: Sylvain Baubeau Yuri Chornoivan Frank Cusack Don Davis Jason DeRose Gunther Deschner Stephen Gallagher Ondrej Hamada Ian Kumlien Karl MacMillan Jon McCann Kevin McCarthy Jim Meyering Martin Nagy David O'Brien Lubomir Rintel Pete Rowley Andreas Schneider Jan Zeleny Pavel Zuna freeipa-3.3.4/install/0000775000175000017500000000000012271707664014164 5ustar mkosekmkosekfreeipa-3.3.4/install/po/0000775000175000017500000000000012271707664014602 5ustar mkosekmkosekfreeipa-3.3.4/install/po/uk.po0000664000175000017500000152723012271663206015564 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # jdennis , 2011 # Yuri Chornoivan , 2011-2013 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 16:10+0000\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: uk\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Введіть %(label)s ще раз Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸: " #, c-format msgid "Passwords do not match!" msgstr "Паролі не збігаютьÑÑ!" msgid "No matching entries found" msgstr "Відповідних запиÑів не знайдено" msgid "Topic or Command" msgstr "Тема або команда" msgid "The topic or command name." msgstr "Ðазва теми або команди." msgid "Topic commands:" msgstr "Команди теми:" msgid "To get command help, use:" msgstr "Щоб отримати довідку щодо команди, ÑкориÑтайтеÑÑ Ñ‚Ð°ÐºÐ¾ÑŽ командою:" msgid " ipa --help" msgstr " ipa <команда> --help" msgid "Command name" msgstr "Ðазва команди" msgid "Positional arguments" msgstr "Обов’Ñзкові аргументи" msgid "No file to read" msgstr "Ðемає файла Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ" #, python-format msgid "%(cver)s client incompatible with %(sver)s server at '%(server)s'" msgstr "Клієнт %(cver)s Ñ” неÑуміÑним з Ñервером %(sver)s на «%(server)s»" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "%(server)s повідомлÑÑ” про невідому помилку %(code)d: %(error)s" msgid "an internal error has occurred" msgstr "ÑталаÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°" #, python-format msgid "an internal error has occurred on server at '%(server)s'" msgstr "на Ñервері «%(server)s» ÑталаÑÑ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°" #, python-format msgid "unknown command '%(name)s'" msgstr "невідома команда: «%(name)s»" #, python-format msgid "error on server '%(server)s': %(error)s" msgstr "помилка на Ñервері «%(server)s»: %(error)s" #, python-format msgid "cannot connect to '%(uri)s': %(error)s" msgstr "не вдалоÑÑ Ð²Ñтановити Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· «%(uri)s»: %(error)s" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "некоректний запит JSON-RPC: %(error)s" #, python-format msgid "error marshalling data for XML-RPC transport: %(error)s" msgstr "" "помилка під Ñ‡Ð°Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… Ð´Ð»Ñ ÐºÐ°Ð½Ð°Ð»Ñƒ Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ð½Ð½Ñ XML-RPC: %(error)s" #, python-format msgid "Missing or invalid HTTP Referer, %(referer)s" msgstr "Ðе вказано HTTP Referer або вказано помилкове значеннÑ, %(referer)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Помилка Kerberos: %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "не отримано реєÑтраційних даних Kerberos" #, python-format msgid "Service '%(service)s' not found in Kerberos database" msgstr "У базі даних Kerberos не виÑвлено Ñлужби «%(service)s»" msgid "No credentials cache found" msgstr "Ðе знайдено кешу реєÑтраційних даних" msgid "Ticket expired" msgstr "Сплив Ñтрок дії квитка" msgid "Credentials cache permissions incorrect" msgstr "Помилкові права доÑтупу до кешу реєÑтраційних даних" msgid "Bad format in credentials cache" msgstr "Помилковий формат кешу реєÑтраційних даних" msgid "Cannot resolve KDC for requested realm" msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ KDC Ð´Ð»Ñ Ð±Ð°Ð¶Ð°Ð½Ð¾Ñ— облаÑті (realm)" msgid "Session error" msgstr "Помилка ÑеанÑу" #, python-format msgid "Principal %(principal)s cannot be authenticated: %(message)s" msgstr "" "Ðе вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñ€ÐµÑ”Ñтраційного запиÑу %(principal)s: " "%(message)s" #, python-format msgid "Insufficient access: %(info)s" msgstr "ÐедоÑтатні права Ð´Ð»Ñ Ð´Ð¾Ñтупу: %(info)s" #, python-format msgid "command '%(name)s' takes no arguments" msgstr "команда «%(name)s» не приймає ніÑких аргументів" #, python-format msgid "command '%(name)s' takes at most %(count)d argument" msgid_plural "command '%(name)s' takes at most %(count)d arguments" msgstr[0] "команда «%(name)s» приймає не більше %(count)d аргументу" msgstr[1] "команда «%(name)s» приймає не більше %(count)d аргументів" msgstr[2] "команда «%(name)s» приймає не більше %(count)d аргументів" #, python-format msgid "overlapping arguments and options: %(names)s" msgstr "Ð¿ÐµÑ€ÐµÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ñ–Ð² Ñ– параметрів: %(names)s" #, python-format msgid "'%(name)s' is required" msgstr "Слід вказати «%(name)s»" #, python-format msgid "invalid '%(name)s': %(error)s" msgstr "некоректне «%(name)s»: %(error)s" #, python-format msgid "api has no such namespace: '%(name)s'" msgstr "api не надає такого проÑтору назв: «%(name)s»" msgid "Passwords do not match" msgstr "Паролі не збігаютьÑÑ" msgid "Command not implemented" msgstr "Команду не реалізовано" msgid "Client is not configured. Run ipa-client-install." msgstr "" "КлієнтÑьку чаÑтину не налаштовано. Віддайте команду ipa-client-install." #, python-format msgid "Could not get %(name)s interactively" msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ %(name)s у інтерактивному режимі" #, python-format msgid "Command '%(name)s' has been deprecated" msgstr "Команда «%(name)s» вважаєтьÑÑ Ð·Ð°Ñтарілою" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Цей Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¶Ðµ Ñ–Ñнує" msgid "You must enroll a host in order to create a host service" msgstr "Щоб Ñтворити Ñлужбу вузла, вам Ñлід зареєÑтрувати вузол" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Ñлужби вказано у формі, відмінній від: Ñлужба/повна " "назва вузла: %(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "" "ОблаÑть дії реєÑтраційного запиÑу не збігаєтьÑÑ Ð· облаÑтю цього Ñервера IPA" msgid "This command requires root access" msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñ†Ñ–Ñ”Ñ— команди потрібні права доÑтупу кориÑтувача root" msgid "This is already a posix group" msgstr "Вже Ñ” posix-групою" #, python-format msgid "Principal is not of the form user@REALM: '%(principal)s'" msgstr "" "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾ у формі, відмінній від кориÑтувач@ОБЛÐСТЬ: " "«%(principal)s»" msgid "This entry is already enabled" msgstr "Цей Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¶Ðµ увімкнено" msgid "This entry is already disabled" msgstr "Цей Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¶Ðµ вимкнено" msgid "This entry cannot be enabled or disabled" msgstr "Цей Ð·Ð°Ð¿Ð¸Ñ Ð½Ðµ можна вмикати або вимикати" msgid "This entry is not a member" msgstr "Цього запиÑу немає Ñеред учаÑників" msgid "A group may not be a member of itself" msgstr "Група не може бути елементом Ñамої Ñебе" msgid "This entry is already a member" msgstr "Цей Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¶Ðµ Ñ” Ñеред учаÑників" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Помилка Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Base64: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "Групу не може бути додано Ñк елемент Ñамої Ñебе" msgid "The default users group cannot be removed" msgstr "Ðе можна вилучати типову групу кориÑтувачів" msgid "Host does not have corresponding DNS A record" msgstr "Вузол не має відповідного запиÑу DNS A" msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐµÑ€Ð¾Ð²Ð°Ð½Ð¸Ñ… груп заборонено. Спочатку групу Ñлід від’єднати." msgid "A managed group cannot have a password policy." msgstr "У керованої групи не може бути влаÑних правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." #, python-format msgid "'%(entry)s' doesn't have a certificate." msgstr "«%(entry)s» не міÑтить Ñертифіката." #, python-format msgid "Unable to create private group. A group '%(group)s' already exists." msgstr "Ðе вдалоÑÑ Ñтворити закриту групу. Група «%(group)s» вже Ñ–Ñнує." #, python-format msgid "" "A problem was encountered when verifying that all members were %(verb)s: " "%(exc)s" msgstr "" "Під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ виÑвлено проблему, вÑÑ– запиÑи учаÑників %(verb)s: %(exc)s" #, python-format msgid "%(attr)s does not contain '%(value)s'" msgstr "%(attr)s не міÑтить «%(value)s»" #, python-format msgid "" "The search criteria was not specific enough. Expected 1 and found %(found)d." msgstr "" "Критерій пошуку не був доÑтатньо точним. Мало бути вказано один критерій, " "виÑвлено — %(found)d." msgid "This group already allows external members" msgstr "У цій групі вже дозволено зовнішніх учаÑників" msgid "This group cannot be posix because it is external" msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° не може належати до груп POSIX, оÑкільки Ñ” зовнішньою" msgid "This is already a posix group and cannot be converted to external one" msgstr "" "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° вже належить до груп POSIX, отже Ñ—Ñ— не можна перетворити на зовнішню" #, python-format msgid "no command nor help topic '%(topic)s'" msgstr "не виÑвлено ні команди, ні запиÑу довідки «%(topic)s»" msgid "change collided with another change" msgstr "зміна конфліктує з іншою внеÑеною зміною" msgid "no modifications to be performed" msgstr "змін не внеÑено" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s: %(info)s" msgid "limits exceeded for this query" msgstr "цим запитом перевищено обмеженнÑ" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "modifying primary key is not allowed" msgstr "зміну оÑновного ключа заборонено" #, python-format msgid "%(attr)s: Only one value allowed." msgstr "%(attr)s: можна викориÑтовувати лише одне значеннÑ." #, python-format msgid "%(attr)s: Invalid syntax." msgstr "%(attr)s: некоректний ÑинтакÑиÑ." #, python-format msgid "Bad search filter %(info)s" msgstr "Помилковий фільтр пошуку %(info)s" msgid "Not allowed on non-leaf entry" msgstr "Заборонено Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів, Ñкі не Ñ” запиÑами лиÑтків (leaf)" msgid "LDAP timeout" msgstr "Ð§Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ LDAP" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ñ‚Ð¸ дію з Ñертифікатом: %(error)s" #, python-format msgid "Certificate format error: %(error)s" msgstr "Помилка Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката: %(error)s" msgid "Already registered" msgstr "Вже зареєÑтровано" msgid "Not registered yet" msgstr "Ще не зареєÑтровано" #, python-format msgid "%(key)s cannot be deleted because %(label)s %(dependent)s requires it" msgstr "" "%(key)s неможливо вилучити, оÑкільки він потрібен Ð´Ð»Ñ %(dependent)s %(label)s" #, python-format msgid "" "%(key)s cannot be deleted or disabled because it is the last member of " "%(label)s %(container)s" msgstr "" "%(key)s не може бути вилучено або вимкнено, оÑкільки він Ñ” оÑтаннім у " "%(container)s %(label)s" #, python-format msgid "%(label)s %(key)s cannot be deleted/modified: %(reason)s" msgstr "%(key)s %(label)s не можна вилучати або змінювати: %(reason)s" #, python-format msgid "%(name)s certificate is not valid" msgstr "Сертифікат %(name)s не Ñ” чинним" msgid "Results are truncated, try a more specific search" msgstr "" "СпиÑок результатів обрізано. Спробуйте точніше визначити критерії пошуку." #, python-format msgid "Unknown option: %(option)s" msgstr "Ðевідомий параметр: %(option)s" msgid "" "Retrieve and print all attributes from the server. Affects command output." msgstr "" "Отримати Ñ– вивеÑти вÑÑ– атрибути з Ñервера. СтоÑуєтьÑÑ Ð»Ð¸ÑˆÐµ виводу команд." msgid "Print entries as stored on the server. Only affects output format." msgstr "" "ВивеÑти запиÑи у формі, у Ñкій вони зберігаютьÑÑ Ð½Ð° Ñервері. СтоÑуєтьÑÑ Ð»Ð¸ÑˆÐµ " "формату Ð²Ð¸Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…." msgid "Client version. Used to determine if server will accept request." msgstr "" "ВерÑÑ–Ñ ÐºÐ»Ñ–Ñ”Ð½Ñ‚Ð°. ВикориÑтовуєтьÑÑ Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ, Ñкщо Ñервер приймає запит." msgid "Forward to server instead of running locally" msgstr "ПереÑпрÑмувати на Ñервер заміÑть локального виконаннÑ" msgid "Additional instructions:" msgstr "Додаткові наÑтанови:" #, python-format msgid "" "API Version number was not sent, forward compatibility not guaranteed. " "Assuming server's API version, %(server_version)s" msgstr "" "Ðе було надіÑлано номера верÑÑ–Ñ— програмного інтерфейÑу (API), ÑуміÑніÑть з " "найновішими верÑÑ–Ñми не можна гарантувати. ПрипуÑкаємо таку верÑÑ–ÑŽ API " "Ñервера: %(server_version)s" msgid "A dictionary representing an LDAP entry" msgstr "Словник, що відповідає запиÑу LDAP" msgid "A list of LDAP entries" msgstr "СпиÑок запиÑів LDAP" msgid "All commands should at least have a result" msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… команд має призводити до ÑкогоÑÑŒ результату" msgid "User-friendly description of action performed" msgstr "Зручний Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача Ð¾Ð¿Ð¸Ñ Ð´Ñ–Ñ—, що виконуєтьÑÑ" msgid "The primary_key value of the entry, e.g. 'jdoe' for a user" msgstr "" "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ primary_key (оÑновного ключа) запиÑу, наприклад, «iivanenko» Ð´Ð»Ñ " "кориÑтувача" msgid "Number of entries returned" msgstr "КількіÑть повернутих запиÑів" msgid "True if not all results were returned" msgstr "True, Ñкщо повернуто було вÑÑ– результати" msgid "List of deletions that failed" msgstr "СпиÑок вилучень, Ñкі не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸" msgid "True means the operation was successful" msgstr "True означає, що дію було виконано уÑпішно" msgid "incorrect type" msgstr "помилковий тип" msgid "Only one value is allowed" msgstr "Можна викориÑтовувати лише одне значеннÑ" msgid "must be True or False" msgstr "має дорівнювати True або False" msgid "must be an integer" msgstr "має бути цілим чиÑлом" #, python-format msgid "must be at least %(minvalue)d" msgstr "має бути чиÑлом, не меншим за %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "не може перевищувати %(maxvalue)d" msgid "must be a decimal number" msgstr "має бути деÑÑтковим чиÑлом" #, python-format msgid "must be at least %(minvalue)s" msgstr "має бути принаймні %(minvalue)s" #, python-format msgid "can be at most %(maxvalue)s" msgstr "не може перевищувати %(maxvalue)s" #, python-format msgid "" "number class '%(cls)s' is not included in a list of allowed number classes: " "%(allowed)s" msgstr "" "чиÑловий ÐºÐ»Ð°Ñ Â«%(cls)s» не включено до ÑпиÑку дозволених чиÑлових клаÑів: " "%(allowed)s" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "має відповідати шаблону «%(pattern)s»" msgid "must be binary data" msgstr "має бути бінарними даними" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "має бути розміром, не менше за %(minlength)d байтів" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "не повинне перевищувати за розміром %(maxlength)d байтів" #, python-format msgid "must be exactly %(length)d bytes" msgstr "має бути розміром точно у %(length)d байтів" msgid "must be Unicode text" msgstr "має бути текÑтом у Unicode" msgid "Leading and trailing spaces are not allowed" msgstr "ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ñ–Ð»Ñ–Ð² на початку Ñ– у кінці заборонено" #, python-format msgid "must be at least %(minlength)d characters" msgstr "має бути не меншим за %(minlength)d Ñимволів довжиною" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "не повинне перевищувати %(maxlength)d Ñимволів у довжину" #, python-format msgid "must be exactly %(length)d characters" msgstr "має бути точно %(length)d Ñимволів у довжину" #, python-format msgid "The character %(char)r is not allowed." msgstr "Ðе можна викориÑтовувати Ñимвол %(char)r." #, python-format msgid "must be '%(value)s'" msgstr "має бути «%(value)s»" #, python-format msgid "must be one of %(values)s" msgstr "має бути одним з таких значень: %(values)s" msgid "incomplete time value" msgstr "неповне чаÑове значеннÑ" msgid "this option is deprecated" msgstr "цей параметр вважаєтьÑÑ Ð·Ð°Ñтарілим" msgid "A list of ACI values" msgstr "СпиÑок значень ACI" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "type, filter, subtree Ñ– targetgroup Ñ” взаємовиключними" msgid "ACI prefix is required" msgstr "Слід вказати Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ ACI" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "Ñлід вказати хоча б одне з: type, filter, subtree, targetgroup, attrs або " "memberof" msgid "filter and memberof are mutually exclusive" msgstr "filter Ñ– memberof не можна викориÑтовувати разом" msgid "group, permission and self are mutually exclusive" msgstr "group, permission Ñ– self не можна викориÑтовувати разом" msgid "One of group, permission or self is required" msgstr "Слід вказати одне зі значень, group, permission або self" #, python-format msgid "Group '%s' does not exist" msgstr "Групи з назвою «%s» не Ñ–Ñнує" msgid "empty filter" msgstr "порожній фільтр" #, python-format msgid "Syntax Error: %(error)s" msgstr "СинтакÑична помилка: %(error)s" #, python-format msgid "invalid DN (%s)" msgstr "некоректне DN (%s)" #, python-format msgid "ACI with name \"%s\" not found" msgstr "Ðе знайдено ACI з назвою «%s»" msgid "ACI prefix" msgstr "Ð¿Ñ€ÐµÑ„Ñ–ÐºÑ ACI" msgid "" "Prefix used to distinguish ACI types (permission, delegation, selfservice, " "none)" msgstr "" "ПрефікÑ, за Ñким визначаєтьÑÑ Ñ‚Ð¸Ð¿ ACI (permission, delegation, selfservice, " "none)" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "Ðазва ACI" msgid "Permission" msgstr "Права доÑтупу" msgid "Permission ACI grants access to" msgstr "ACI прав доÑтупу надає доÑтуп до" msgid "User group" msgstr "Група кориÑтувачів" msgid "User group ACI grants access to" msgstr "Група кориÑтувачів, до Ñкої надає доÑтуп ACI" msgid "Permissions" msgstr "Права доÑтупу" msgid "Permissions to grant(read, write, add, delete, all)" msgstr "Права доÑтупу, Ñкі Ñлід надати (read, write, add, delete, all)" msgid "Attributes to which the permission applies" msgstr "Ðтрибути, до Ñких заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ доÑтупу" msgid "Attributes" msgstr "Ðтрибути" msgid "Type" msgstr "Тип" msgid "type of IPA object (user, group, host, hostgroup, service, netgroup)" msgstr "" "тип об’єкта IPA (user (кориÑтувач), group (група), host (вузол), hostgroup " "(група вузлів), service (Ñлужба), netgroup (мережева група))" msgid "Member of" msgstr "УчаÑник" msgid "Member of a group" msgstr "УчаÑник групи" msgid "Filter" msgstr "Фільтр" msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "ПрипуÑтимий фільтр LDAP (наприклад, ou=Engineering)" msgid "Subtree" msgstr "Піддерево" msgid "Subtree to apply ACI to" msgstr "Піддерево, до Ñкого Ñлід заÑтоÑувати ACI" msgid "Target group" msgstr "Цільова група" msgid "Group to apply ACI to" msgstr "Група, до Ñкої Ñлід заÑтоÑувати ACI" msgid "Target your own entry (self)" msgstr "Виконати над влаÑним запиÑом (self)" msgid "Apply ACI to your own entry (self)" msgstr "ЗаÑтоÑувати ACI до вашого влаÑного запиÑу (self)" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "Створено ACI «%(value)s»" msgid "Test the ACI syntax but don't write anything" msgstr "Перевірити ÑинтакÑÐ¸Ñ ACI, але не виконувати запиÑу" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "Вилучено ACI «%(value)s»" msgid "ACI" msgstr "ACI" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "Змінено ACI «%(value)s»" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d ACI" msgstr[1] "вÑтановлено відповідніÑть %(count)d ACI" msgstr[2] "вÑтановлено відповідніÑть %(count)d ACI" msgid "New ACI name" msgstr "Ðова назва ACI" #, python-format msgid "Renamed ACI to \"%(value)s\"" msgstr "ACI перейменовано на «%(value)s»" msgid "" "\n" "Auto Membership Rule.\n" "\n" "Bring clarity to the membership of hosts and users by configuring inclusive\n" "or exclusive regex patterns, you can automatically assign a new entries " "into\n" "a group or hostgroup based upon attribute information.\n" "\n" "A rule is directly associated with a group by name, so you cannot create\n" "a rule without an accompanying group or hostgroup.\n" "\n" "A condition is a regular expression used by 389-ds to match a new incoming\n" "entry with an automember rule. If it matches an inclusive rule then the\n" "entry is added to the appropriate group or hostgroup.\n" "\n" "A default group or hostgroup could be specified for entries that do not\n" "match any rule. In case of user entries this group will be a fallback group\n" "because all users are by default members of group specified in IPA config.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add the initial group or hostgroup:\n" " ipa hostgroup-add --desc=\"Web Servers\" webservers\n" " ipa group-add --desc=\"Developers\" devel\n" "\n" " Add the initial rule:\n" " ipa automember-add --type=hostgroup webservers\n" " ipa automember-add --type=group devel\n" "\n" " Add a condition to the rule:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" " ipa automember-add-condition --key=manager --type=group --inclusive-" "regex=^uid=mscott devel\n" "\n" " Add an exclusive condition to the rule to prevent auto assignment:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-" "regex=^web5\\.example\\.com webservers\n" "\n" " Add a host:\n" " ipa host-add web1.example.com\n" "\n" " Add a user:\n" " ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott\n" "\n" " Verify automembership:\n" " ipa hostgroup-show webservers\n" " Host-group: webservers\n" " Description: Web Servers\n" " Member hosts: web1.example.com\n" "\n" " ipa group-show devel\n" " Group name: devel\n" " Description: Developers\n" " GID: 1004200000\n" " Member users: tuser\n" "\n" " Remove a condition from the rule:\n" " ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" "\n" " Modify the automember rule:\n" " ipa automember-mod\n" "\n" " Set the default (fallback) target group:\n" " ipa automember-default-group-set --default-group=webservers --" "type=hostgroup\n" " ipa automember-default-group-set --default-group=ipausers --type=group\n" "\n" " Remove the default (fallback) target group:\n" " ipa automember-default-group-remove --type=hostgroup\n" " ipa automember-default-group-remove --type=group\n" "\n" " Show the default (fallback) target group:\n" " ipa automember-default-group-show --type=hostgroup\n" " ipa automember-default-group-show --type=group\n" "\n" " Find all of the automember rules:\n" " ipa automember-find\n" "\n" " Display a automember rule:\n" " ipa automember-show --type=hostgroup webservers\n" " ipa automember-show --type=group devel\n" "\n" " Delete an automember rule:\n" " ipa automember-del --type=hostgroup webservers\n" " ipa automember-del --type=group devel\n" msgstr "" "\n" "Правило автоматичної учаÑті.\n" "\n" "Спрощує Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÑƒÑ‡Ð°Ñті вузлів Ñ– кориÑтувачів за допомогою визначених\n" "вами шаблонів (формальних виразів) Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ñ‡Ð¸ не Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… запиÑів\n" "до груп або груп вузлів на оÑнові даних атрибутів у автоматичному режимі.\n" "\n" "Правило безпоÑередньо пов’ÑзуєтьÑÑ Ð· групою за назвою, отже ви не можете\n" "Ñтворювати правила, Ñкі не буде пов’Ñзано з групою кориÑтувачів чи групою\n" "вузлів.\n" "Умовою викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° Ñ” формальний вираз, Ñкий викориÑтовуватиметьÑÑ\n" "389-ds Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¾Ñті нового вхідного запиÑу з правилом\n" "автоматичної учаÑті. Якщо Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð°Ñ‚Ð¸Ð¼Ðµ правилу включеннÑ, його буде\n" "додано до відповідної групи або групи вузлів.\n" "\n" "Можна вказати типову групу або групу вузлів Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів, Ñкі не " "відповідають\n" "жодному правилу. У випадку запиÑів кориÑтувачів Ñ†Ñ Ð³Ñ€ÑƒÐ¿Ð° буде резервною,\n" "оÑкільки вÑÑ– кориÑтувачі Ñ” типовими учаÑниками групи, вказаної у " "налаштуваннÑÑ…\n" "IPA (файлі налаштувань).\n" "\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— групи або групи вузлів:\n" " ipa hostgroup-add --desc=\"Web Servers\" webservers\n" " ipa group-add --desc=\"Developers\" devel\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ð³Ð¾ правила:\n" " ipa automember-add --type=hostgroup webservers\n" " ipa automember-add --type=group devel\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÐ¼Ð¾Ð²Ð¸ до правила:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" " ipa automember-add-condition --key=manager --type=group --inclusive-" "regex=^uid=mscott devel\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÐ¼Ð¾Ð²Ð¸ Ð²Ð¸ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð´Ð¾ правила з метою запобіганнÑ\n" " автоматичному додаванню:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-" "regex=^web5\\.example\\.com webservers\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð²ÑƒÐ·Ð»Ð°:\n" " ipa host-add web1.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача:\n" " ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott\n" "\n" " Перевірка правила:\n" " ipa hostgroup-show webservers\n" " Host-group: webservers\n" " Description: Web Servers\n" " Member hosts: web1.example.com\n" "\n" " ipa group-show devel\n" " Group name: devel\n" " Description: Developers\n" " GID: 1004200000\n" " Member users: tuser\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÑƒÐ¼Ð¾Ð²Ð¸ з правила:\n" " ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" "\n" " ВнеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до правила автоматичної учаÑті:\n" " ipa automember-mod\n" "\n" " Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ñ— (резервної) групи призначеннÑ:\n" " ipa automember-default-group-set --default-group=webservers --" "type=hostgroup\n" " ipa automember-default-group-set --default-group=ipausers --type=group\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ñ— (резервної) групи призначеннÑ:\n" " ipa automember-default-group-remove --type=hostgroup\n" " ipa automember-default-group-remove --type=group\n" "\n" " Показати типову (резервну) групу призначеннÑ:\n" " ipa automember-default-group-show --type=hostgroup\n" " ipa automember-default-group-show --type=group\n" "\n" " Знайти вÑÑ– правила автоматичної учаÑті:\n" " ipa automember-find\n" "\n" " Показати правило автоматичної учаÑті:\n" " ipa automember-show --type=hostgroup webservers\n" " ipa automember-show --type=group devel\n" "\n" " Вилучити правило автоматичної учаÑті:\n" " ipa automember-del --type=hostgroup webservers\n" " ipa automember-del --type=group devel\n" msgid "Inclusive Regex" msgstr "Формальний вираз включеннÑ" msgid "Exclusive Regex" msgstr "Формальний вираз виключеннÑ" msgid "Attribute Key" msgstr "Ключ атрибута" msgid "" "Attribute to filter via regex. For example fqdn for a host, or manager for a " "user" msgstr "" "Ðтрибут Ð´Ð»Ñ Ñ„Ñ–Ð»ÑŒÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° формальним виразом. Приклад: fqdn Ð´Ð»Ñ Ð²ÑƒÐ·Ð»Ð° або " "manager Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача" msgid "Grouping Type" msgstr "Тип групуваннÑ" msgid "Grouping to which the rule applies" msgstr "ГрупуваннÑ, Ñкого ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "Automember Rule" msgstr "Правило автоматичної учаÑті" msgid "Auto Membership Rule" msgstr "Правило автоматичної учаÑті" msgid "Description" msgstr "ОпиÑ" msgid "A description of this auto member rule" msgstr "ÐžÐ¿Ð¸Ñ Ñ†ÑŒÐ¾Ð³Ð¾ правила автоматичної учаÑті" msgid "Default (fallback) Group" msgstr "Типова (резервна) група" msgid "Default group for entries to land" msgstr "Типова група Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів" #, python-format msgid "Group: %s not found!" msgstr "Група: %s не знайдено!" #, python-format msgid "%s is not a valid attribute." msgstr "%s не Ñ” коректним атрибутом." msgid "" "\n" " Add an automember rule.\n" " " msgstr "" "\n" " Додати правило автоматичної учаÑті.\n" " " #, python-format msgid "Added automember rule \"%(value)s\"" msgstr "Додано правило автоматичної учаÑті «%(value)s»" msgid "Auto Membership is not configured" msgstr "Ðвтоматичну учаÑть не налаштовано" msgid "" "\n" " Add conditions to an automember rule.\n" " " msgstr "" "\n" " Додати умови до правила автоматичної учаÑті.\n" " " msgid "Failed to add" msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸" #, python-format msgid "Added condition(s) to \"%(value)s\"" msgstr "Додано умови до «%(value)s»" msgid "Conditions that could not be added" msgstr "Умови, Ñкі не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸" msgid "Number of conditions added" msgstr "КількіÑть доданих умов" #, python-format msgid "Auto member rule: %s not found!" msgstr "Правило автоматичної учаÑті: %s не знайдено!" msgid "" "\n" " Override this so we can add completed and failed to the return " "result.\n" " " msgstr "" "\n" " ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· метою Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñƒ повернуте Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… щодо " "уÑпіху чи невдачі.\n" " " msgid "" "\n" " Remove conditions from an automember rule.\n" " " msgstr "" "\n" " Вилучити умови з правила автоматичної учаÑті.\n" " " #, python-format msgid "Removed condition(s) from \"%(value)s\"" msgstr "Вилучено умови з «%(value)s»" msgid "Conditions that could not be removed" msgstr "Умови, Ñкі не вдалоÑÑ Ð²Ð¸Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸" msgid "Number of conditions removed" msgstr "КількіÑть вилучених умов" msgid "" "\n" " Override this so we can set completed and failed.\n" " " msgstr "" "\n" " ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· метою вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñтанів уÑпіху та невдачі.\n" " " msgid "" "\n" " Modify an automember rule.\n" " " msgstr "" "\n" " Змінити правило автоматичної учаÑті.\n" " " #, python-format msgid "Modified automember rule \"%(value)s\"" msgstr "Змінено правило автоматичної учаÑті «%(value)s»" msgid "" "\n" " Delete an automember rule.\n" " " msgstr "" "\n" " Вилучити правило автоматичної учаÑті.\n" " " #, python-format msgid "Deleted automember rule \"%(value)s\"" msgstr "Вилучено правило автоматичної учаÑті «%(value)s»" msgid "" "\n" " Search for automember rules.\n" " " msgstr "" "\n" " Шукати правила автоматичної учаÑті.\n" " " #, python-format msgid "%(count)d rules matched" msgid_plural "%(count)d rules matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d правила" msgstr[1] "вÑтановлено відповідніÑть %(count)d правил" msgstr[2] "вÑтановлено відповідніÑть %(count)d правил" msgid "" "\n" " Display information about an automember rule.\n" " " msgstr "" "\n" " Показати дані щодо правила автоматичної учаÑті.\n" " " msgid "" "\n" " Set default (fallback) group for all unmatched entries.\n" " " msgstr "" "\n" " Ð’Ñтановити типову (резервну) групу Ð´Ð»Ñ Ð½ÐµÐ²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¸Ñ… запиÑів.\n" " " msgid "Default (fallback) group for entries to land" msgstr "Типова (резервна) група Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів" #, python-format msgid "Set default (fallback) group for automember \"%(value)s\"" msgstr "Ð’Ñтановити типову (резервну) групу Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ñ— учаÑті «%(value)s»" msgid "" "\n" " Remove default (fallback) group for all unmatched entries.\n" " " msgstr "" "\n" " Вилучити типову (резервну) групу Ð´Ð»Ñ Ð½ÐµÐ²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¸Ñ… запиÑів.\n" " " #, python-format msgid "Removed default (fallback) group for automember \"%(value)s\"" msgstr "Вилучити типову (резервну) групу Ð´Ð»Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ñ— учаÑті «%(value)s»" msgid "No default (fallback) group set" msgstr "Ðе вÑтановлено типової (резервної) групи" msgid "" "\n" " Display information about the default (fallback) automember groups.\n" " " msgstr "" "\n" " Показати дані щодо типових (резервних) груп автоматичної учаÑті.\n" " " msgid "" "\n" "Automount\n" "\n" "Stores automount(8) configuration for autofs(8) in IPA.\n" "\n" "The base of an automount configuration is the configuration file auto." "master.\n" "This is also the base location in IPA. Multiple auto.master configurations\n" "can be stored in separate locations. A location is implementation-specific\n" "with the default being a location named 'default'. For example, you can " "have\n" "locations by geographic region, by floor, by type, etc.\n" "\n" "Automount has three basic object types: locations, maps and keys.\n" "\n" "A location defines a set of maps anchored in auto.master. This allows you\n" "to store multiple automount configurations. A location in itself isn't\n" "very interesting, it is just a point to start a new automount map.\n" "\n" "A map is roughly equivalent to a discrete automount file and provides\n" "storage for keys.\n" "\n" "A key is a mount point associated with a map.\n" "\n" "When a new location is created, two maps are automatically created for\n" "it: auto.master and auto.direct. auto.master is the root map for all\n" "automount maps for the location. auto.direct is the default map for\n" "direct mounts and is mounted on /-.\n" "\n" "An automount map may contain a submount key. This key defines a mount\n" "location within the map that references another map. This can be done\n" "either using automountmap-add-indirect --parentmap or manually\n" "with automountkey-add and setting info to \"-type=autofs :\".\n" "\n" "EXAMPLES:\n" "\n" "Locations:\n" "\n" " Create a named location, \"Baltimore\":\n" " ipa automountlocation-add baltimore\n" "\n" " Display the new location:\n" " ipa automountlocation-show baltimore\n" "\n" " Find available locations:\n" " ipa automountlocation-find\n" "\n" " Remove a named automount location:\n" " ipa automountlocation-del baltimore\n" "\n" " Show what the automount maps would look like if they were in the " "filesystem:\n" " ipa automountlocation-tofiles baltimore\n" "\n" " Import an existing configuration into a location:\n" " ipa automountlocation-import baltimore /etc/auto.master\n" "\n" " The import will fail if any duplicate entries are found. For\n" " continuous operation where errors are ignored, use the --continue\n" " option.\n" "\n" "Maps:\n" "\n" " Create a new map, \"auto.share\":\n" " ipa automountmap-add baltimore auto.share\n" "\n" " Display the new map:\n" " ipa automountmap-show baltimore auto.share\n" "\n" " Find maps in the location baltimore:\n" " ipa automountmap-find baltimore\n" "\n" " Create an indirect map with auto.share as a submount:\n" " ipa automountmap-add-indirect baltimore --parentmap=auto.share --" "mount=sub auto.man\n" "\n" " This is equivalent to:\n" "\n" " ipa automountmap-add-indirect baltimore --mount=/man auto.man\n" " ipa automountkey-add baltimore auto.man --key=sub --info=\"-" "fstype=autofs ldap:auto.share\"\n" "\n" " Remove the auto.share map:\n" " ipa automountmap-del baltimore auto.share\n" "\n" "Keys:\n" "\n" " Create a new key for the auto.share map in location baltimore. This ties\n" " the map we previously created to auto.master:\n" " ipa automountkey-add baltimore auto.master --key=/share --info=auto." "share\n" "\n" " Create a new key for our auto.share map, an NFS mount for man pages:\n" " ipa automountkey-add baltimore auto.share --key=man --info=\"-ro,soft," "rsize=8192,wsize=8192 ipa.example.com:/shared/man\"\n" "\n" " Find all keys for the auto.share map:\n" " ipa automountkey-find baltimore auto.share\n" "\n" " Find all direct automount keys:\n" " ipa automountkey-find baltimore --key=/-\n" "\n" " Remove the man key from the auto.share map:\n" " ipa automountkey-del baltimore auto.share --key=man\n" msgstr "" "\n" "Ðвтоматичне монтуваннÑ\n" "\n" "Зберігає Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ automount(8) Ð´Ð»Ñ autofs(8) у IPA.\n" "\n" "ОÑновою налаштувань автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ” файл налаштувань auto." "master.\n" "Це також оÑновне міÑце у IPA. Декілька налаштувань auto.master можна\n" "зберігати у окремих міÑцÑÑ…. МіÑце залежить від реалізації, типовим\n" "Ñ” міÑце з назвою «default». Ðаприклад, ви можете Ñтворити міÑÑ†Ñ Ð´Ð»Ñ\n" "географічної облаÑті, поверху, типу тощо.\n" "\n" "У автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ” три оÑновних типи об’єктів: міÑцÑ, карти Ñ– " "ключі.\n" "\n" "МіÑце визначає набір карт, прив’Ñзаних у auto.master. За його допомогою\n" "можна зберігати одразу декілька налаштувань автоматичного монтуваннÑ. МіÑце\n" "Ñаме Ñобою не Ñ” дуже цікавим, це проÑто початок нової карти автоматичного\n" "монтуваннÑ.\n" "\n" "Карта Ñ” наближеним еквівалентом окремого файла автоматичного монтуваннÑ, у\n" "ній зберігаютьÑÑ ÐºÐ»ÑŽÑ‡Ñ–.\n" "\n" "Ключ — точка монтуваннÑ, пов’Ñзана з картою.\n" "\n" "Під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ міÑÑ†Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾ ÑтворюютьÑÑ Ð´Ð²Ñ– карти:\n" "auto.master Ñ– auto.direct. auto.master — коренева карта Ð´Ð»Ñ Ð²ÑÑ–Ñ… карт\n" "автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ñ–ÑцÑ. auto.direct — типова карта Ð´Ð»Ñ " "безпоÑередніх\n" "монтувань, Ñ—Ñ— змонтовано до /-.\n" "\n" "Карта автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ðµ міÑтити ключ підмонтуваннÑ. Цей ключ\n" "визначає адреÑу Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñƒ карті, що поÑилаєтьÑÑ Ð½Ð° іншу карту. Такий " "ключ\n" "може бути додано або за допомогою команди automountmap-add-indirect --" "parentmap\n" "або вручну за допомогою automountkey-add зі вÑтановленнÑм info у значеннÑ\n" "\"-type=autofs :<назва карти>\".\n" "\n" "ПРИКЛÐДИ:\n" "\n" "МіÑцÑ:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ міÑцÑ, \"Kyiv\":\n" " ipa automountlocation-add kyiv\n" "\n" " Показ нового міÑцÑ:\n" " ipa automountlocation-show kyiv\n" "\n" " Пошук доÑтупних міÑць:\n" " ipa automountlocation-find\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñ–Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð¾Ð³Ð¾ міÑÑ†Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ:\n" " ipa automountlocation-del kyiv\n" "\n" " Показ того, Ñк мають виглÑдати карти автоматичного монтуваннÑ, Ñкщо б вони " "перебували у файловій ÑиÑтемі:\n" " ipa automountlocation-tofiles kyiv\n" "\n" " Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¶Ðµ Ñтворених налаштувань до міÑцÑ:\n" " ipa automountlocation-import kyiv /etc/auto.master\n" "\n" " Спроба Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð·Ð½Ð°Ñ” невдачі, Ñкщо буде знайдено дублікати " "запиÑів.\n" " Щоб програма працювала безперервно (з пропуÑканнÑм вÑÑ–Ñ… помилок),\n" " ÑкориÑтайтеÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ --continue.\n" "\n" "Карти:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ°Ñ€Ñ‚Ð¸ \"auto.share\":\n" " ipa automountmap-add kyiv auto.share\n" "\n" " Показ нової карти:\n" " ipa automountmap-show kyiv auto.share\n" "\n" " Пошук карт у міÑці kyiv:\n" " ipa automountmap-find baltimore\n" "\n" " Створити непрÑму карту з auto.share Ñк точкою підмонтуваннÑ:\n" " ipa automountmap-add-indirect baltimore --parentmap=auto.share --" "mount=sub auto.man\n" "\n" " Ð¦Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð° еквівалентна до таких команд:\n" "\n" " ipa automountmap-add-indirect baltimore --mount=/man auto.man\n" " ipa automountkey-add baltimore auto.man --key=sub --info=\"-" "fstype=autofs ldap:auto.share\"\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐ°Ñ€Ñ‚Ð¸ auto.share:\n" " ipa automountmap-del kyiv auto.share\n" "\n" "Ключі:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° Ð´Ð»Ñ ÐºÐ°Ñ€Ñ‚Ð¸ auto.share у міÑці kyiv. Карту буде\n" " пов’Ñзано з раніше Ñтвореною у auto.master:\n" " ipa automountkey-add kyiv auto.master --key=/share --info=auto.share\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° Ð´Ð»Ñ Ð½Ð°ÑˆÐ¾Ñ— карти auto.share, змонтованого реÑурÑу NFS Ð´Ð»Ñ " "Ñторінок man:\n" " ipa automountkey-add kyiv auto.share --key=man --info=\"-ro,soft," "rsize=8192,wsize=8192 ipa.example.com:/shared/man\"\n" "\n" " Знайти вÑÑ– ключі Ð´Ð»Ñ ÐºÐ°Ñ€Ñ‚Ð¸ auto.share:\n" " ipa automountkey-find kyiv auto.share\n" "\n" " Пошук вÑÑ–Ñ… безпоÑередніх ключів автоматичного монтуваннÑ:\n" " ipa automountkey-find kyiv --key=/-\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° man Ð´Ð»Ñ ÐºÐ°Ñ€Ñ‚Ð¸ auto.share:\n" " ipa automountkey-del kyiv auto.share --key=man\n" msgid "automount location" msgstr "Ð·Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ" msgid "automount locations" msgstr "запиÑи автомонтуваннÑ" msgid "Automount Locations" msgstr "ЗапиÑи автомонтуваннÑ" msgid "Automount Location" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ" msgid "Location" msgstr "ЗапиÑ" msgid "Automount location name." msgstr "ÐдреÑа автомонтуваннÑ." msgid "Create a new automount location." msgstr "Створити новий Ð·Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ." #, python-format msgid "Added automount location \"%(value)s\"" msgstr "Додано міÑце автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Delete an automount location." msgstr "Вилучити Ð·Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ." #, python-format msgid "Deleted automount location \"%(value)s\"" msgstr "Вилучено міÑце автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Display an automount location." msgstr "Показати Ð·Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ." msgid "Search for an automount location." msgstr "Шукати Ð·Ð°Ð¿Ð¸Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ." #, python-format msgid "%(count)d automount location matched" msgid_plural "%(count)d automount locations matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d міÑÑ†Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d міÑÑ†Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ монтуваннÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d міÑць автоматичного монтуваннÑ" msgid "Generate automount files for a specific location." msgstr "Створити файли automount Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— адреÑи." msgid "maps not connected to /etc/auto.master:" msgstr "карти, не з’єднані з /etc/auto.master:" msgid "Import automount files for a specific location." msgstr "Імпортувати файли automount Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— адреÑи." msgid "Master file" msgstr "ОÑновний файл" msgid "Automount master file." msgstr "ОÑновний файл automount." msgid "" "Continuous operation mode. Errors are reported but the process continues." msgstr "" "Режим неперервної обробки. Програма повідомлÑÑ” про помилки, але продовжує " "обробку." #, python-format msgid "File %(file)s not found" msgstr "Файла %(file)s не знайдено" #, python-format msgid "key %(key)s already exists" msgstr "Ð·Ð°Ð¿Ð¸Ñ ÐºÐ»ÑŽÑ‡Ð° %(key)s вже Ñ–Ñнує" #, python-format msgid "map %(map)s already exists" msgstr "Ð·Ð°Ð¿Ð¸Ñ ÐºÐ°Ñ€Ñ‚Ð¸ %(map)s вже Ñ–Ñнує" msgid "automount map" msgstr "карта автомонтуваннÑ" msgid "automount maps" msgstr "карти автоматичного монтуваннÑ" msgid "Map" msgstr "Карта" msgid "Automount map name." msgstr "Ðазва карти автоматичного монтуваннÑ." msgid "Automount Maps" msgstr "Карти автоматичного монтуваннÑ" msgid "Automount Map" msgstr "Карта автомонтуваннÑ" msgid "Create a new automount map." msgstr "Створити карту автомонтуваннÑ." #, python-format msgid "Added automount map \"%(value)s\"" msgstr "Додано карту автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Delete an automount map." msgstr "Вилучити карту автоматичного монтуваннÑ." #, python-format msgid "Deleted automount map \"%(value)s\"" msgstr "Вилучено карту автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Modify an automount map." msgstr "Змінити карту автоматичного монтуваннÑ." #, python-format msgid "Modified automount map \"%(value)s\"" msgstr "Змінено карту автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Search for an automount map." msgstr "Виконати пошук карти автоматичного монтуваннÑ." #, python-format msgid "%(count)d automount map matched" msgid_plural "%(count)d automount maps matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d карти автоматичного монтуваннÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d карти автоматичного монтуваннÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d карт автоматичного монтуваннÑ" msgid "Display an automount map." msgstr "Показати карту автоматичного монтуваннÑ." msgid "Automount key object." msgstr "Об’єкт ключа автоматичного монтуваннÑ." msgid "automount key" msgstr "ключ автомонтуваннÑ" msgid "automount keys" msgstr "ключі автомонтуваннÑ" msgid "Key" msgstr "Ключ" msgid "Automount key name." msgstr "Ðазва ключа автоматичного монтуваннÑ." msgid "Mount information" msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ñ‰Ð¾Ð´Ð¾ монтуваннÑ" msgid "description" msgstr "опиÑ" msgid "Automount Keys" msgstr "Ключі автомонтуваннÑ" msgid "Automount Key" msgstr "Ключ автомонтуваннÑ" #, python-format msgid "" "The key,info pair must be unique. A key named %(key)s with info %(info)s " "already exists" msgstr "" "Пара ключ,Ñ–Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð¼Ð°Ñ” бути унікальною. Ключ з назвою %(key)s та " "інформацією %(info)s вже Ñ–Ñнує." #, python-format msgid "key named %(key)s already exists" msgstr "ключ з назвою %(key)s вже Ñ–Ñнує" #, python-format msgid "The automount key %(key)s with info %(info)s does not exist" msgstr "Ключа автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ %(key)s з інформацією %(info)s не Ñ–Ñнує" #, python-format msgid "" "More than one entry with key %(key)s found, use --info to select specific " "entry." msgstr "" "Знайдено декілька запиÑів ключів %(key)s, ÑкориÑтайтеÑÑ --info Ð´Ð»Ñ Ð²Ð¸Ð±Ð¾Ñ€Ñƒ " "певного запиÑу." msgid "Create a new automount key." msgstr "Створити ключ автоматичного монтуваннÑ." #, python-format msgid "Added automount key \"%(value)s\"" msgstr "Додано ключ автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Create a new indirect mount point." msgstr "Створити опоÑередковану точку монтуваннÑ." #, python-format msgid "Added automount indirect map \"%(value)s\"" msgstr "Додано опоÑередковану карту автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Mount point" msgstr "Точка монтуваннÑ" msgid "Parent map" msgstr "БатьківÑька карта" msgid "Name of parent automount map (default: auto.master)." msgstr "" "Ðазва батьківÑької карти Ð°Ð²Ñ‚Ð¾Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ (типове значеннÑ: auto.master)." msgid "mount point is relative to parent map, cannot begin with /" msgstr "" "точка Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÐºÐ°Ð·ÑƒÑ”Ñ‚ÑŒÑÑ Ð²Ñ–Ð´Ð½Ð¾Ñно батьківÑької картки, Ñ—Ñ— Ð·Ð°Ð¿Ð¸Ñ Ð½Ðµ може " "починатиÑÑ Ð· «/»" msgid "Delete an automount key." msgstr "Вилучити ключ автоматичного монтуваннÑ." #, python-format msgid "Deleted automount key \"%(value)s\"" msgstr "Вилучено ключ автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Modify an automount key." msgstr "Змінити ключ автоматичного монтуваннÑ." #, python-format msgid "Modified automount key \"%(value)s\"" msgstr "Змінено ключ автоматичного Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "New mount information" msgstr "Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ монтуваннÑ" msgid "Search for an automount key." msgstr "Виконати пошук ключа автоматичного монтуваннÑ." #, python-format msgid "%(count)d automount key matched" msgid_plural "%(count)d automount keys matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d ключа автоматичного монтуваннÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d ключі автоматичного монтуваннÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d ключів автоматичного монтуваннÑ" msgid "Display an automount key." msgstr "Показати ключ автоматичного монтуваннÑ." msgid "Password" msgstr "Пароль" msgid "Failed members" msgstr "Помилка members" msgid "Member users" msgstr "УчаÑник users" msgid "Member groups" msgstr "УчаÑник groups" msgid "Member of groups" msgstr "УчаÑник груп" msgid "Member hosts" msgstr "УчаÑник hosts" msgid "Member host-groups" msgstr "УчаÑник host-groups" msgid "Member of host-groups" msgstr "УчаÑник host-groups" msgid "Roles" msgstr "Ролі" msgid "Sudo Command Groups" msgstr "Групи команд sudo" msgid "Granting privilege to roles" msgstr "ÐÐ°Ð´Ð°Ð½Ð½Ñ ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½ÑŒ ролÑм" msgid "Member netgroups" msgstr "Мережеві групи учаÑника" msgid "Member of netgroups" msgstr "УчаÑник мережевих груп" msgid "Member services" msgstr "Служби учаÑника" msgid "Member service groups" msgstr "Групи Ñлужб учаÑника" msgid "Member HBAC service" msgstr "Служба HBAC учаÑника" msgid "Member HBAC service groups" msgstr "Групи Ñлужб HBAC учаÑника" msgid "Indirect Member users" msgstr "ОпоÑередковані кориÑтувачі учаÑника" msgid "Indirect Member groups" msgstr "ОпоÑередковані групи учаÑника" msgid "Indirect Member hosts" msgstr "Вузли з опоÑередкованою учаÑтю" msgid "Indirect Member host-groups" msgstr "Групи вузлів з опоÑередкованою учаÑтю" msgid "Indirect Member of roles" msgstr "ОпоÑередкований учаÑник roles" msgid "Indirect Member permissions" msgstr "ОпоÑередковані права доÑтупу учаÑника" msgid "Indirect Member HBAC service" msgstr "ОпоÑередкована Ñлужба HBAC учаÑника" msgid "Indirect Member HBAC service group" msgstr "ОпоÑередкована група Ñлужб HBAC учаÑника" msgid "Indirect Member netgroups" msgstr "ОпоÑередковані мережеві групи учаÑника" msgid "Failed source hosts/hostgroups" msgstr "Помилка hosts/hostgroups джерела" msgid "Failed hosts/hostgroups" msgstr "Помилка hosts/hostgroups" msgid "Failed users/groups" msgstr "Помилка users/groups" msgid "Failed service/service groups" msgstr "Помилки Ñлужб/груп Ñлужб" msgid "Failed to remove" msgstr "Спроба Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð·Ð½Ð°Ð»Ð° невдачі" msgid "Failed RunAs" msgstr "Помилка запуÑку від імені" msgid "Failed RunAsGroup" msgstr "Помилка запуÑку від імені групи" msgid "Invalid format. Should be name=value" msgstr "Ðекоректний формат. Правильний формат: назва=значеннÑ" msgid "External host" msgstr "Зовнішній вузол" msgid "An IPA master host cannot be deleted or disabled" msgstr "ОÑновний вузол IPA не можна вилучати або вимикати" msgid "entry" msgstr "запиÑ" msgid "entries" msgstr "запиÑи" msgid "Entry" msgstr "ЗапиÑ" #, python-format msgid "container entry (%(container)s) not found" msgstr "не знайдено Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð° (%(container)s)" #, python-format msgid "%(parent)s: %(oname)s not found" msgstr "%(parent)s: не знайдено %(oname)s" #, python-format msgid "%(pkey)s: %(oname)s not found" msgstr "%(pkey)s: не знайдено %(oname)s" #, python-format msgid "%(oname)s with name \"%(pkey)s\" already exists" msgstr "%(oname)s з назвою «%(pkey)s» вже Ñ–Ñнує" #, python-format msgid "attribute \"%(attribute)s\" not allowed" msgstr "не можна викориÑтовувати атрибут «%(attribute)s»" msgid "" "Set an attribute to a name/value pair. Format is attr=value.\n" "For multi-valued attributes, the command replaces the values already present." msgstr "" "Ð’Ñтановити атрибут Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¸ назва/значеннÑ. Формат: атрибут=значеннÑ.\n" "Ð”Ð»Ñ Ð°Ñ‚Ñ€Ð¸Ð±ÑƒÑ‚Ñ–Ð² з багатьма значеннÑм команда замінює вже вказані значеннÑ." msgid "" "Add an attribute/value pair. Format is attr=value. The attribute\n" "must be part of the schema." msgstr "" "Додати пару атрибут/значеннÑ. Формат: атрибут=значеннÑ. Ðтрибут має бути\n" "чаÑтиною Ñхеми." msgid "" "Delete an attribute/value pair. The option will be evaluated\n" "last, after all sets and adds." msgstr "" "Вилучити парну атрибут-значеннÑ. Цей параметр буде викориÑтано\n" "оÑтаннім, піÑÐ»Ñ Ð²ÑÑ–Ñ… вÑтановлень Ñ– додавань." msgid "attribute is not configurable" msgstr "атрибут не можна налаштовувати" msgid "No such attribute on this entry" msgstr "У цього запиÑу немає такого атрибута" msgid "Suppress processing of membership attributes." msgstr "Придушити обробку атрибутів учаÑті." msgid "Continuous mode: Don't stop on errors." msgstr "Режим неперервної роботи: не зупинÑтиÑÑ Ñƒ разі помилок." msgid "Rights" msgstr "Права" msgid "" "Display the access rights of this entry (requires --all). See ipa man page " "for details." msgstr "" "Показати права доÑтупу цього запиÑу (потребує --all). Докладніше про це " "можна дізнатиÑÑ Ð·Ñ– Ñторінки довідника (man) ipa." msgid "Rename" msgstr "Перейменувати" #, python-format msgid "Rename the %(ldap_obj_name)s object" msgstr "Перейменувати об’єкт %(ldap_obj_name)s" msgid "the entry was deleted while being modified" msgstr "Ð·Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ»Ð¾ вилучено під Ñ‡Ð°Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½" #, python-format msgid "%s" msgstr "%s" #, python-format msgid "member %s" msgstr "%s учаÑника" #, python-format msgid "%s to add" msgstr "%s Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ" msgid "Members that could not be added" msgstr "УчаÑники, запиÑи Ñких не вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸" msgid "Number of members added" msgstr "КількіÑть доданих учаÑників" #, python-format msgid "%s to remove" msgstr "%s Ð´Ð»Ñ Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ" msgid "Members that could not be removed" msgstr "УчаÑники, запиÑи Ñких не вдалоÑÑ Ð²Ð¸Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸" msgid "Number of members removed" msgstr "КількіÑть вилучених учаÑників" msgid "Primary key only" msgstr "Лише первинний ключ" #, python-format msgid "Results should contain primary key attribute only (\"%s\")" msgstr "Результати мають міÑтити лише атрибут оÑновного ключа («%s»)" #, python-format msgid "" "Search for %(searched_object)s with these %(relationship)s %(ldap_object)s." msgstr "Шукати %(searched_object)s у цих %(relationship)s %(ldap_object)s." #, python-format msgid "" "Search for %(searched_object)s without these %(relationship)s " "%(ldap_object)s." msgstr "Шукати %(searched_object)s не у цих %(relationship)s %(ldap_object)s." msgid "Time Limit" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу" msgid "Time limit of search in seconds" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу пошуку у Ñекундах" msgid "Size Limit" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ€Ñƒ" msgid "Maximum number of entries returned" msgstr "МакÑимальна кількіÑть повернутих запиÑів" msgid "A string searched in all relevant object attributes" msgstr "" "РÑдок, пошук Ñкого відбуватиметьÑÑ Ñƒ вÑÑ–Ñ… відповідних атрибутах об’єктів" msgid "Nested Methods to execute" msgstr "Вкладені методи, Ñкі Ñлід виконати" msgid "" "\n" "IPA certificate operations\n" "\n" "Implements a set of commands for managing server SSL certificates.\n" "\n" "Certificate requests exist in the form of a Certificate Signing Request " "(CSR)\n" "in PEM format.\n" "\n" "The dogtag CA uses just the CN value of the CSR and forces the rest of the\n" "subject to values configured in the server.\n" "\n" "A certificate is stored with a service principal and a service principal\n" "needs a host.\n" "\n" "In order to request a certificate:\n" "\n" "* The host must exist\n" "* The service must exist (or you use the --add option to automatically add " "it)\n" "\n" "SEARCHING:\n" "\n" "Certificates may be searched on by certificate subject, serial number,\n" "revocation reason, validity dates and the issued date.\n" "\n" "When searching on dates the _from date does a >= search and the _to date\n" "does a <= search. When combined these are done as an AND.\n" "\n" "Dates are treated as GMT to match the dates in the certificates.\n" "\n" "The date format is YYYY-mm-dd.\n" "\n" "EXAMPLES:\n" "\n" " Request a new certificate and add the principal:\n" " ipa cert-request --add --principal=HTTP/lion.example.com example.csr\n" "\n" " Retrieve an existing certificate:\n" " ipa cert-show 1032\n" "\n" " Revoke a certificate (see RFC 5280 for reason details):\n" " ipa cert-revoke --revocation-reason=6 1032\n" "\n" " Remove a certificate from revocation hold status:\n" " ipa cert-remove-hold 1032\n" "\n" " Check the status of a signing request:\n" " ipa cert-status 10\n" "\n" " Search for certificates by hostname:\n" " ipa cert-find --subject=ipaserver.example.com\n" "\n" " Search for revoked certificates by reason:\n" " ipa cert-find --revocation-reason=5\n" "\n" " Search for certificates based on issuance date\n" " ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07\n" "\n" "IPA currently immediately issues (or declines) all certificate requests so\n" "the status of a request is not normally useful. This is for future use\n" "or the case where a CA does not immediately issue a certificate.\n" "\n" "The following revocation reasons are supported:\n" "\n" " * 0 - unspecified\n" " * 1 - keyCompromise\n" " * 2 - cACompromise\n" " * 3 - affiliationChanged\n" " * 4 - superseded\n" " * 5 - cessationOfOperation\n" " * 6 - certificateHold\n" " * 8 - removeFromCRL\n" " * 9 - privilegeWithdrawn\n" " * 10 - aACompromise\n" "\n" "Note that reason code 7 is not used. See RFC 5280 for more details:\n" "\n" "http://www.ietf.org/rfc/rfc5280.txt\n" "\n" msgstr "" "\n" "Дії з Ñертифікатами IPA\n" "\n" "Реалізує набір команд Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñертифікатами Ñерверів SSL.\n" "\n" "Запити щодо Ñертифікатів Ñ–Ñнують у формі Certificate Signing Request (CSR)\n" "Ñ– форматі PEM.\n" "\n" "Якщо викориÑтовуєтьÑÑ Ð°Ð²Ñ‚Ð¾Ð¿Ñ–Ð´Ð¿Ð¸Ñний модуль, Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ CSR має збігатиÑÑ\n" "з призначеннÑм на Ñервері. Служба Ñертифікації викориÑтовує лише CN\n" "CSR Ñ– примуÑово визначає призначеннÑ.\n" "\n" "Сертифікат зберігаєтьÑÑ Ð· реєÑтраційним запиÑом, а реєÑтраційний запиÑ\n" "потребує вузла.\n" "\n" "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб Ñтворити запит щодо Ñертифіката:\n" "\n" "* Вузол має Ñ–Ñнувати\n" "* Служба має Ñ–Ñнувати (або Ñлід ÑкориÑтатиÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ --add длÑ\n" "автоматичного додаваннÑ)\n" "\n" "ПОШУК:\n" "\n" "Шукати Ñертифікати можна за призначеннÑм Ñертифіката, Ñерійним номером,\n" "причиною відкликаннÑ, датами чинноÑті та датою виданнÑ.\n" "\n" "Якщо пошук виконуєтьÑÑ Ð·Ð° датою _від, викориÑтовуєтьÑÑ Ð¿Ð¾Ñ€Ñ–Ð²Ð½ÑÐ½Ð½Ñ >=, а " "Ñкщо\n" "виконуєтьÑÑ Ð¿Ð¾ÑˆÑƒÐº _до дати — порівнÑÐ½Ð½Ñ <=. ÐŸÐ¾Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð¾Ð±Ð¾Ñ… пошуків " "призводить\n" "до пошуку з логічним поєднаннÑм ТÐ.\n" "\n" "Дати оброблÑютьÑÑ Ñк дати за Гринвічем, відповідно до дат визначених у\n" "Ñертифікатах.\n" "\n" "Формат дати Ñ” таким: РРРР-мм-дд.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Створити запит щодо нового Ñертифіката Ñ– додати реєÑтраційний запиÑ:\n" " ipa cert-request --add --principal=HTTP/lion.example.com example.csr\n" "\n" " Отримати вже Ñтворений Ñертифікат:\n" " ipa cert-show 1032\n" "\n" " Відкликати Ñертифікат (причини визначено у RFC 5280):\n" " ipa cert-revoke --revocation-reason=6 1032\n" "\n" " Вилучити Ñертифікат зі ÑпиÑку відкликаннÑ:\n" " ipa cert-remove-hold 1032\n" "\n" " Перевірити Ñтан запиту щодо підпиÑуваннÑ:\n" " ipa cert-status 10\n" "\n" " Пошук Ñертифікатів за назвою вузла:\n" " ipa cert-find --subject=ipaserver.example.com\n" "\n" " Пошук відкликаних Ñертифікатів за причиною:\n" " ipa cert-find --revocation-reason=5\n" "\n" " Пошук Ñертифікатів за датою виданнÑ\n" " ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07\n" "\n" "У поточній верÑÑ–Ñ— IPA негайно виконує (або відхилÑÑ”) вÑÑ– запити щодо\n" "Ñертифікатів, отже дані щодо Ñтану запиту не мають ÑенÑу. Ці дані\n" "можуть знадобитиÑÑ Ñƒ наÑтупних верÑÑ–ÑÑ… або у разі, Ñкщо CA видає\n" "Ñертифікат не одразу.\n" "\n" "Передбачено підтримку таких причин відкликаннÑ:\n" "\n" "* 0 - unspecified\n" " * 1 - keyCompromise\n" " * 2 - cACompromise\n" " * 3 - affiliationChanged\n" " * 4 - superseded\n" " * 5 - cessationOfOperation\n" " * 6 - certificateHold\n" " * 8 - removeFromCRL\n" " * 9 - privilegeWithdrawn\n" " * 10 - aACompromise\n" "\n" "Зауважте, що коди причини 7 не викориÑтовуєтьÑÑ. Докладніші дані у RFC " "5280:\n" "\n" "http://www.ietf.org/rfc/rfc5280.txt\n" "\n" msgid "Failure decoding Certificate Signing Request:" msgstr "Помилка під Ñ‡Ð°Ñ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на підпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката (CSR):" msgid "Failure decoding Certificate Signing Request" msgstr "Помилка під Ñ‡Ð°Ñ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на підпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката (CSR)" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "" "Помилка під Ñ‡Ð°Ñ Ð´ÐµÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на підпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката (CSR): %s" msgid "Submit a certificate signing request." msgstr "ÐадіÑлати запит щодо підпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката." msgid "CSR" msgstr "CSR" msgid "Principal" msgstr "РеєÑтраційний запиÑ" msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "" "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Ñлужби Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ñертифіката (наприклад HTTP/test." "example.com)" msgid "automatically add the principal if it doesn't exist" msgstr "автоматично додати реєÑтраційний запиÑ, Ñкщо його не Ñ–Ñнує" msgid "Certificate" msgstr "Сертифікат" msgid "Subject" msgstr "Об’єкт" msgid "Issuer" msgstr "Видавець" msgid "Not Before" msgstr "Ðе раніше" msgid "Not After" msgstr "Ðе пізніше" msgid "Fingerprint (MD5)" msgstr "Відбиток (MD5)" msgid "Fingerprint (SHA1)" msgstr "Відбиток (SHA1)" msgid "Serial number" msgstr "Серійний номер" msgid "Serial number (hex)" msgstr "Серійний номер (шіÑтнадцÑтковий)" msgid "Dictionary mapping variable name to value" msgstr "Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ змінної на Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð° Ñловником" msgid "No hostname was found in subject of request." msgstr "У темі запиту не було знайдено назви вузла." #, python-format msgid "" "hostname in subject of request '%(subject_host)s' does not match principal " "hostname '%(hostname)s'" msgstr "" "назва вузла у призначенні запиту, «%(subject_host)s», не збігаєтьÑÑ Ð· назвою " "вузла реєÑтраційного запиÑу, «%(hostname)s»" msgid "The service principal for this request doesn't exist." msgstr "РеєÑтраційного запиÑу Ñлужби Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ запиту не Ñ–Ñнує." msgid "You need to be a member of the serviceadmin role to add services" msgstr "" "Ð”Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñлужб вам Ñлід мати роль адмініÑтратора Ñлужб (serviceadmin)" #, python-format msgid "" "Insufficient 'write' privilege to the 'userCertificate' attribute of entry " "'%s'." msgstr "" "ÐедоÑтатні права доÑтупу «write» до атрибута «userCertificate» запиÑу «%s»." #, python-format msgid "no host record for subject alt name %s in certificate request" msgstr "" "немає запиÑу вузла Ð´Ð»Ñ Ð°Ð»ÑŒÑ‚ÐµÑ€Ð½Ð°Ñ‚Ð¸Ð²Ð½Ð¾Ñ— назви призначеннÑ, %s, у запиті щодо " "Ñертифікації" #, python-format msgid "" "Insufficient privilege to create a certificate with subject alt name '%s'." msgstr "" "ÐедоÑтатні права доÑтупу Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñертифіката з альтернативною назвою " "Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«%s»." msgid "Check the status of a certificate signing request." msgstr "Перевірити Ñтан запиту щодо підпиÑÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката." msgid "Request id" msgstr "Ід. запиту" msgid "Request status" msgstr "Стан запиту" msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "Серійний деÑÑтковий номер або шіÑтнадцÑтковий номер з префікÑом 0x" msgid "Retrieve an existing certificate." msgstr "Отримати вже Ñтворений Ñертифікат." msgid "Revocation reason" msgstr "Причина відкликаннÑ" msgid "Output filename" msgstr "Ðазва файла виводу" msgid "File to store the certificate in." msgstr "Файл, у Ñкому зберігатимутьÑÑ Ð´Ð°Ð½Ñ– Ñертифіката." msgid "Revoke a certificate." msgstr "Відкликати Ñертифікат." msgid "Revoked" msgstr "Ðнульований" msgid "Reason" msgstr "ПідÑтава" msgid "Reason for revoking the certificate (0-10)" msgstr "Причина Ð²Ñ–Ð´ÐºÐ»Ð¸ÐºÐ°Ð½Ð½Ñ Ñертифіката (0-10)" msgid "7 is not a valid revocation reason" msgstr "7 не Ñ” коректною причиною відкликаннÑ" msgid "Take a revoked certificate off hold." msgstr "Забрати відкликаний Ñертифікат." msgid "Unrevoked" msgstr "Ð’Ñ–Ð´ÐºÐ»Ð¸ÐºÐ°Ð½Ð½Ñ ÑкаÑовано" msgid "Error" msgstr "Помилка" msgid "Search for existing certificates." msgstr "Шукати наÑвні Ñертифікати." msgid "minimum serial number" msgstr "мінімальний Ñерійний номер" msgid "maximum serial number" msgstr "макÑимальний Ñерійний номер" msgid "match the common name exactly" msgstr "повна відповідніÑть загальній назві" msgid "Valid not after from this date (YYYY-mm-dd)" msgstr "Чинний не пізніше, ніж з цієї дати (РРРР-мм-дд)" msgid "Valid not after to this date (YYYY-mm-dd)" msgstr "Чинний не пізніше, ніж до цієї дати (РРРР-мм-дд)" msgid "Valid not before from this date (YYYY-mm-dd)" msgstr "Чинний не раніше від цієї дати (РРРР-мм-дд)" msgid "Valid not before to this date (YYYY-mm-dd)" msgstr "Чинний не раніше цієї дати (РРРР-мм-дд)" msgid "Issued on from this date (YYYY-mm-dd)" msgstr "Видано з цієї дати (РРРР-мм-дд)" msgid "Issued on to this date (YYYY-mm-dd)" msgstr "Видано до цієї дати (РРРР-мм-дд)" msgid "Revoked on from this date (YYYY-mm-dd)" msgstr "Відкликано з цієї дати (РРРР-мм-дд)" msgid "Revoked on to this date (YYYY-mm-dd)" msgstr "Відкликано до цієї дати (РРРР-мм-дд)" msgid "Maximum number of certs returned" msgstr "МакÑимальна кількіÑть Ñертифікатів у повернутому ÑпиÑку" msgid "Status" msgstr "Стан" #, python-format msgid "%(count)d certificate matched" msgid_plural "%(count)d certificates matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d Ñертифіката" msgstr[1] "вÑтановлено відповідніÑть %(count)d Ñертифікатів" msgstr[2] "вÑтановлено відповідніÑть %(count)d Ñертифікатів" msgid "" "\n" "Server configuration\n" "\n" "Manage the default values that IPA uses and some of its tuning parameters.\n" "\n" "NOTES:\n" "\n" "The password notification value (--pwdexpnotify) is stored here so it will\n" "be replicated. It is not currently used to notify users in advance of an\n" "expiring password.\n" "\n" "Some attributes are read-only, provided only for information purposes. " "These\n" "include:\n" "\n" "Certificate Subject base: the configured certificate subject base,\n" " e.g. O=EXAMPLE.COM. This is configurable only at install time.\n" "Password plug-in features: currently defines additional hashes that the\n" " password will generate (there may be other conditions).\n" "\n" "When setting the order list for mapping SELinux users you may need to\n" "quote the value so it isn't interpreted by the shell.\n" "\n" "EXAMPLES:\n" "\n" " Show basic server configuration:\n" " ipa config-show\n" "\n" " Show all configuration options:\n" " ipa config-show --all\n" "\n" " Change maximum username length to 99 characters:\n" " ipa config-mod --maxusername=99\n" "\n" " Increase default time and size limits for maximum IPA server search:\n" " ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000\n" "\n" " Set default user e-mail domain:\n" " ipa config-mod --emaildomain=example.com\n" "\n" " Enable migration mode to make \"ipa migrate-ds\" command operational:\n" " ipa config-mod --enable-migration=TRUE\n" "\n" " Define SELinux user map order:\n" " ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-" "s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'\n" msgstr "" "\n" "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñервера\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¸Ð¼Ð¸ значеннÑми, Ñкі викориÑтовує IPA, та деÑкими з\n" "придатних до зміни параметрів.\n" "\n" "ЗÐУВÐЖЕÐÐЯ:\n" "\n" "Тут зберігаєтьÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ паролів\n" "(--pwdexpnotify), отже його не буде Ñкопійовано. Це Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð¾ÐºÐ¸ що\n" "не викориÑтовуєтьÑÑ Ð´Ð»Ñ ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів щодо Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñтроку дії\n" "паролÑ.\n" "\n" "ДеÑкі з атрибутів придатні лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ, Ñ—Ñ… буде показано лише з метою\n" "інформуваннÑ. Серед цих атрибутів:\n" "\n" "ОÑнова Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñертифіката: змінна оÑнова Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñертифіката,\n" " наприклад O=EXAMPLE.COM. Цей атрибут можна налаштувати лише під чаÑ\n" " вÑтановленнÑ.\n" "Параметри додатка роботи з паролÑми: у поточній верÑÑ–Ñ— визначають додаткові\n" " хеші, Ñкі ÑтворюютьÑÑ Ð½Ð° оÑнові Ð¿Ð°Ñ€Ð¾Ð»Ñ (можуть бути Ñ– інші умови).\n" "\n" "Під Ñ‡Ð°Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑпиÑку пріоритетноÑті Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів SELinux може " "виникнути\n" "потреба у додаванні лапок до значеннÑ, щоб оболонка не оброблÑла параметр.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Показати оÑновні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñервера:\n" " ipa config-show\n" "\n" " Показати вÑÑ– параметри налаштуваннÑ:\n" " ipa config-show --all\n" "\n" " Змінити макÑимальну довжину імені кориÑтувача на 99 Ñимволів:\n" " ipa config-mod --maxusername=99\n" "\n" " Збільшити типовий Ñ‡Ð°Ñ Ñ– макÑимальне Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° розмір пошуку\n" " Ñервера IPA:\n" " ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000\n" "\n" " Ð’Ñтановити типовий домен електронної пошти кориÑтувачів:\n" " ipa config-mod --emaildomain=example.com\n" "\n" " Увімкнути режим перенеÑеннÑ, щоб зробити команду \"ipa migrate-ds\"\n" " працездатною:\n" " ipa config-mod --enable-migration=TRUE\n" "\n" " Визначити пріоритетніÑть кориÑтувачів у карті SELinux:\n" " ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-" "s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'\n" msgid "searchtimelimit must be -1 or > 1." msgstr "searchtimelimit повинен мати Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ -1 або > 1." msgid "configuration options" msgstr "параметри налаштуваннÑ" msgid "Configuration" msgstr "ÐалаштуваннÑ" msgid "Maximum username length" msgstr "МакÑимальна довжина імені кориÑтувача" msgid "Home directory base" msgstr "ÐдреÑа домашніх каталогів" msgid "Default location of home directories" msgstr "Типова адреÑа домашніх каталогів" msgid "Default shell" msgstr "Типова оболонка" msgid "Default shell for new users" msgstr "Типова оболонка Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… кориÑтувачів" msgid "Default users group" msgstr "Типова група кориÑтувачів" msgid "Default group for new users" msgstr "Типова група Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… кориÑтувачів" msgid "Default e-mail domain" msgstr "Типовий домен ел. пошти" msgid "Search time limit" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу пошуку" msgid "" "Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)" msgstr "" "МакÑимальний проміжок чаÑу (у Ñекундах) Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¾Ð´Ð½Ñ–Ñ”Ñ— дії з пошуку " "(>0, -1 — без обмежень)" msgid "Search size limit" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ€Ñƒ пошуку" msgid "Maximum number of records to search (-1 is unlimited)" msgstr "МакÑимальна кількіÑть запиÑів результатів пошуку (-1 — без обмежень)" msgid "User search fields" msgstr "ÐŸÐ¾Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ кориÑтувачів" msgid "A comma-separated list of fields to search in when searching for users" msgstr "" "Відокремлений комами ÑпиÑок полів, за Ñкими виконуватиметьÑÑ Ð¿Ð¾ÑˆÑƒÐº " "кориÑтувачів" msgid "A comma-separated list of fields to search in when searching for groups" msgstr "" "Відокремлений комами ÑпиÑок полів, за Ñкими виконуватиметьÑÑ Ð¿Ð¾ÑˆÑƒÐº груп" msgid "Enable migration mode" msgstr "Увімкнути режим міграції" msgid "Certificate Subject base" msgstr "Базовий об’єкт Ñертифікації" msgid "Base for certificate subjects (OU=Test,O=Example)" msgstr "ОÑнова Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів об’єктів Ñертифікації (OU=Test,O=Example)" msgid "Default group objectclasses" msgstr "Типові клаÑи об’єктів групи" msgid "Default group objectclasses (comma-separated list)" msgstr "Типові клаÑи об’єктів груп (ÑпиÑок клаÑів, відокремлених комами)" msgid "Default user objectclasses" msgstr "Типові клаÑи об’єктів кориÑтувачів" msgid "Default user objectclasses (comma-separated list)" msgstr "" "Типові клаÑи об’єктів кориÑтувачів (ÑпиÑок клаÑів, відокремлених комами)" msgid "Password Expiration Notification (days)" msgstr "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ Ð²Ð¸Ñ‡ÐµÑ€Ð¿Ð°Ð½Ð½Ñ Ñтроку дії Ð¿Ð°Ñ€Ð¾Ð»Ñ (у днÑÑ…)" msgid "Number of days's notice of impending password expiration" msgstr "" "Ð¡Ð¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ кількіÑть днів, Ñкі залишилиÑÑ Ð´Ð¾ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð´Ñ–Ñ— паролÑ." msgid "Password plugin features" msgstr "МожливоÑті додатка паролів" msgid "Extra hashes to generate in password plug-in" msgstr "Додаткові хеші Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñƒ додатку паролів." msgid "SELinux user map order" msgstr "ПорÑдок карт кориÑтувачів SELinux" msgid "Order in increasing priority of SELinux users, delimited by $" msgstr "" "ПорÑдок у збільшенні пріоритетноÑті кориÑтувачів SELinux, відокремлений $" msgid "Default SELinux user" msgstr "Типовий кориÑтувач SELinux" msgid "Default SELinux user when no match is found in SELinux map rule" msgstr "" "Типовий кориÑтувач SELinux, Ñкщо не буде знайдено відповідного у правилі " "карти SELinux" msgid "Default PAC types" msgstr "Типові типи PAC" msgid "Default types of PAC supported for services" msgstr "Типові типи PAC, підтримувані Ð´Ð»Ñ Ñлужб" msgid "Modify configuration options." msgstr "Змінити параметри налаштуваннÑ." msgid "The group doesn't exist" msgstr "Такої групи не Ñ–Ñнує" #, python-format msgid "attribute \"%s\" not allowed" msgstr "не можна викориÑтовувати атрибут «%s»" msgid "May not be empty" msgstr "Ðе може бути порожнім" #, python-format msgid "%(obj)s default attribute %(attr)s would not be allowed!" msgstr "Типовий атрибут %(obj)s, %(attr)s, не буде дозволено!" msgid "A list of SELinux users delimited by $ expected" msgstr "" "Мало бути вказано ÑпиÑок кориÑтувачів SELinux, запиÑи Ñкого відокремлено " "Ñимволом $" #, python-format msgid "SELinux user '%(user)s' is not valid: %(error)s" msgstr "КориÑтувач SELinux «%(user)s» Ñ” некоректним: %(error)s" msgid "SELinux user map default user not in order list" msgstr "" "Типового кориÑтувача типової карти кориÑтувачів SELinux немає у порÑдковому " "ÑпиÑку" msgid "Show the current configuration." msgstr "Показати поточні налаштуваннÑ." msgid "" "\n" "Group to Group Delegation\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "Group to Group Delegations grants the members of one group to update a set\n" "of attributes of members of another group.\n" "\n" "EXAMPLES:\n" "\n" " Add a delegation rule to allow managers to edit employee's addresses:\n" " ipa delegation-add --attrs=street --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones. Add postalCode to the list:\n" " ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " Display our updated rule:\n" " ipa delegation-show \"managers edit employees' street\"\n" "\n" " Delete a rule:\n" " ipa delegation-del \"managers edit employees' street\"\n" msgstr "" "\n" "Міжгрупове уповноваженнÑ\n" "\n" "Права доÑтупу може бути точно налаштовано. Правила ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом\n" "або інÑтрукції (ACI), Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ð·Ð²Ð¾Ð»Ñƒ на Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… завдань, зокрема\n" "Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача, внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до групи тощо.\n" "\n" "Міжгрупові ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ð°Ð´Ð°ÑŽÑ‚ÑŒ учаÑникам однієї групи можливіÑть\n" "оновлювати набір атрибутів учаÑників іншої групи.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Додати правило уповноваженнÑ, Ñке надаÑть змогу керівникам (managers)\n" " редагувати адреÑи Ñпівробітників:\n" " ipa delegation-add --attrs=street --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " Під Ñ‡Ð°Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑпиÑком атрибутів Ñлід включати вÑÑ– атрибути ÑпиÑку\n" " разом з вже Ñтвореними. Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð¾ ÑпиÑку postalCode:\n" " ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " Показ нашого оновленого правила:\n" " ipa delegation-show \"managers edit employees' street\"\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°:\n" " ipa delegation-del \"managers edit employees' street\"\n" msgid "delegation" msgstr "уповноваженнÑ" msgid "delegations" msgstr "уповноваженнÑ" msgid "Delegations" msgstr "УповноваженнÑ" msgid "Delegation" msgstr "УповноваженнÑ" msgid "Delegation name" msgstr "Ðазва уповноваженнÑ" msgid "Permissions to grant (read, write). Default is write." msgstr "" "Права доÑтупу, Ñкі Ñлід надати (read, write). Типовими Ñ” права доÑтупу write." msgid "Attributes to which the delegation applies" msgstr "Ðтрибути, до Ñких заÑтоÑовуєтьÑÑ ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ" msgid "Member user group" msgstr "УчаÑник групи кориÑтувачів" msgid "User group to apply delegation to" msgstr "Група кориÑтувачів, до Ñкої Ñлід заÑтоÑувати уповноваженнÑ" msgid "Add a new delegation." msgstr "Додати нове уповноваженнÑ." #, python-format msgid "Added delegation \"%(value)s\"" msgstr "Додано ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Delete a delegation." msgstr "Вилучити уповноваженнÑ." #, python-format msgid "Deleted delegation \"%(value)s\"" msgstr "Вилучено ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Modify a delegation." msgstr "Змінити уповноваженнÑ." #, python-format msgid "Modified delegation \"%(value)s\"" msgstr "Змінено ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Search for delegations." msgstr "Пошук уповноважень." #, python-format msgid "%(count)d delegation matched" msgid_plural "%(count)d delegations matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d уповноваженнÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d уповноваженнÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d уповноважень" msgid "Display information about a delegation." msgstr "Показати дані щодо уповноваженнÑ." msgid "" "\n" "Domain Name System (DNS)\n" "\n" "Manage DNS zone and resource records.\n" "\n" "\n" "USING STRUCTURED PER-TYPE OPTIONS\n" "\n" "There are many structured DNS RR types where DNS data stored in LDAP server\n" "is not just a scalar value, for example an IP address or a domain name, but\n" "a data structure which may be often complex. A good example is a LOC record\n" "[RFC1876] which consists of many mandatory and optional parts (degrees,\n" "minutes, seconds of latitude and longitude, altitude or precision).\n" "\n" "It may be difficult to manipulate such DNS records without making a mistake\n" "and entering an invalid value. DNS module provides an abstraction over " "these\n" "raw records and allows to manipulate each RR type with specific options. " "For\n" "each supported RR type, DNS module provides a standard option to manipulate\n" "a raw records with format ---rec, e.g. --mx-rec, and special " "options\n" "for every part of the RR structure with format ---, e.g.\n" "--mx-preference and --mx-exchanger.\n" "\n" "When adding a record, either RR specific options or standard option for a " "raw\n" "value can be used, they just should not be combined in one add operation. " "When\n" "modifying an existing entry, new RR specific options can be used to change\n" "one part of a DNS record, where the standard option for raw value is used\n" "to specify the modified value. The following example demonstrates\n" "a modification of MX record preference from 0 to 1 in a record without\n" "modifying the exchanger:\n" "ipa dnsrecord-mod --mx-rec=\"0 mx.example.com.\" --mx-preference=1\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add new zone:\n" " ipa dnszone-add example.com --name-server=ns \\\n" " --admin-email=admin@example.com \\\n" " --ip-address=10.0.0.1\n" "\n" " Add system permission that can be used for per-zone privilege delegation:\n" " ipa dnszone-add-permission example.com\n" "\n" " Modify the zone to allow dynamic updates for hosts own records in realm " "EXAMPLE.COM:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE\n" "\n" " This is the equivalent of:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " --update-policy=\"grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM " "krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;\"\n" "\n" " Modify the zone to allow zone transfers for local network only:\n" " ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8\n" "\n" " Add new reverse zone specified by network IP address:\n" " ipa dnszone-add --name-from-ip=80.142.15.0/24 \\\n" " --name-server=ns.example.com.\n" "\n" " Add second nameserver for example.com:\n" " ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com\n" "\n" " Add a mail server for example.com:\n" " ipa dnsrecord-add example.com @ --mx-rec=\"10 mail1\"\n" "\n" " Add another record using MX record specific options:\n" " ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2\n" "\n" " Add another record using interactive mode (started when dnsrecord-add, " "dnsrecord-mod,\n" " or dnsrecord-del are executed with no options):\n" " ipa dnsrecord-add example.com @\n" " Please choose a type of DNS resource record to be added\n" " The most common types for this type of zone are: NS, MX, LOC\n" "\n" " DNS resource record type: MX\n" " MX Preference: 30\n" " MX Exchanger: mail3\n" " Record name: example.com\n" " MX record: 10 mail1, 20 mail2, 30 mail3\n" " NS record: nameserver.example.com., nameserver2.example.com.\n" "\n" " Delete previously added nameserver from example.com:\n" " ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com.\n" "\n" " Add LOC record for example.com:\n" " ipa dnsrecord-add example.com @ --loc-rec=\"49 11 42.4 N 16 36 29.6 E " "227.64m\"\n" "\n" " Add new A record for www.example.com. Create a reverse record in " "appropriate\n" " reverse zone as well. In this case a PTR record \"2\" pointing to www." "example.com\n" " will be created in zone 15.142.80.in-addr.arpa.\n" " ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse\n" "\n" " Add new PTR record for www.example.com\n" " ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com.\n" "\n" " Add new SRV records for LDAP servers. Three quarters of the requests\n" " should go to fast.example.com, one quarter to slow.example.com. If neither\n" " is available, switch to backup.example.com.\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 3 389 fast.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 1 389 slow.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"1 1 389 backup." "example.com\"\n" "\n" " The interactive mode can be used for easy modification:\n" " ipa dnsrecord-mod example.com _ldap._tcp\n" " No option to modify specific record provided.\n" " Current DNS record contents:\n" "\n" " SRV record: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 " "backup.example.com\n" "\n" " Modify SRV record '0 3 389 fast.example.com'? Yes/No (default No):\n" " Modify SRV record '0 1 389 slow.example.com'? Yes/No (default No): y\n" " SRV Priority [0]: (keep the default value)\n" " SRV Weight [1]: 2 (modified value)\n" " SRV Port [389]: (keep the default value)\n" " SRV Target [slow.example.com]: (keep the default value)\n" " 1 SRV record skipped. Only one value per DNS record type can be modified " "at one time.\n" " Record name: _ldap._tcp\n" " SRV record: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 " "389 slow.example.com\n" "\n" " After this modification, three fifths of the requests should go to\n" " fast.example.com and two fifths to slow.example.com.\n" "\n" " An example of the interactive mode for dnsrecord-del command:\n" " ipa dnsrecord-del example.com www\n" " No option to delete specific record provided.\n" " Delete all? Yes/No (default No): (do not delete all records)\n" " Current DNS record contents:\n" "\n" " A record: 1.2.3.4, 11.22.33.44\n" "\n" " Delete A record '1.2.3.4'? Yes/No (default No):\n" " Delete A record '11.22.33.44'? Yes/No (default No): y\n" " Record name: www\n" " A record: 1.2.3.4 (A record 11.22.33.44 has been " "deleted)\n" "\n" " Show zone example.com:\n" " ipa dnszone-show example.com\n" "\n" " Find zone with \"example\" in its domain name:\n" " ipa dnszone-find example\n" "\n" " Find records for resources with \"www\" in their name in zone example.com:\n" " ipa dnsrecord-find example.com www\n" "\n" " Find A records with value 10.10.0.1 in zone example.com\n" " ipa dnsrecord-find example.com --a-rec=10.10.0.1\n" "\n" " Show records for resource www in zone example.com\n" " ipa dnsrecord-show example.com www\n" "\n" " Delegate zone sub.example to another nameserver:\n" " ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5\n" " ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com.\n" "\n" " If global forwarder is configured, all requests to sub.example.com will be\n" " routed through the global forwarder. To change the behavior for example." "com\n" " zone only and forward the request directly to ns.sub.example.com., global\n" " forwarding may be disabled per-zone:\n" " ipa dnszone-mod example.com --forward-policy=none\n" "\n" " Forward all requests for the zone external.com to another nameserver using\n" " a \"first\" policy (it will send the queries to the selected forwarder and " "if\n" " not answered it will use global resolvers):\n" " ipa dnszone-add external.com\n" " ipa dnszone-mod external.com --forwarder=10.20.0.1 \\\n" " --forward-policy=first\n" "\n" " Delete zone example.com with all resource records:\n" " ipa dnszone-del example.com\n" "\n" " Resolve a host name to see if it exists (will add default IPA domain\n" " if one is not included):\n" " ipa dns-resolve www.example.com\n" " ipa dns-resolve www\n" "\n" "\n" "GLOBAL DNS CONFIGURATION\n" "\n" "DNS configuration passed to command line install script is stored in a " "local\n" "configuration file on each IPA server where DNS service is configured. " "These\n" "local settings can be overridden with a common configuration stored in LDAP\n" "server:\n" "\n" " Show global DNS configuration:\n" " ipa dnsconfig-show\n" "\n" " Modify global DNS configuration and set a list of global forwarders:\n" " ipa dnsconfig-mod --forwarder=10.0.0.1\n" msgstr "" "\n" "СиÑтема доменних назв (DNS)\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¾Ð½Ð¾ÑŽ Ñ– запиÑами реÑурÑів DNS.\n" "\n" "\n" "ВИКОРИСТÐÐÐЯ СТРУКТУРОВÐÐИХ ПÐРÐМЕТРІВ, ОКРЕМИХ ДЛЯ ТИПУ\n" "\n" "ІÑнує багато Ñтруктурованих типів RR DNS, Ð´Ð»Ñ Ñких дані DNS, що " "зберігаютьÑÑ\n" "на Ñервері LDAP, не Ñ” проÑто ÑкалÑрними величинами, наприклад IP-адреÑа або\n" "назва домену, але Ñтруктурами даних, Ñкі чаÑто Ñ” доволі Ñкладними. Чудовим\n" "прикладом Ñ” Ð·Ð°Ð¿Ð¸Ñ LOC [RFC1876], Ñкий ÑкладаєтьÑÑ Ð· багатьох обов’Ñзкових " "та\n" "додаткових чаÑтин (градуÑів, мінут, Ñекунд широти Ñ– довготи, виÑоти або\n" "точноÑті).\n" "\n" "Працювати з такими запиÑами DNS без помилок або Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½ÐµÐºÐ¾Ñ€ÐµÐºÑ‚Ð½Ð¾Ð³Ð¾ " "значеннÑ\n" "доволі Ñкладно. Модуль DNS надає рівень абÑтракції над цими необробленими\n" "запиÑами Ñ– дозволÑÑ” працювати з кожним типом RR зі Ñпецифічними " "параметрами.\n" "Ð”Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ з підтримуваних типів RR модуль DNS надає Ñтандартний параметр\n" "Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¸Ð¼Ð¸ запиÑами у форматі --<тип-rr>-rec, наприклад --" "mx-rec,\n" "Ñ– окремі параметри Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ñ— з чаÑтин Ñтруктури RR у форматі\n" "--<тип-rr>-<назва-чаÑтини>, наприклад --mx-preference Ñ– --mx-exchanger.\n" "\n" "Під Ñ‡Ð°Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу можна викориÑтовувати Ñпецифічні Ð´Ð»Ñ RR параметри\n" "або Ñтандартний параметр Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¾Ð³Ð¾ значеннÑ, але Ñ—Ñ… не можна " "поєднувати\n" "у одній дії з додаваннÑ. Під Ñ‡Ð°Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до вже Ñтвореного запиÑу " "можна\n" "викориÑтовувати нові Ñпецифічні параметри RR Ð´Ð»Ñ Ð·Ð¼Ñ–Ð½Ð¸ однієї чаÑтини запиÑу " "DNS,\n" "де Ñтандартний параметр Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ñ€Ð¾Ð±Ð»ÐµÐ½Ð¾Ð³Ð¾ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтовуєтьÑÑ Ð´Ð»Ñ " "визначеннÑ\n" "зміненого значеннÑ. У наведеному нижче прикладі продемонÑтровано внеÑÐµÐ½Ð½Ñ " "змін до\n" "запиÑу MX з 0 на 1 у запиÑÑ– без внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до обмінника:\n" "ipa dnsrecord-mod --mx-rec=\"0 mx.example.com.\" --mx-preference=1\n" "\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— зони:\n" " ipa dnszone-add example.com --name-server=ns \\\n" " --admin-email=admin@example.com \\\n" " --ip-address=10.0.0.1\n" "\n" " Змінити зону з метою дозволити динамічні Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ð»Ð°Ñних запиÑів " "вузлів у облаÑті EXAMPLE.COM:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " \n" " Це рівнозначно до такої команди:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " --update-policy=\"grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM " "krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;\"\n" "\n" " Зміна зони з метою дозволити перенеÑÐµÐ½Ð½Ñ Ð·Ð¾Ð½ лише Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¸Ñ… мереж:\n" " ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— зворотної зони, вказаної за IP-адреÑою у мережі:\n" " ipa dnszone-add --name-from-ip 80.142.15.0/24\n" " --name-server nameserver.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð³Ð¾ Ñервера назв Ð´Ð»Ñ example.com:\n" " ipa dnsrecord-add example.com @ --ns-rec nameserver2.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ð¾ÑˆÑ‚Ð¾Ð²Ð¾Ð³Ð¾ Ñервера Ð´Ð»Ñ example.com:\n" " ipa dnsrecord-add example.com @ --mx-rec=\"10 mail1\"\n" "\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½ÑˆÐ¾Ð³Ð¾ запиÑу за викориÑтаннÑм Ñпецифічних параметрів MX:\n" " ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñ–Ð½ÑˆÐ¾Ð³Ð¾ запиÑу з викориÑтаннÑм інтерактивного режиму " "(розпочинаєтьÑÑ Ð¿Ñ–ÑлÑ\n" " Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ dnsrecord-add, dnsrecord-mod або dnsrecord-del запуÑкаютьÑÑ Ð±ÐµÐ· " "параметрів):\n" " ipa dnsrecord-add example.com @\n" " Будь лаÑка, виберіть тип запиÑу реÑурÑу DNS, Ñкий Ñлід додати\n" " Ðайпоширенішими Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу зон Ñ”: NS, MX, LOC\n" "\n" " Тип запиÑу реÑурÑу DNS: MX\n" " ПріоритетніÑть MX: 30\n" " Обмінник MX: mail3\n" " Ðазва запиÑу: example.com\n" " Ð—Ð°Ð¿Ð¸Ñ MX: 10 mail1, 20 mail2, 30 mail3\n" " Ð—Ð°Ð¿Ð¸Ñ NS: nameserver.example.com., nameserver2.example.com.\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾ доданого Ñервера назв з example.com:\n" " ipa dnsrecord-del example.com @ --ns-rec nameserver2.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ LOC Ð´Ð»Ñ example.com:\n" " ipa dnsrecord-add example.com @ --loc-rec=\"49 11 42.4 N 16 36 29.6 E " "227.64m\"\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ запиÑу A Ð´Ð»Ñ www.example.com. Також буде Ñтворено " "зворотний\n" " Ð·Ð°Ð¿Ð¸Ñ Ñƒ зворотній зоні. У цьому випадку Ð·Ð°Ð¿Ð¸Ñ PTR «2», що вказує на www." "example.com,\n" " буде Ñтворено у зоні 15.142.80.in-addr.arpa.\n" " ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ запиÑу PTR Ð´Ð»Ñ www.example.com\n" " ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec www.example.com.\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… запиÑів SRV Ð´Ð»Ñ Ñерверів LDAP. Три чвертини запитів\n" " має бути надіÑлано на fast.example.com, одну чвертину — slow.example.com.\n" " Якщо жодне з них не буде доÑтупним, перемкнутиÑÑ Ð½Ð° backup.example.com.\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 3 389 fast.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 1 389 slow.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"1 1 389 backup." "example.com\"\n" "\n" " Інтерактивним режимом можна ÑкориÑтатиÑÑ Ð´Ð»Ñ ÑÐ¿Ñ€Ð¾Ñ‰ÐµÐ½Ð½Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½:\n" " ipa dnsrecord-mod example.com _ldap._tcp\n" " Ðе вказано параметри Ð´Ð»Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до певного запиÑу.\n" " ВміÑÑ‚ поточного запиÑу DNS:\n" "\n" " Ð—Ð°Ð¿Ð¸Ñ SRV: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 " "backup.example.com\n" "\n" " Змінити Ð·Ð°Ð¿Ð¸Ñ SRV '0 3 389 fast.example.com'? Так/ÐÑ– (типово «Ðі»): \n" " Змінити Ð·Ð°Ð¿Ð¸Ñ SRV '0 1 389 slow.example.com'? Так/ÐÑ– (типово «Ðі»): y\n" " ПріоритетніÑть SRV [0]: (зберегти типове значеннÑ)\n" " Ваги SRV [1]: 2 (змінене значеннÑ)\n" " Порт SRV [389]: (зберегти типове значеннÑ)\n" " ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ SRV [slow.example.com]: (зберегти типове значеннÑ)\n" " 1 Ð·Ð°Ð¿Ð¸Ñ SRV пропущено. ОдночаÑно можна змінювати лише одне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð° тип " "запиÑу DNS.\n" " Ðазва запиÑу: _ldap._tcp\n" " Ð—Ð°Ð¿Ð¸Ñ SRV: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 389 " "slow.example.com\n" "\n" " ПіÑÐ»Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ñ†Ð¸Ñ… змін, три п’Ñтих запитів ÑпрÑмовуватиметьÑÑ Ð´Ð¾,\n" " fast.example.com, а дві п’Ñтих — до slow.example.com.\n" "\n" " Приклад інтерактивного режиму Ð´Ð»Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸ dnsrecord-del:\n" " ipa dnsrecord-del example.com www\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… реÑурÑів не передбачено.\n" " Вилучити вÑÑ–? Так/ÐÑ– (типово «Ðі»): (не вилучати вÑÑ– запиÑи)\n" " Поточний вміÑÑ‚ запиÑу DNS:\n" "\n" " Ð·Ð°Ð¿Ð¸Ñ A: 1.2.3.4, 11.22.33.44\n" "\n" " Вилучити Ð·Ð°Ð¿Ð¸Ñ A «1.2.3.4»? Так/ÐÑ– (типово «Ðі»):\n" " Вилучити Ð·Ð°Ð¿Ð¸Ñ A «11.22.33.44»? Так/ÐÑ– (типово «Ðі»): y\n" " Ðазва запиÑу: www\n" " Ð—Ð°Ð¿Ð¸Ñ A: 1.2.3.4 (Ð·Ð°Ð¿Ð¸Ñ A 11.22.33.44 було вилучено)\n" "\n" " Показ зони example.com:\n" " ipa dnszone-show example.com\n" "\n" " Пошук зони з Ñ€Ñдком «example» у назві домену:\n" " ipa dnszone-find example\n" "\n" " Пошук запиÑів Ð´Ð»Ñ Ñ€ÐµÑурÑів з Ñ€Ñдком «www» у назві у зоні example.com:\n" " ipa dnsrecord-find example.com www\n" "\n" " Знайти запиÑи A зі значеннÑм 10.10.0.1 у зоні example.com\n" " ipa dnsrecord-find example.com --a-rec 10.10.0.1\n" "\n" " Показ запиÑів Ð´Ð»Ñ Ñ€ÐµÑурÑу www у зоні example.com\n" " ipa dnsrecord-show example.com www\n" "\n" " Уповноважити на зону sub.example інший Ñервер назв:\n" " ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5\n" " ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com.\n" "\n" " Якщо налаштовано переÑпрÑÐ¼Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° загальному рівні, вÑÑ– запити до\n" " sub.example.com буде передано переÑпрÑмовувачу загального рівнÑ. Щоб " "змінити\n" " таку поведінку лише Ð´Ð»Ñ Ð·Ð¾Ñ€Ð¸ example.com Ñ– переÑпрÑмувати запит " "безпоÑередньо\n" " до ns.sub.example.com., можна вимкнути загальне переÑпрÑÐ¼Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ " "окремої\n" " зони:\n" " ipa dnszone-mod example.com --forward-policy=none\n" "\n" " СпрÑмовувати вÑÑ– запити Ð´Ð»Ñ Ð·Ð¾Ð½Ð¸ external.com на інший Ñервер назв з\n" " викориÑтаннÑм правил «first» (запити буде ÑпрÑмовано на вибраний\n" " переÑпрÑмовувач, Ñкщо він не відповіÑть, буде викориÑтано загальні " "розв’Ñзувачі):\n" " ipa dnszone-add external.com\n" " ipa dnszone-mod external.com --forwarder=10.20.0.1 \\\n" " --forward-policy=first\n" "\n" " Вилучити зону example.com з уÑіма запиÑами реÑурÑів:\n" " ipa dnszone-del example.com\n" "\n" " Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ вузла з метою перевірки, чи Ñ–Ñнує вузол (додаваннÑ\n" " типового домену IPA, Ñкщо його не включено):\n" " ipa dns-resolve www.example.com\n" " ipa dns-resolve www\n" "\n" "\n" "ЗÐГÐЛЬÐІ ÐÐЛÐШТУВÐÐÐЯ DNS\n" "\n" "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS, що передаютьÑÑ Ñкрипту вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð· командного Ñ€Ñдка,\n" "зберігаютьÑÑ Ñƒ локальному файлі налаштувань на кожному з Ñерверів IPA, де\n" "налаштовано Ñлужбу DNS. Ці локальні параметри може бути перевизначено за\n" "допомогою загальних налаштувань, що зберігаютьÑÑ Ð½Ð° Ñервері LDAP:\n" "\n" " Показати загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS:\n" " ipa dnsconfig-show\n" "\n" " Змінити загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS Ñ– вÑтановити ÑпиÑок загальних\n" " переÑпрÑмовувачів:\n" " ipa dnsconfig-mod --forwarder=10.0.0.1\n" #, python-format msgid "invalid IP address version (is %(value)d, must be %(required_value)d)!" msgstr "" "некоректна верÑÑ–Ñ IP-адреÑи (маємо: %(value)d, має бути: %(required_value)d)!" msgid "invalid IP address format" msgstr "некоректний формат запиÑу IP-адреÑи" msgid "invalid IP network format" msgstr "некоректний формат запиÑу мережі IP" msgid "each ACL element must be terminated with a semicolon" msgstr "кожен з елементів ACL має бути відокремлено від інших крапкою з комою" msgid "invalid address format" msgstr "некоректний формат адреÑи" #, python-format msgid "invalid domain-name: %s" msgstr "некоректна назва домену: %s" #, python-format msgid "%(port)s is not a valid port" msgstr "%(port)s не Ñ” чинним портом" #, python-format msgid "DNS reverse zone for IP address %(addr)s not found" msgstr "Зворотної зони DNS Ð´Ð»Ñ IP-адреÑи %(addr)s не знайдено" #, python-format msgid "DNS zone %(zone)s not found" msgstr "Зони DNS %(zone)s не знайдено" #, python-format msgid "IP address %(ip)s is already assigned in domain %(domain)s." msgstr "IP-адреÑу %(ip)s вже призначено у домені %(domain)s." #, python-format msgid "" "Reverse record for IP address %(ip)s already exists in reverse zone %(zone)s." msgstr "" "Зворотний Ð·Ð°Ð¿Ð¸Ñ Ð´Ð»Ñ IP-адреÑи %(ip)s вже Ñ–Ñнує у зворотній зоні %(zone)s." #, python-format msgid "%s record" msgstr "Ð—Ð°Ð¿Ð¸Ñ %s" #, python-format msgid "Raw %s records" msgstr "Ðеоброблені запиÑи %s" #, python-format msgid "%s Record" msgstr "Ð—Ð°Ð¿Ð¸Ñ %s" #, python-format msgid "(see RFC %s for details)" msgstr "(докладніше про це у RFC %s)" #, python-format msgid "'%s' is a required part of DNS record" msgstr "«%s» Ñ” обов’Ñзковою чаÑтиною запиÑу DNS" msgid "Invalid number of parts!" msgstr "Ðекоректна кількіÑть чаÑтин!" #, python-format msgid "DNS RR type \"%s\" is not supported by bind-dyndb-ldap plugin" msgstr "Тип RR DNS «%s» не підтримуєтьÑÑ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð¼ bind-dyndb-ldap" #, python-format msgid "format must be specified as \"%(format)s\" %(rfcs)s" msgstr "" "формат має бути вÑтановлено так: \"%(format)s\", відповідно до %(rfcs)s" msgid "Create reverse" msgstr "Створити зворотний запиÑ" msgid "Create reverse record for this IP Address" msgstr "Створити зворотний Ð·Ð°Ð¿Ð¸Ñ Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— IP-адреÑи" #, python-format msgid "Cannot create reverse record for \"%(value)s\": %(exc)s" msgstr "Ðе вдалоÑÑ Ñтворити зворотний Ð·Ð°Ð¿Ð¸Ñ Ð´Ð»Ñ Â«%(value)s»: %(exc)s" msgid "IP Address" msgstr "IP-адреÑа" msgid "Record data" msgstr "Дані запиÑу" msgid "Subtype" msgstr "Підтип" msgid "Hostname" msgstr "Ðазва вузла" msgid "Certificate Type" msgstr "Тип Ñертифіката" msgid "Key Tag" msgstr "Мітка ключа" msgid "Algorithm" msgstr "Ðлгоритм" msgid "Certificate/CRL" msgstr "Сертифікат/CRL" msgid "A hostname which this alias hostname points to" msgstr "Ðазва вузла на Ñку вказує цей пÑевдонім вузла" msgid "Target" msgstr "Ціль" msgid "Digest Type" msgstr "Тип контрольної Ñуми" msgid "Digest" msgstr "Контрольна Ñума" msgid "Flags" msgstr "Прапорці" msgid "Protocol" msgstr "Протокол" msgid "Public Key" msgstr "Відкритий ключ" msgid "Preference" msgstr "Пріоритет" msgid "Preference given to this exchanger. Lower values are more preferred" msgstr "" "Пріоритет цього обмінника. ЗапиÑи з меншим значеннÑм мають вищий пріоритет." msgid "Exchanger" msgstr "Обмінник" msgid "A host willing to act as a key exchanger" msgstr "Вузол, Ñкий може працювати Ñк обмінник ключів" msgid "Degrees Latitude" msgstr "ГрадуÑи широти" msgid "Minutes Latitude" msgstr "Мінути широти" msgid "Seconds Latitude" msgstr "Секунди широти" msgid "Direction Latitude" msgstr "ÐŸÑ–Ð²ÐºÑƒÐ»Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð¸" msgid "Degrees Longitude" msgstr "ГрадуÑи довготи" msgid "Minutes Longitude" msgstr "Мінути довготи" msgid "Seconds Longitude" msgstr "Секунди довготи" msgid "Direction Longitude" msgstr "ÐапрÑмок довготи" msgid "Altitude" msgstr "ВиÑота" msgid "Size" msgstr "Розмір" msgid "Horizontal Precision" msgstr "ТочніÑть за горизонталлю" msgid "Vertical Precision" msgstr "ТочніÑть за вертикаллю" msgid "" "format must be specified as\n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (degrees latitude)\n" " d2: [0 .. 180] (degrees longitude)\n" " m1, m2: [0 .. 59] (minutes latitude/longitude)\n" " s1, s2: [0 .. 59.999] (seconds latitude/longitude)\n" " alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters)\n" " siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)\n" " See RFC 1876 for details" msgstr "" "формат має бути таким:\n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (широта у градуÑах)\n" " d2: [0 .. 180] (довгота у градуÑах)\n" " m1, m2: [0 .. 59] (мінути широти Ñ– довготи)\n" " s1, s2: [0 .. 59.999] (Ñекунди широти Ñ– довготи)\n" " alt: [-100000.00 .. 42849672.95] крок — .01 (виÑота у метрах)\n" " siz, hp, vp: [0 .. 90000000.00] (розміри, точніÑть у метрах)\n" " Див. RFC 1876." #, python-format msgid "'%(required)s' must not be empty when '%(name)s' is set" msgstr "«%(required)s» має бути порожнім, Ñкщо вказано «%(name)s»" msgid "A host willing to act as a mail exchanger" msgstr "Вузол, Ñкий може працювати Ñк обмінник поштовими даними" msgid "" "format must be specified as \"NEXT TYPE1 [TYPE2 [TYPE3 [...]]]\" (see RFC " "4034 for details)" msgstr "" "формат має бути таким: «ÐÐСТУПÐИЙ ТИП1 [ТИП2 [ТИП3 [...]]]» (докладніше про " "це у RFC 4034)" msgid "Next Domain Name" msgstr "ÐаÑтупна назва домену" msgid "Type Map" msgstr "Карта типів" msgid "flags must be one of \"S\", \"A\", \"U\", or \"P\"" msgstr "" "значеннÑм прапорців (flags) має бути одна з літер, \"S\", \"A\", \"U\" або " "\"P\"" msgid "Order" msgstr "ПорÑдок" msgid "Service" msgstr "Служба" msgid "Regular Expression" msgstr "Формальний вираз" msgid "Replacement" msgstr "Заміна" msgid "The hostname this reverse record points to" msgstr "Ðазва вузла, на Ñку вказує цей зворотний запиÑ" msgid "Priority" msgstr "Пріоритет" msgid "Weight" msgstr "Вага" msgid "Port" msgstr "Порт" msgid "" "The domain name of the target host or '.' if the service is decidedly not " "available at this domain" msgstr "" "Доменна назва вузла Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ '.', Ñкщо Ñлужба Ñ” Ñвно недоÑтупною на " "цьому домені" msgid "the value does not follow \"YYYYMMDDHHMMSS\" time format" msgstr "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ðµ відповідає формату «РРРРММДДГГХХСС»" msgid "Type Covered" msgstr "Тип покриттÑ" msgid "Labels" msgstr "Мітки" msgid "Original TTL" msgstr "Початковий TTL" msgid "Signature Expiration" msgstr "Строк Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð´Ñ–Ñ— підпиÑу" msgid "Signature Inception" msgstr "Початок дії підпиÑу" msgid "Signer's Name" msgstr "Ð†Ð¼â€™Ñ Ð¿Ñ–Ð´Ð¿Ð¸Ñувача" msgid "Signature" msgstr "ПідпиÑ" msgid "Fingerprint Type" msgstr "Тип відбитка" msgid "Fingerprint" msgstr "Відбиток" msgid "Text Data" msgstr "ТекÑтові дані" msgid "Records" msgstr "ЗапиÑи" msgid "Record type" msgstr "Тип запиÑу" #, python-format msgid "Nameserver '%(host)s' does not have a corresponding A/AAAA record" msgstr "Сервер назв «%(host)s» не має відповідного запиÑу A/AAAA" msgid "Managedby permission" msgstr "Права доÑтупу managedby" msgid "DNS zone" msgstr "зона DNS" msgid "DNS zones" msgstr "зони DNS" msgid "DNS Zones" msgstr "Зони DNS" msgid "DNS Zone" msgstr "Зона DNS" msgid "Zone name" msgstr "Ðазва зони" msgid "Zone name (FQDN)" msgstr "Ðазва зони (FQDN)" msgid "Reverse zone IP network" msgstr "Мережа IP зворотної зони" msgid "IP network to create reverse zone name from" msgstr "Мережа IP Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ð¸Ñ… назв зони" msgid "Authoritative nameserver" msgstr "ОÑновний Ñервер назв" msgid "Authoritative nameserver domain name" msgstr "Ðазва домену оÑновного Ñервера назв" msgid "Administrator e-mail address" msgstr "ÐдреÑа електронної пошти адмініÑтратора" msgid "SOA serial" msgstr "Серійний номер SOA" msgid "SOA record serial number" msgstr "Серійний номер запиÑу SOA" msgid "SOA refresh" msgstr "ОÑÐ²Ñ–Ð¶ÐµÐ½Ð½Ñ SOA" msgid "SOA record refresh time" msgstr "Ð§Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу SOA" msgid "SOA retry" msgstr "ÐŸÐ¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð½Ñ Ñпроби SOA" msgid "SOA record retry time" msgstr "Проміжок між повторними Ñпробами Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу SOA" msgid "SOA expire" msgstr "ЗаÑÑ‚Ð°Ñ€Ñ–Ð²Ð°Ð½Ð½Ñ SOA" msgid "SOA record expire time" msgstr "Ð§Ð°Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ñтроку дії запиÑу SOA" msgid "SOA minimum" msgstr "Мінімальний SOA" msgid "How long should negative responses be cached" msgstr "ТриваліÑть ÐºÐµÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¼Ð¾Ð²" msgid "SOA time to live" msgstr "Строк дії SOA" msgid "SOA record time to live" msgstr "Ð§Ð°Ñ Ð¶Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ð¿Ð¸Ñу SOA" msgid "SOA class" msgstr "ÐšÐ»Ð°Ñ SOA" msgid "SOA record class" msgstr "ÐšÐ»Ð°Ñ Ð·Ð°Ð¿Ð¸Ñів SOA" msgid "BIND update policy" msgstr "Правила Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ BIND" msgid "Active zone" msgstr "Ðктивна зона" msgid "Is zone active?" msgstr "Чи Ñ” зона активною?" msgid "Dynamic update" msgstr "Динамічне оновленнÑ" msgid "Allow dynamic updates." msgstr "Дозволити динамічні оновленнÑ." msgid "Allow query" msgstr "Дозволити запит" msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "issue queries" msgstr "" "СпиÑок відокремлених крапкою з комою запиÑів IP-Ð°Ð´Ñ€ÐµÑ Ð°Ð±Ð¾ мереж, Ñким надано " "доÑтуп до надÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñ–Ð²" msgid "Allow transfer" msgstr "Дозволити перенеÑеннÑ" msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "transfer the zone" msgstr "" "СпиÑок відокремлених крапкою з комою запиÑів IP-Ð°Ð´Ñ€ÐµÑ Ð°Ð±Ð¾ мереж, Ñким надано " "доÑтуп до перенеÑÐµÐ½Ð½Ñ Ð·Ð¾Ð½Ð¸" msgid "Zone forwarders" msgstr "ПереÑпрÑмовувачі зон" msgid "" "Per-zone forwarders. A custom port can be specified for each forwarder using " "a standard format \"IP_ADDRESS port PORT\"" msgstr "" "ПереÑпрÑмовувачі Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¾Ñ— зони. Можна вказати нетиповий порт Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ " "переÑпрÑмовувача у Ñтандартному форматі: «IP_ÐДРЕСРport ПОРТ»" msgid "Forward policy" msgstr "Правила переÑпрÑмовуваннÑ" msgid "" "Per-zone conditional forwarding policy. Set to \"none\" to disable " "forwarding to global forwarder for this zone. In that case, conditional zone " "forwarders are disregarded." msgstr "" "Умовні правила переÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¾Ñ— зони. Ð’Ñтановіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«none» " "Ð´Ð»Ñ Ð²Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÑпрÑмовувача загального Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— зони. Якщо ви " "вÑтановите це значеннÑ, умовні переÑпрÑмовувачі зони не братимутьÑÑ до уваги." msgid "Allow PTR sync" msgstr "Дозволити PTR-Ñинхронізацію" msgid "" "Allow synchronization of forward (A, AAAA) and reverse (PTR) records in the " "zone" msgstr "" "Дозволити у зоні Ñинхронізацію прÑмих (A, AAAA) Ñ– зворотних (PTR) запиÑів" msgid "Create new DNS zone (SOA record)." msgstr "Створити зону DNS (Ð·Ð°Ð¿Ð¸Ñ SOA)." msgid "Force" msgstr "ПримуÑово" msgid "Force DNS zone creation even if nameserver is not resolvable." msgstr "" "ПримуÑово Ñтворити зону DNS, навіть Ñкщо не вдаєтьÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ адреÑу " "Ñервера назв." msgid "Add forward record for nameserver located in the created zone" msgstr "" "Додати Ð·Ð°Ð¿Ð¸Ñ Ð¿ÐµÑ€ÐµÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ñервера назв, розташованого у Ñтвореній зоні" msgid "Nameserver IP address" msgstr "IP-адреÑа Ñервера назв" msgid "DNS is not configured" msgstr "DNS не налаштовано" msgid "Nameserver address is not a domain name" msgstr "ÐдреÑа Ñервера назв не Ñ” назвою домену" msgid "Nameserver for reverse zone cannot be a relative DNS name" msgstr "Ðе можна задавати Ñервер назв Ð´Ð»Ñ Ð·Ð²Ð¾Ñ€Ð¾Ñ‚Ð½Ð¾Ñ— зони відноÑно назви DNS" msgid "Nameserver DNS record is created for for forward zones only" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ñервера назв DNS Ñтворено лише Ð´Ð»Ñ Ð·Ð¾Ð½ переÑпрÑмовуваннÑ" msgid "Nameserver DNS record is created only for nameservers in current zone" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ñервера назв DNS Ñтворено лише Ð´Ð»Ñ Ñерверів назв у поточній зоні" msgid "Delete DNS zone (SOA record)." msgstr "Вилучити зону DNS (Ð·Ð°Ð¿Ð¸Ñ SOA)." #, python-format msgid "Deleted DNS zone \"%(value)s\"" msgstr "Вилучено зону DNS «%(value)s»" msgid "Modify DNS zone (SOA record)." msgstr "Змінити зону DNS (Ð·Ð°Ð¿Ð¸Ñ SOA)." msgid "Force nameserver change even if nameserver not in DNS" msgstr "" "ПримуÑово змінити Ñервер назв, навіть Ñкщо запиÑу Ñервера назв немає у DNS" msgid "Search for DNS zones (SOA records)." msgstr "Пошук зон DNS (запиÑів SOA)." msgid "Forward zones only" msgstr "Лише прÑмі зони" msgid "Search for forward zones only" msgstr "Шукати лише прÑмі зони" msgid "Display information about a DNS zone (SOA record)." msgstr "Показати дані щодо зони DNS (запиÑу SOA)." msgid "Disable DNS Zone." msgstr "Вимкнути зону DNS." #, python-format msgid "Disabled DNS zone \"%(value)s\"" msgstr "Вимкнено зону DNS «%(value)s»" msgid "Enable DNS Zone." msgstr "Увімкнути зону DNS." #, python-format msgid "Enabled DNS zone \"%(value)s\"" msgstr "Увімкнено зону DNS «%(value)s»" msgid "Add a permission for per-zone access delegation." msgstr "Додати права доÑтупу до Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до окремих зон." #, python-format msgid "Added system permission \"%(value)s\"" msgstr "Додано ÑиÑтемні права доÑтупу «%(value)s»" msgid "Remove a permission for per-zone access delegation." msgstr "Вилучити права доÑтупу до Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до окремих зон." #, python-format msgid "Removed system permission \"%(value)s\"" msgstr "Вилучено ÑиÑтемні права доÑтупу «%(value)s»" msgid "DNS resource record" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ñ€ÐµÑурÑу DNS" msgid "DNS resource records" msgstr "ЗапиÑи реÑурÑів DNS" msgid "DNS Resource Records" msgstr "ЗапиÑи реÑурÑів DNS" msgid "DNS Resource Record" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ñ€ÐµÑурÑу DNS" msgid "Record name" msgstr "Ðазва запиÑу" msgid "Time to live" msgstr "Строк дії" msgid "Class" msgstr "КлаÑ" msgid "DNS class" msgstr "ÐšÐ»Ð°Ñ DNS" msgid "Structured" msgstr "Структурована" msgid "Parse all raw DNS records and return them in a structured way" msgstr "Обробити вÑÑ– запиÑи DNS Ñ– повернути дані у Ñтруктурованій формі" #, python-format msgid "" "Reverse zone for PTR record should be a sub-zone of one the following fully " "qualified domains: %s" msgstr "" "Зворотна зона Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу PTR має бути підзоною одного з таких повноформатних " "доменів: %s" #, python-format msgid "" "Reverse zone %(name)s requires exactly %(count)d IP address components, " "%(user_count)d given" msgstr "" "Зворотна зона %(name)s потребує точно %(count)d компонентів IP-адреÑ, надано " "%(user_count)d" msgid "only one CNAME record is allowed per name (RFC 2136, section 1.1.5)" msgstr "" "можна викориÑтовувати лише один Ð·Ð°Ð¿Ð¸Ñ CNAME на назву (RFC 2136, розділ 1.1.5)" msgid "" "CNAME record is not allowed to coexist with any other record (RFC 1034, " "section 3.6.2)" msgstr "" "ЗапиÑом CNAME не можна кориÑтуватиÑÑ Ñ€Ð°Ð·Ð¾Ð¼ з будь-Ñкими іншими запиÑами, " "окрім PTR (RFC 1034, розділ 3.6.2)" msgid "only one DNAME record is allowed per name (RFC 6672, section 2.4)" msgstr "" "можна викориÑтовувати лише один Ð·Ð°Ð¿Ð¸Ñ DNAME на назву (RFC 6672, розділ 2.4)" msgid "" "DNAME record is not allowed to coexist with an NS record except when located " "in a zone root record (RFC 6672, section 2.3)" msgstr "" "Ð·Ð°Ð¿Ð¸Ñ DNAME не можна викориÑтовувати разом з запиÑом NS, Ñкщо Ñ—Ñ… не " "розташовано у запиÑу ÐºÐ¾Ñ€ÐµÐ½Ñ Ð·Ð¾Ð½Ð¸ (RFC 6672, розділ 2.3)" msgid "Add new DNS resource record." msgstr "Додати новий Ð·Ð°Ð¿Ð¸Ñ Ñ€ÐµÑурÑу DNS." msgid "force NS record creation even if its hostname is not in DNS" msgstr "" "примуÑово Ñтворити Ð·Ð°Ð¿Ð¸Ñ Ñервера назв, навіть Ñкщо відповідної назви вузла " "немає у DNS" msgid "Please choose a type of DNS resource record to be added" msgstr "Будь лаÑка, виберіть тип запиÑу реÑурÑу DNS, Ñкий Ñлід додати" #, python-format msgid "The most common types for this type of zone are: %s\n" msgstr "Ðайпоширенішими типами Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу зон Ñ”: %s\n" msgid "DNS resource record type" msgstr "Тип запиÑу реÑурÑу DNS" #, python-format msgid "Invalid or unsupported type. Allowed values are: %s" msgstr "Ðекоректний або непідтримуваний тип. Дозволені значеннÑ: %s" #, python-format msgid "Raw value of a DNS record was already set by \"%(name)s\" option" msgstr "" "Ðеоброблене Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñу DNS вже було вÑтановлено за допомогою " "параметра «%(name)s»" msgid "Modify a DNS resource record." msgstr "Змінити Ð·Ð°Ð¿Ð¸Ñ Ñ€ÐµÑурÑу DNS." msgid "DNS zone root record cannot be renamed" msgstr "Кореневий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð¾Ð½Ð¸ DNS не можна перейменовувати" msgid "DNS records can be only updated one at a time" msgstr "ЗапиÑи DNS можна оновлювати лише поодинці" msgid "No option to modify specific record provided." msgstr "МожливоÑті внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ у певний Ð·Ð°Ð¿Ð¸Ñ Ð½Ðµ передбачено." msgid "Current DNS record contents:\n" msgstr "Поточний вміÑÑ‚ запиÑу DNS:\n" #, python-format msgid "Modify %(name)s '%(value)s'?" msgstr "Змінити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«%(value)s» %(name)s?" #, python-format msgid "" "%(count)d %(type)s record skipped. Only one value per DNS record type can be " "modified at one time." msgid_plural "" "%(count)d %(type)s records skipped. Only one value per DNS record type can " "be modified at one time." msgstr[0] "" "Пропущено %(count)d %(type)s запиÑ. ОдночаÑно можна змінювати лише одне " "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð° тип запиÑу DNS." msgstr[1] "" "Пропущено %(count)d %(type)s запиÑи. ОдночаÑно можна змінювати лише одне " "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð° тип запиÑу DNS." msgstr[2] "" "Пропущено %(count)d %(type)s запиÑів. ОдночаÑно можна змінювати лише одне " "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð° тип запиÑу DNS." #, python-format msgid "Deleted record \"%(value)s\"" msgstr "Вилучено Ð·Ð°Ð¿Ð¸Ñ Â«%(value)s»" msgid "Delete DNS resource record." msgstr "Вилучити Ð·Ð°Ð¿Ð¸Ñ Ñ€ÐµÑурÑу DNS." msgid "" "Neither --del-all nor options to delete a specific record provided.\n" "Command help may be consulted for all supported record types." msgstr "" "Ðе надано ні --del-all, ні параметрів Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¾Ð³Ð¾ запиÑу.\n" "Ð’ÑÑ– підтримувані типи запиÑів можна знайти у виводі команди help." msgid "Delete all associated records" msgstr "Вилучити вÑÑ– пов’Ñзані запиÑи" #, python-format msgid "Zone record '%s' cannot be deleted" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð·Ð¾Ð½Ð¸ «%s» не можна вилучати" msgid "No option to delete specific record provided." msgstr "Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… реÑурÑів не передбачено." msgid "Delete all?" msgstr "Вилучити вÑе?" #, python-format msgid "Delete %(name)s '%(value)s'?" msgstr "Вилучити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«%(value)s» %(name)s?" msgid "Display DNS resource." msgstr "Показати реÑÑƒÑ€Ñ DNS." msgid "Search for DNS resources." msgstr "Шукати реÑурÑи DNS." msgid "Resolve a host name in DNS." msgstr "Визначити назву вузла у DNS." #, python-format msgid "Found '%(value)s'" msgstr "Знайдено «%(value)s»" #, python-format msgid "Host '%(host)s' not found" msgstr "Вузла «%(host)s» не знайдено" msgid "DNS configuration options" msgstr "Параметри Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS" msgid "DNS Global Configuration" msgstr "Загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS" msgid "Global forwarders" msgstr "Загальні переÑпрÑмовувачі" msgid "" "Global forwarders. A custom port can be specified for each forwarder using a " "standard format \"IP_ADDRESS port PORT\"" msgstr "" "ПереÑпрÑмовувачі загального рівнÑ. Ð”Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ переÑпрÑмовувача можна " "вказати нетиповий порт за допомогою Ñтандартного формату: «IP_ÐДРЕСРport " "ПОРТ»" msgid "" "Global forwarding policy. Set to \"none\" to disable any configured global " "forwarders." msgstr "" "Загальні правил переÑпрÑмовуваннÑ. Щоб вимкнути будь-Ñкі переÑпрÑмовувачі на " "загальному рівні, вÑтановіть Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«none»." msgid "Allow synchronization of forward (A, AAAA) and reverse (PTR) records" msgstr "Дозволити Ñинхронізацію прÑмих (A, AAAA) Ñ– зворотних (PTR) запиÑів" msgid "Zone refresh interval" msgstr "Інтервал між оновленнÑми даних зони" msgid "An interval between regular polls of the name server for new DNS zones" msgstr "" "Інтервал між двома регулÑрними ÑеанÑами Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… з Ñервера назв Ð´Ð»Ñ " "нових зон DNS" msgid "Global DNS configuration is empty" msgstr "Загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS Ñ” порожніми" msgid "Modify global DNS configuration." msgstr "Змінити загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS." msgid "Show the current global DNS configuration." msgstr "Показати поточні загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS." msgid "" "\n" "Groups of users\n" "\n" "Manage groups of users. By default, new groups are POSIX groups. You\n" "can add the --nonposix option to the group-add command to mark a new group\n" "as non-POSIX. You can use the --posix argument with the group-mod command\n" "to convert a non-POSIX group into a POSIX group. POSIX groups cannot be\n" "converted to non-POSIX groups.\n" "\n" "Every group must have a description.\n" "\n" "POSIX groups must have a Group ID (GID) number. Changing a GID is\n" "supported but can have an impact on your file permissions. It is not " "necessary\n" "to supply a GID when creating a group. IPA will generate one automatically\n" "if it is not provided.\n" "\n" "EXAMPLES:\n" "\n" " Add a new group:\n" " ipa group-add --desc='local administrators' localadmins\n" "\n" " Add a new non-POSIX group:\n" " ipa group-add --nonposix --desc='remote administrators' remoteadmins\n" "\n" " Convert a non-POSIX group to posix:\n" " ipa group-mod --posix remoteadmins\n" "\n" " Add a new POSIX group with a specific Group ID number:\n" " ipa group-add --gid=500 --desc='unix admins' unixadmins\n" "\n" " Add a new POSIX group and let IPA assign a Group ID number:\n" " ipa group-add --desc='printer admins' printeradmins\n" "\n" " Remove a group:\n" " ipa group-del unixadmins\n" "\n" " To add the \"remoteadmins\" group to the \"localadmins\" group:\n" " ipa group-add-member --groups=remoteadmins localadmins\n" "\n" " Add multiple users to the \"localadmins\" group:\n" " ipa group-add-member --users=test1 --users=test2 localadmins\n" "\n" " Remove a user from the \"localadmins\" group:\n" " ipa group-remove-member --users=test2 localadmins\n" "\n" " Display information about a named group.\n" " ipa group-show localadmins\n" "\n" "External group membership is designed to allow users from trusted domains\n" "to be mapped to local POSIX groups in order to actually use IPA resources.\n" "External members should be added to groups that specifically created as\n" "external and non-POSIX. Such group later should be included into one of " "POSIX\n" "groups.\n" "\n" "An external group member is currently a Security Identifier (SID) as defined " "by\n" "the trusted domain. When adding external group members, it is possible to\n" "specify them in either SID, or DOM\\name, or name@domain format. IPA will " "attempt\n" "to resolve passed name to SID with the use of Global Catalog of the trusted " "domain.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" msgstr "" "\n" "Групи кориÑтувачів\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð°Ð¼Ð¸ кориÑтувачів. Типово нові групи Ñ” групами POSIX. Ви " "можете\n" "додати параметр --nonposix до команди group-add з метою Ð¿Ð¾Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ—\n" "групи Ñк групи не-POSIX. Ви можете ÑкориÑтатиÑÑ Ð°Ñ€Ð³ÑƒÐ¼ÐµÐ½Ñ‚Ð¾Ð¼ --posix команди " "group-mod\n" "Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸ не-POSIX на групу POSIX. Групи POSIX не можна\n" "перетворювати на групи не-POSIX.\n" "\n" "Кожна група повинна мати опиÑ.\n" "\n" "Групи POSIX повинні мати номер ідентифікатора групи (GID). Передбачено " "підтримку\n" "зміни GID, але Ñ†Ñ Ð·Ð¼Ñ–Ð½Ð° може вплинути на права доÑтупу до ваших файлів. ДлÑ\n" "ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸ Ñлід вказати GID. IPA Ñтворить одну групу автоматично, Ñкщо\n" "таку не вказано.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— групи:\n" " ipa group-add --desc='local administrators' localadmins\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— групи не-POSIX:\n" " ipa group-add --nonposix --desc='remote administrators' remoteadmins\n" "\n" " Перетворити групу не-POSIX на групу posix:\n" " ipa group-mod --posix remoteadmins\n" "\n" " Додати нову групу POSIX з вказаним ідентифікатором групи:\n" " ipa group-add --gid=500 --desc='unix admins' unixadmins\n" "\n" " Додати нову групу POSIX Ñ– надати IPA змогу призначити ідентифікатор:\n" " ipa group-add --desc='printer admins' printeradmins\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸:\n" " ipa group-del unixadmins\n" "\n" " Додати групу \"remoteadmins\" до групи \"localadmins\":\n" " ipa group-add-member --groups=remoteadmins localadmins\n" "\n" " Додати ÑпиÑок кориÑтувачів до групи \"localadmins\":\n" " ipa group-add-member --users=test1 --users=test2 localadmins\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача з групи \"localadmins\":\n" " ipa group-remove-member --users=test2 localadmins\n" "\n" " Показати інформацію щодо іменованої групи.\n" " ipa group-show localadmins\n" "\n" "УчаÑть із зовнішніх груп Ñтворено Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб уможливити прив’Ñзку\n" "кориÑтувачів з довірених доменів до локальних груп POSIX з метою\n" "викориÑÑ‚Ð°Ð½Ð½Ñ Ñ€ÐµÑурÑів IPA. Зовнішніх кориÑтувачів Ñлід додавати до груп\n" "Ñкі Ñпеціально Ñтворено Ñк зовнішні або групи не-POSIX. Таку групу\n" "Ñлід пізніше включити до одної з груп POSIX.\n" "\n" "У поточній верÑÑ–Ñ— учаÑник зовнішньої групи Ñ” ідентифікатором безпеки\n" "(Security Identifier або SID) визначеним довіреним доменом. ДодаваннÑ\n" "учаÑників зовнішньої групи можна виконати у форматі SID, DOM\\Ñ–Ð¼â€™Ñ Ð°Ð±Ð¾\n" "ім’Ñ@домен. IPA намагатиметьÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ за переданим іменем SID за\n" "допомогою викориÑÑ‚Ð°Ð½Ð½Ñ Ð—Ð°Ð³Ð°Ð»ÑŒÐ½Ð¾Ð³Ð¾ каталогу довіреного домену.\n" "\n" "Приклад:\n" "\n" "1. Створити групу Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²â€™Ñзки адмініÑтраторів довіреного домену до\n" "відповідної локальної групи POSIX:\n" "\n" " ipa group-add --desc='<домен.ad> admins external map' ad_admins_external " "--external\n" " ipa group-add --desc='<домен.ad> admins' ad_admins\n" "\n" "2. Додати ідентифікатор Domain Admins домену <домен.ad> до\n" "групи ad_admins_external:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Дозволити прив’Ñзку групи ad_admins_external до групи POSIX ad_admins:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. Показати ÑпиÑок зовнішніх учаÑників групи ad_admins_external, щоб " "визначити\n" "їхні SIDs:\n" "\n" " ipa group-show ad_admins_external\n" msgid "group" msgstr "група" msgid "groups" msgstr "групи" msgid "User Groups" msgstr "Групи кориÑтувачів" msgid "User Group" msgstr "Група кориÑтувачів" msgid "Group name" msgstr "Ðазва групи" msgid "Group description" msgstr "ÐžÐ¿Ð¸Ñ Ð³Ñ€ÑƒÐ¿Ð¸" msgid "GID" msgstr "GID" msgid "GID (use this option to set it manually)" msgstr "GID (за допомогою цього параметра можна вÑтановити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ)" msgid "External member" msgstr "Зовнішній учаÑник" msgid "Members of a trusted domain in DOM\\name or name@domain form" msgstr "УчаÑники довіреного домену у форматі ДОМЕÐ\\Ñ–Ð¼â€™Ñ Ð°Ð±Ð¾ ім’Ñ@домен" msgid "Create a new group." msgstr "Створити нову групу." #, python-format msgid "Added group \"%(value)s\"" msgstr "Додано групу «%(value)s»" msgid "Create as a non-POSIX group" msgstr "Створити Ñк групу, що не відповідає POSIX" msgid "Allow adding external non-IPA members from trusted domains" msgstr "Дозволити Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ–Ñ… учаÑників поза IPA з довірених доменів" msgid "Delete group." msgstr "Вилучити групу." #, python-format msgid "Deleted group \"%(value)s\"" msgstr "Вилучено групу «%(value)s»" msgid "privileged group" msgstr "привілейована група" msgid "Modify a group." msgstr "Змінити групу." #, python-format msgid "Modified group \"%(value)s\"" msgstr "Змінено групу «%(value)s»" msgid "change to a POSIX group" msgstr "змінити на групу POSIX" msgid "change to support external non-IPA members from trusted domains" msgstr "змінити Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ñ€Ð¸Ð¼ÐºÐ¸ зовнішніх учаÑників поза IPA з довірених доменів" msgid "Search for groups." msgstr "Шукати групи." #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d групи" msgstr[1] "вÑтановлено відповідніÑть %(count)d груп" msgstr[2] "вÑтановлено відповідніÑть %(count)d груп" msgid "search for private groups" msgstr "шукати закриті групи" msgid "search for POSIX groups" msgstr "шукати групи POSIX" msgid "" "search for groups with support of external non-IPA members from trusted " "domains" msgstr "" "шукати групи з підтримкою зовнішніх учаÑників поза IPA з довірених доменів" msgid "search for non-POSIX groups" msgstr "шукати групи, Ñкі не Ñ” групами POSIX" msgid "Display information about a named group." msgstr "Показати дані щодо іменованої групи." msgid "Add members to a group." msgstr "Додати учаÑників до групи." msgid "" "Cannot perform external member validation without Samba 4 support installed. " "Make sure you have installed server-trust-ad sub-package of IPA on the server" msgstr "" "Виконати дію з перевірки зовнішніх учаÑників без вÑтановленої підтримки " "Samba 4 неможливо. ПереконайтеÑÑ, що вами вÑтановлено на Ñервері підпакунок " "IPA server-trust-ad." msgid "" "Cannot perform join operation without own domain configured. Make sure you " "have run ipa-adtrust-install on the IPA server first" msgstr "" "Без Ð½Ð°Ð»Ð°ÑˆÑ‚Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñного домену не можна виконувати дію з приєднаннÑ. " "Спочатку запуÑтіть ipa-adtrust-install на Ñервері IPA." msgid "Remove members from a group." msgstr "Вилучити учаÑників з групи." msgid "Detach a managed group from a user." msgstr "Від’єднати керовану групу від кориÑтувача." #, python-format msgid "Detached group \"%(value)s\" from user \"%(value)s\"" msgstr "Від’єднати групу «%(value)s» від кориÑтувача «%(value)s»" msgid "not allowed to modify user entries" msgstr "заборонено змінювати запиÑи кориÑтувачів" msgid "not allowed to modify group entries" msgstr "заборонено змінювати запиÑи груп" msgid "Not a managed group" msgstr "Ðе Ñ” керованою групою" msgid "" "\n" "Host-based access control\n" "\n" "Control who can access what services on what hosts. You\n" "can use HBAC to control which users or groups can\n" "access a service, or group of services, on a target host.\n" "\n" "You can also specify a category of users and target hosts.\n" "This is currently limited to \"all\", but might be expanded in the\n" "future.\n" "\n" "Target hosts in HBAC rules must be hosts managed by IPA.\n" "\n" "The available services and groups of services are controlled by the\n" "hbacsvc and hbacsvcgroup plug-ins respectively.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that grants all users access to the host \"server" "\" from\n" " anywhere:\n" " ipa hbacrule-add --usercat=all test1\n" " ipa hbacrule-add-host --hosts=server.example.com test1\n" "\n" " Display the properties of a named HBAC rule:\n" " ipa hbacrule-show test1\n" "\n" " Create a rule for a specific service. This lets the user john access\n" " the sshd service on any machine from any machine:\n" " ipa hbacrule-add --hostcat=all john_sshd\n" " ipa hbacrule-add-user --users=john john_sshd\n" " ipa hbacrule-add-service --hbacsvcs=sshd john_sshd\n" "\n" " Create a rule for a new service group. This lets the user john access\n" " the FTP service on any machine from any machine:\n" " ipa hbacsvcgroup-add ftpers\n" " ipa hbacsvc-add sftp\n" " ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers\n" " ipa hbacrule-add --hostcat=all john_ftp\n" " ipa hbacrule-add-user --users=john john_ftp\n" " ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp\n" "\n" " Disable a named HBAC rule:\n" " ipa hbacrule-disable test1\n" "\n" " Remove a named HBAC rule:\n" " ipa hbacrule-del allow_server\n" msgstr "" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів\n" "\n" "Керуйте тим, хто, з Ñких вузлів зможе отримувати доÑтуп\n" "до певних Ñлужб. Ви можете ÑкориÑтатиÑÑ HBAC Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ\n" "кориÑтувачів Ñ– груп на вузлі Ð¿Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ зможе отримувати\n" "доÑтуп до певної Ñлужби або групи Ñлужб.\n" "\n" "Ви також можете визначити категорію кориÑтувачів та вузли призначеннÑ.\n" "У поточній верÑÑ–Ñ— можливі варіанти\n" "обмежено варіантом \"all\", але перелік варіантів може бути\n" "розширено у майбутніх верÑÑ–ÑÑ….\n" "\n" "Вузли Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð° вузли Ð¿Ð¾Ñ…Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ñƒ правилах HBAC мають бути\n" "вузлами, керованими IPA.\n" "\n" "ДоÑтупними Ñлужбами Ñ– групами Ñлужб Ñ” Ñлужби, керовані hbacsvc\n" "та додатками hbacsvcgroup, відповідно.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° \"test1\", Ñке надає вÑім кориÑтувачам доÑтуп\n" " до вузла \"server\" звідуÑюди:\n" " ipa hbacrule-add --usercat=all test1\n" " ipa hbacrule-add-host --hosts=server.example.com test1\n" "\n" " Показ влаÑтивоÑтей вказаного правила HBAC:\n" " ipa hbacrule-show test1\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— Ñлужби. Це правило надаÑть кориÑтувачу john\n" " доÑтуп до Ñлужби sshd у будь-Ñкій ÑиÑтемі звідуÑіль:\n" " ipa hbacrule-add --hostcat=all john_sshd\n" " ipa hbacrule-add-user --users=john john_sshd\n" " ipa hbacrule-add-service --hbacsvcs=sshd john_sshd\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ñ— групи Ñлужб. КориÑтувачу john\n" " надаєтьÑÑ Ð´Ð¾Ñтуп до Ñлужби FTP у будь-Ñкій ÑиÑтемі звідуÑіль:\n" " ipa hbacsvcgroup-add ftpers\n" " ipa hbacsvc-add sftp\n" " ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers\n" " ipa hbacrule-add --type=allow --hostcat=all john_ftp\n" " ipa hbacrule-add-user --users=john john_ftp\n" " ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾Ð³Ð¾ правила HBAC:\n" " ipa hbacrule-disable test1\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾Ð³Ð¾ правила HBAC:\n" " ipa hbacrule-del allow_server\n" msgid "Host-based access control commands" msgstr "Команди ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів" msgid "The deny type has been deprecated." msgstr "Тип «deny» вважаєтьÑÑ Ð·Ð°Ñтарілим." msgid "HBAC rule" msgstr "Правило HBAC" msgid "HBAC rules" msgstr "правила HBAC" msgid "HBAC Rules" msgstr "Правила HBAC" msgid "HBAC Rule" msgstr "Правило HBAC" msgid "Rule name" msgstr "Ðазва правила" msgid "Rule type (allow)" msgstr "Тип правила (allow)" msgid "Rule type" msgstr "Тип правила" msgid "User category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів" msgid "User category the rule applies to" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів, до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "Host category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÑƒÐ·Ð»Ñ–Ð²" msgid "Host category the rule applies to" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÑƒÐ·Ð»Ñ–Ð², до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "Service category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ñлужб" msgid "Service category the rule applies to" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ñлужб, до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "Enabled" msgstr "Увімкнено" msgid "Users" msgstr "КориÑтувачі" msgid "Hosts" msgstr "Вузли" msgid "Host Groups" msgstr "Групи вузлів" msgid "Services" msgstr "Служби" msgid "Service Groups" msgstr "Групи Ñлужб" msgid "Create a new HBAC rule." msgstr "Створити правило HBAC." #, python-format msgid "Added HBAC rule \"%(value)s\"" msgstr "Додано правило HBAC «%(value)s»" msgid "Delete an HBAC rule." msgstr "Вилучити правило HBAC." #, python-format msgid "Deleted HBAC rule \"%(value)s\"" msgstr "Вилучено правило HBAC «%(value)s»" msgid "Modify an HBAC rule." msgstr "Змінити правило HBAC." #, python-format msgid "Modified HBAC rule \"%(value)s\"" msgstr "Змінено правило HBAC «%(value)s»" msgid "user category cannot be set to 'all' while there are allowed users" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— кориÑтувачів Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all», доки Ñ” " "запиÑи дозволених кориÑтувачів" msgid "host category cannot be set to 'all' while there are allowed hosts" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— вузлів Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all», доки Ñ” запиÑи " "дозволених вузлів" msgid "" "service category cannot be set to 'all' while there are allowed services" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— Ñлужб Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all», доки Ñ” дозволені " "Ñлужби" msgid "Search for HBAC rules." msgstr "Шукати правила HBAC." #, python-format msgid "%(count)d HBAC rule matched" msgid_plural "%(count)d HBAC rules matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d правила HBAC" msgstr[1] "вÑтановлено відповідніÑть %(count)d правил HBAC" msgstr[2] "вÑтановлено відповідніÑть %(count)d правил HBAC" msgid "Display the properties of an HBAC rule." msgstr "Показати влаÑтивоÑті правила HBAC." msgid "Enable an HBAC rule." msgstr "Увімкнути правило HBAC." #, python-format msgid "Enabled HBAC rule \"%(value)s\"" msgstr "Увімкнено правило HBAC «%(value)s»" msgid "Disable an HBAC rule." msgstr "Вимкнути правило HBAC." #, python-format msgid "Disabled HBAC rule \"%(value)s\"" msgstr "Вимкнено правило HBAC «%(value)s»" msgid "Access time" msgstr "Ð§Ð°Ñ Ð´Ð¾Ñтупу" msgid "Add users and groups to an HBAC rule." msgstr "Додати кориÑтувачів та групи до правила HBAC." msgid "users cannot be added when user category='all'" msgstr "" "не можна додавати запиÑи кориÑтувачів, Ñкщо ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів=«all»" msgid "Remove users and groups from an HBAC rule." msgstr "Вилучити кориÑтувачів Ñ– групи з правила HBAC." msgid "Add target hosts and hostgroups to an HBAC rule." msgstr "Додати вузли Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð° групи вузлів до правила HBAC." msgid "hosts cannot be added when host category='all'" msgstr "не можна додавати запиÑи вузлів, Ñкщо ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÑƒÐ·Ð»Ñ–Ð²=«all»" msgid "Remove target hosts and hostgroups from an HBAC rule." msgstr "Вилучити вузли Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð° групи вузлів з правила HBAC." msgid "Add services to an HBAC rule." msgstr "Додати Ñлужби до правила HBAC." msgid "services cannot be added when service category='all'" msgstr "не можна додавати запиÑи Ñлужб, Ñкщо ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ñлужб=«all»" msgid "Remove service and service groups from an HBAC rule." msgstr "Вилучити Ñлужби та групи Ñлужб з правила HBAC." msgid "" "\n" "HBAC Services\n" "\n" "The PAM services that HBAC can control access to. The name used here\n" "must match the service name that PAM is evaluating.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service:\n" " ipa hbacsvc-add tftp\n" "\n" " Modify an existing HBAC service:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Search for HBAC services. This example will return two results, the FTP\n" " service and the newly-added tftp service:\n" " ipa hbacsvc-find ftp\n" "\n" " Delete an HBAC service:\n" " ipa hbacsvc-del tftp\n" "\n" msgstr "" "\n" "Служби HBAC\n" "\n" "Служби PAM, Ñкими може керувати HBAC. Ðазва, викориÑтана тут, має\n" "відповідати назві Ñлужби, з Ñкою працює PAM.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Додати нову Ñлужбу HBAC:\n" " ipa hbacsvc-add tftp\n" "\n" " Змінити вже Ñтворену Ñлужбу HBAC:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Шукати Ñлужби HBAC. У нашому прикладі буде повернуто два результати\n" " Ñлужбу FTP Ñ– щойно додану Ñлужбу tftp:\n" " ipa hbacsvc-find ftp\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñлужби HBAC:\n" " ipa hbacsvc-del tftp\n" "\n" msgid "Host based access control commands" msgstr "Команди ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів" msgid "HBAC service" msgstr "Служба HBAC" msgid "HBAC services" msgstr "Служби HBAC" msgid "HBAC Services" msgstr "Служби HBAC" msgid "HBAC Service" msgstr "Служба HBAC" msgid "Service name" msgstr "Ðазва Ñлужби" msgid "HBAC service description" msgstr "ÐžÐ¿Ð¸Ñ Ñлужби HBAC" msgid "Add a new HBAC service." msgstr "Додати нову Ñлужбу HBAC." #, python-format msgid "Added HBAC service \"%(value)s\"" msgstr "Додано Ñлужбу HBAC «%(value)s»" msgid "Delete an existing HBAC service." msgstr "Вилучити вже Ñтворену Ñлужбу HBAC." #, python-format msgid "Deleted HBAC service \"%(value)s\"" msgstr "Вилучено Ñлужбу HBAC «%(value)s»" msgid "Modify an HBAC service." msgstr "Змінити Ñлужбу HBAC." #, python-format msgid "Modified HBAC service \"%(value)s\"" msgstr "Змінено Ñлужбу HBAC «%(value)s»" msgid "Search for HBAC services." msgstr "Шукати Ñлужби HBAC." #, python-format msgid "%(count)d HBAC service matched" msgid_plural "%(count)d HBAC services matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d Ñлужби HBAC" msgstr[1] "вÑтановлено відповідніÑть %(count)d Ñлужб HBAC" msgstr[2] "вÑтановлено відповідніÑть %(count)d Ñлужб HBAC" msgid "Display information about an HBAC service." msgstr "Показати дані щодо Ñлужби HBAC." msgid "" "\n" "HBAC Service Groups\n" "\n" "HBAC service groups can contain any number of individual services,\n" "or \"members\". Every group must have a description.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service group:\n" " ipa hbacsvcgroup-add --desc=\"login services\" login\n" "\n" " Add members to an HBAC service group:\n" " ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login\n" "\n" " Display information about a named group:\n" " ipa hbacsvcgroup-show login\n" "\n" " Delete an HBAC service group:\n" " ipa hbacsvcgroup-del login\n" msgstr "" "\n" "Групи Ñлужб HBAC\n" "\n" "Групи Ñлужб HBAC можуть міÑтити будь-Ñку кількіÑть окремих Ñлужб\n" "або «учаÑників». Кожна з груп повинна мати опиÑ.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— групи Ñлужб HBAC:\n" " ipa hbacsvcgroup-add --desc=\"login services\" login\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñників до групи Ñлужб HBAC:\n" " ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login\n" "\n" " Показ даних щодо вказаної групи:\n" " ipa hbacsvcgroup-show login\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸ Ñлужб HBAC:\n" " ipa hbacsvcgroup-del login\n" msgid "HBAC service group" msgstr "група Ñлужб HBAC" msgid "HBAC service groups" msgstr "Група Ñлужб HBAC" msgid "HBAC Service Groups" msgstr "Група Ñлужб HBAC" msgid "HBAC Service Group" msgstr "Група Ñлужб HBAC" msgid "Service group name" msgstr "Ðазва групи Ñлужб" msgid "HBAC service group description" msgstr "ÐžÐ¿Ð¸Ñ Ð³Ñ€ÑƒÐ¿Ð¸ Ñлужб HBAC" msgid "Add a new HBAC service group." msgstr "Додати нову групу Ñлужб HBAC." #, python-format msgid "Added HBAC service group \"%(value)s\"" msgstr "Додано групу Ñлужб HBAC «%(value)s»" msgid "Delete an HBAC service group." msgstr "Вилучити групу Ñлужб HBAC." #, python-format msgid "Deleted HBAC service group \"%(value)s\"" msgstr "Вилучено групу Ñлужб HBAC «%(value)s»" msgid "Modify an HBAC service group." msgstr "Змінити групу Ñлужб HBAC." #, python-format msgid "Modified HBAC service group \"%(value)s\"" msgstr "Змінено групу Ñлужб HBAC «%(value)s»" msgid "Search for an HBAC service group." msgstr "Шукати групу Ñлужб HBAC." #, python-format msgid "%(count)d HBAC service group matched" msgid_plural "%(count)d HBAC service groups matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d групи Ñлужб HBAC" msgstr[1] "вÑтановлено відповідніÑть %(count)d груп Ñлужб HBAC" msgstr[2] "вÑтановлено відповідніÑть %(count)d груп Ñлужб HBAC" msgid "Display information about an HBAC service group." msgstr "Показати дані щодо групи Ñлужб HBAC." msgid "Add members to an HBAC service group." msgstr "Додати учаÑників до групи Ñлужб HBAC." msgid "Remove members from an HBAC service group." msgstr "Вилучити учаÑників з групи Ñлужб HBAC." msgid "" "\n" "Simulate use of Host-based access controls\n" "\n" "HBAC rules control who can access what services on what hosts.\n" "You can use HBAC to control which users or groups can access a service,\n" "or group of services, on a target host.\n" "\n" "Since applying HBAC rules implies use of a production environment,\n" "this plugin aims to provide simulation of HBAC rules evaluation without\n" "having access to the production environment.\n" "\n" " Test user coming to a service on a named host against\n" " existing enabled rules.\n" "\n" " ipa hbactest --user= --host= --service=\n" " [--rules=rules-list] [--nodetail] [--enabled] [--disabled]\n" " [--sizelimit= ]\n" "\n" " --user, --host, and --service are mandatory, others are optional.\n" "\n" " If --rules is specified simulate enabling of the specified rules and test\n" " the login of the user using only these rules.\n" "\n" " If --enabled is specified, all enabled HBAC rules will be added to " "simulation\n" "\n" " If --disabled is specified, all disabled HBAC rules will be added to " "simulation\n" "\n" " If --nodetail is specified, do not return information about rules matched/" "not matched.\n" "\n" " If both --rules and --enabled are specified, apply simulation to --rules " "_and_\n" " all IPA enabled rules.\n" "\n" " If no --rules specified, simulation is run against all IPA enabled rules.\n" " By default there is a IPA-wide limit to number of entries fetched, you can " "change it\n" " with --sizelimit option.\n" "\n" "EXAMPLES:\n" "\n" " 1. Use all enabled HBAC rules in IPA database to simulate:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 2. Disable detailed summary of how rules were applied:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail\n" " --------------------\n" " Access granted: True\n" " --------------------\n" "\n" " 3. Test explicitly specified HBAC rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: myrule\n" "\n" " 4. Use all enabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --enabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 5. Test all disabled HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: new-rule\n" "\n" " 6. Test all disabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" "\n" " 7. Test all (enabled and disabled) HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --enabled --disabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Not matched rules: new-rule\n" " Matched rules: allow_all\n" "\n" "\n" "HBACTEST AND TRUSTED DOMAINS\n" "\n" "When an external trusted domain is configured in IPA, HBAC rules are also " "applied\n" "on users accessing IPA resources from the trusted domain. Trusted domain " "users and\n" "groups (and their SIDs) can be then assigned to external groups which can " "be\n" "members of POSIX groups in IPA which can be used in HBAC rules and thus " "allowing\n" "access to resources protected by the HBAC system.\n" "\n" "hbactest plugin is capable of testing access for both local IPA users and " "users\n" "from the trusted domains, either by a fully qualified user name or by user " "SID.\n" "Such user names need to have a trusted domain specified as a short name\n" "(DOMAIN\\Administrator) or with a user principal name (UPN), " "Administrator@ad.test.\n" "\n" "Please note that hbactest executed with a trusted domain user as --user " "parameter\n" "can be only run by members of \"trust admins\" group.\n" "\n" "EXAMPLES:\n" "\n" " 1. Test if a user from a trusted domain specified by its shortname " "matches any\n" " rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Administrator' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 2. Test if a user from a trusted domain specified by its domain name " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 3. Test if a user from a trusted domain specified by its SID matches any " "rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 4. Test if other user from a trusted domain specified by its SID matches " "any rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" "\n" " 5. Test if other user from a trusted domain specified by its shortname " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Otheruser' --host `hostname` --service " "sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" msgstr "" "\n" "Ð†Ð¼Ñ–Ñ‚Ð°Ñ†Ñ–Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів (HBAC)\n" "\n" "Правила HBAC керують тим, хто може отримувати доÑтуп до певних Ñлужб на\n" "певних вузлах.\n" "Ви можете ÑкориÑтатиÑÑ HBAC Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð¸Ð¼, Ñкі кориÑтувачі або групи\n" "на початковому вузлі можуть отримувати доÑтуп до Ñлужби або групи Ñлужб\n" "на вузлі призначеннÑ\n" "\n" "ОÑкільки заÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» HBAC передбачає викориÑÑ‚Ð°Ð½Ð½Ñ Ñ€Ð¾Ð±Ð¾Ñ‡Ð¾Ð³Ð¾\n" "Ñередовища, це додаток призначено Ð´Ð»Ñ Ñ–Ð¼Ñ–Ñ‚Ð°Ñ†Ñ–Ñ— обробки правил HBAC без\n" "доÑтупу до реального Ñередовища\n" "\n" " Перевірити відповідніÑть кориÑтувача з початкового вузла до Ñлужби на " "іменованому\n" " вузлі правилам ÑƒÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупу.\n" "\n" " ipa hbactest --user= --host= --service=\n" " [--rules=rules-list] [--nodetail] [--enabled] [--disabled]\n" " [--sizelimit= ]\n" "\n" " --user, --host Ñ– --service Ñ” обов’Ñзковими, інші можна не вказувати.\n" "\n" " Якщо вказано --rules, імітувати Ð²Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¸Ñ… правил Ñ– перевірити\n" " можливіÑть входу кориÑтувача у разі викориÑÑ‚Ð°Ð½Ð½Ñ Ð»Ð¸ÑˆÐµ цих правил.\n" "\n" " Якщо вказано --enabled, додати вÑÑ– увімкнені правила HBAC до імітації\n" "\n" " Якщо вказано --disabled, додати вÑÑ– вимкнені правила HBAC до імітації\n" "\n" " Якщо вказано --nodetail, не повертати даних щодо відповідних Ñ– " "невідповідних\n" " правил.\n" "\n" " Якщо вказано одночаÑно --rules Ñ– --enabled, виконати імітацію --rules _Ñ–_\n" " вÑÑ–Ñ… увімкнених правил IPA.\n" "\n" " Якщо не вказано --rules, буде виконано імітацію вÑÑ–Ñ… увімкнених правил " "IPA.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " 1. ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… увімкнених правил HBAC у базі даних IPA:\n" " $ ipa hbactest --user=a1a --srchost=foo --host=bar --service=sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " невідповідне: my-second-rule\n" " невідповідне: my-third-rule\n" " невідповідне: myrule\n" " відповідне: allow_all\n" "\n" " 2. Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð´Ð¾ÐºÐ»Ð°Ð´Ð½Ð¾Ð³Ð¾ резюме заÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" "\n" " 3. Перевірити Ñвно вказані правила HBAC:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --rules=my-" "second-rule,myrule\n" " ---------------------\n" " Ðадано доÑтуп: ÐÑ–\n" " ---------------------\n" " невідповідне: my-second-rule\n" " невідповідне: myrule\n" "\n" " 4. ВикориÑÑ‚Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… увімкнених правил HBAC у базі даних IPA + Ñвно " "вказаних правил:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --rules=my-" "second-rule,myrule --enabled\n" " --------------------\n" " ДоÑтуп надано: Так\n" " --------------------\n" " невідповідне: my-second-rule\n" " невідповідне: my-third-rule\n" " невідповідне: myrule\n" " відповідне: allow_all\n" "\n" " 5. Перевірка вÑÑ–Ñ… вимкнених правил HBAC у базі даних IPA:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled\n" " ---------------------\n" " Ðадано доÑтуп: ÐÑ–\n" " ---------------------\n" " невідповідне: new-rule\n" "\n" " 6. Перевірка вÑÑ–Ñ… вимкнених правил HBAC у базі даних IPA + Ñвно вказані " "правила:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --rules=my-" "second-rule,myrule --disabled\n" " ---------------------\n" " Ðадано доÑтуп: ÐÑ–\n" " ---------------------\n" " невідповідне: my-second-rule\n" " невідповідне: my-third-rule\n" " невідповідне: myrule\n" "\n" " 7. Перевірка вÑÑ–Ñ… (увімкнених Ñ– вимкнених) правил HBAC у базі даних " "IPA:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --enabled " "--disabled\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " невідповідне: my-second-rule\n" " невідповідне: my-third-rule\n" " невідповідне: myrule\n" " невідповідне: new-rule\n" " відповідне: allow_all\n" "\n" "\n" "HBACTEST І ДОВІРЕÐІ ДОМЕÐИ\n" "\n" "Якщо у IPA налаштовано зовнішній довірений домен, правила HBAC також\n" "заÑтоÑовуютьÑÑ Ð´Ð¾ кориÑтувачів, що отримують доÑтуп до реÑурÑів IPA з\n" "з довіреного домену. ПіÑÐ»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ кориÑтувачі Ñ– групи довіреного домену\n" "(на їхні SID) може бути прив’Ñзано до зовнішніх груп, Ñкі можуть бути\n" "учаÑниками груп POSIX у IPA. Такі прив’Ñзки може бути викориÑтано у\n" "правилах HBAC, отже ÑƒÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупу до реÑурÑів, захищених ÑиÑтемою\n" "HBAC.\n" "\n" "Додаток hbactest здатен теÑтувати доÑтуп Ñк Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¸Ñ… кориÑтувачів\n" "IPA, так Ñ– кориÑтувачів з довірених доменів, Ñк за повним іменем\n" "кориÑтувача, так Ñ– за SID кориÑтувачів. У таких іменах кориÑтувачів\n" "має бути вказано Ñкорочено довірений домен (ДОМЕÐ\\Administrator) або\n" "назву реєÑтраційного запиÑу кориÑтувача (UPN), Administrator@ad.test.\n" "\n" "Будь лаÑка, зауважте, що виконувати hbactest з аргументом кориÑтувача\n" "довіреного домену у параметрі --user можуть виконувати лише учаÑники\n" "групи «trust admins».\n" "\n" "ПРИКЛÐД:\n" "\n" " 1. Перевірити, чи відповідає кориÑтувач з довіреного домену,\n" " вказаний за коротким іменем, ÑкомуÑÑŒ правилу:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Administrator' --host `hostname` --" "service sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " Відповідні правила: allow_all\n" " Відповідні правила: can_login\n" "\n" " 2. Перевірити, чи відповідає кориÑтувач з довіреного домену,\n" " вказаний за назвою його домену, ÑкомуÑÑŒ правилу:\n" "\n" " $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --" "service sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " Відповідні правила: allow_all\n" " Ðевідповідні правила: can_login\n" "\n" " 3. Перевірити, чи відповідає кориÑтувач з довіреного домену\n" " вказаний за SID, ÑкомуÑÑŒ правилу:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " Відповідні правила: allow_all\n" " Відповідні правила: can_login\n" "\n" " 4. Перевірити, чи відповідає інший кориÑтувач з довіреного домену,\n" " вказаний за SID, ÑкомуÑÑŒ правилу:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " Відповідні правила: allow_all\n" " Відповідні правила: can_login\n" "\n" " 5. Перевірити, чи відповідає інший кориÑтувач з довіреного домену,\n" " вказаний за коротким ім’Ñм, ÑкомуÑÑŒ правилу:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Otheruser' --host `hostname` --service " "sshd\n" " --------------------\n" " Ðадано доÑтуп: Так\n" " --------------------\n" " Відповідні правила: allow_all\n" " Ðевідповідні правила: can_login\n" msgid "Simulate use of Host-based access controls" msgstr "Імітувати викориÑÑ‚Ð°Ð½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів" msgid "Warning" msgstr "ПопередженнÑ" msgid "Matched rules" msgstr "Відповідні правила" msgid "Not matched rules" msgstr "Ðевідповідні правила" msgid "Non-existent or invalid rules" msgstr "Ðекоректні правила або правила, Ñких не Ñ–Ñнує" msgid "Result of simulation" msgstr "Результат імітації" msgid "User name" msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача" msgid "Target host" msgstr "Вузол призначеннÑ" msgid "Rules to test. If not specified, --enabled is assumed" msgstr "" "Правила Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸. Якщо не вказано, вважаєтьÑÑ, що викориÑтано --enabled." msgid "Hide details which rules are matched, not matched, or invalid" msgstr "" "Приховати дані щодо того, Ñкі правила Ñ” відповідними, Ñкі не Ñ” відповідними " "Ñ– Ñкі Ñ” некоректними" msgid "Include all enabled IPA rules into test [default]" msgstr "Перевірити вÑÑ– увімкнені правила IPA [типова поведінка]" msgid "Include all disabled IPA rules into test" msgstr "Перевірити вÑÑ– вимкнені правила IPA" msgid "Maximum number of rules to process when no --rules is specified" msgstr "" "МакÑимальна кількіÑть правил, Ñкі Ñлід обробити, Ñкщо не вказано параметра --" "rules" msgid "Unresolved rules in --rules" msgstr "Ðепридатні до обробки правила у --rules" msgid "" "Cannot search in trusted domains without own domain configured. Make sure " "you have run ipa-adtrust-install on the IPA server first" msgstr "" "Без Ð½Ð°Ð»Ð°ÑˆÑ‚Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð»Ð°Ñного домену не можна виконувати пошук у довірених " "доменах. Спочатку запуÑтіть ipa-adtrust-install на Ñервері IPA." #, python-format msgid "Access granted: %s" msgstr "Ðадано доÑтуп: %s" msgid "" "\n" "Hosts/Machines\n" "\n" "A host represents a machine. It can be used in a number of contexts:\n" "- service entries are associated with a host\n" "- a host stores the host/ service principal\n" "- a host can be used in Host-based Access Control (HBAC) rules\n" "- every enrolled client generates a host entry\n" "\n" "ENROLLMENT:\n" "\n" "There are three enrollment scenarios when enrolling a new client:\n" "\n" "1. You are enrolling as a full administrator. The host entry may exist\n" " or not. A full administrator is a member of the hostadmin role\n" " or the admins group.\n" "2. You are enrolling as a limited administrator. The host must already\n" " exist. A limited administrator is a member a role with the\n" " Host Enrollment privilege.\n" "3. The host has been created with a one-time password.\n" "\n" "A host can only be enrolled once. If a client has enrolled and needs to\n" "be re-enrolled, the host entry must be removed and re-created. Note that\n" "re-creating the host entry will result in all services for the host being\n" "removed, and all SSL certificates associated with those services being\n" "revoked.\n" "\n" "A host can optionally store information such as where it is located,\n" "the OS that it runs, etc.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host:\n" " ipa host-add --location=\"3rd floor lab\" --locality=Dallas test.example." "com\n" "\n" " Delete a host:\n" " ipa host-del test.example.com\n" "\n" " Add a new host with a one-time password:\n" " ipa host-add --os='Fedora 12' --password=Secret123 test.example.com\n" "\n" " Add a new host with a random one-time password:\n" " ipa host-add --os='Fedora 12' --random test.example.com\n" "\n" " Modify information about a host:\n" " ipa host-mod --os='Fedora 12' test.example.com\n" "\n" " Remove SSH public keys of a host and update DNS to reflect this change:\n" " ipa host-mod --sshpubkey= --updatedns test.example.com\n" "\n" " Disable the host Kerberos key, SSL certificate and all of its services:\n" " ipa host-disable test.example.com\n" "\n" " Add a host that can manage this host's keytab and certificate:\n" " ipa host-add-managedby --hosts=test2 test\n" msgstr "" "\n" "Вузли/Комп’ютери\n" "\n" "Одному вузлу відповідає один комп’ютер. Вузол може бути викориÑтано\n" "у декількох контекÑтах:\n" "- запиÑи Ñлужб, пов’Ñзані з вузлом;\n" "- на вузлі зберігаєтьÑÑ Ñ€ÐµÑ”Ñтраційний Ð·Ð°Ð¿Ð¸Ñ Ñлужби вузла\n" "- вузол може бути викориÑтано у правилах Host-based Access Control (HBAC);\n" "- Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ зареєÑтрованого клієнта ÑтворюєтьÑÑ Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð°.\n" "\n" "РЕЄСТРÐЦІЯ:\n" "\n" "Передбачено три Ñценарії реєÑтрації нового клієнта:\n" "\n" "1. РеєÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ Ð¿Ð¾Ð²Ð½Ð¾Ñ†Ñ–Ð½Ð½Ð¾Ð³Ð¾ адмініÑтратора. Відповідний Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð° може " "Ñ–Ñнувати\n" " або не Ñ–Ñнувати. Повноцінний адмініÑтратор Ñ” учаÑником ролі hostadmin " "або\n" " групи admins.\n" "2. РеєÑÑ‚Ñ€Ð°Ñ†Ñ–Ñ Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð¾Ð³Ð¾ адмініÑтратора. Відповідний Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð° вже має " "Ñ–Ñнувати\n" " Обмежений адмініÑтратор Ñ” учаÑником розі з правами реєÑтрації вузлів.\n" "3. Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу вузла з одноразовим паролем.\n" "\n" "РеєÑтрувати вузол можна лише один раз. Якщо клієнт було зареєÑтровано Ñ– " "виникла\n" "потреба у перереєÑтрації, Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð° Ñлід вилучити Ñ– Ñтворити повторно.\n" "Зауважте, що повторне ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу вузла призведе до вилученнÑ\n" "вÑÑ–Ñ… Ñлужб вузла та Ð²Ñ–Ð´ÐºÐ»Ð¸ÐºÐ°Ð½Ð½Ñ Ð²ÑÑ–Ñ… Ñертифікатів SSL, пов’Ñзаних з цими\n" "Ñлужбами.\n" "\n" "У запиÑÑ– вузла додатково можуть зберігатиÑÑ Ð´Ð°Ð½Ñ– щодо його розташуваннÑ,\n" "вÑтановленої на ньому операційної ÑиÑтеми тощо.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ вузла:\n" " ipa host-add --location=\"3rd floor lab\" --locality=Dallas test.example." "com\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ð°:\n" " ipa host-del test.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ вузла з одноразовим паролем:\n" " ipa host-add --os='Fedora 12' --password=Secret123 test.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ вузла з випадковим одноразовим паролем:\n" " ipa host-add --os='Fedora 12' --random test.example.com\n" "\n" " Зміна даних щодо вузла:\n" " ipa host-mod --os='Fedora 12' test.example.com\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸Ñ… ключів SSH вузла Ñ– Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ DNS відповідно до внеÑених " "змін:\n" " ipa host-mod --sshpubkey= --updatedns test.example.com\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° Kerberos вузла, Ñертифіката SSL та вÑÑ–Ñ… його Ñлужб:\n" " ipa host-disable test.example.com\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð²ÑƒÐ·Ð»Ð°, Ñкий може керувати таблицею ключів Ñ– Ñертифікатів\n" " цього вузла:\n" " ipa host-add-managedby --hosts=test2 test\n" msgid "Keytab" msgstr "Ð¢Ð°Ð±Ð»Ð¸Ñ†Ñ ÐºÐ»ÑŽÑ‡Ñ–Ð²" msgid "Serial Number" msgstr "Серійний номер" msgid "Serial Number (hex)" msgstr "Серійний номер (шіÑтнадцÑтковий)" msgid "Failed managedby" msgstr "Помилка managedby" msgid "SSH public key fingerprint" msgstr "Відбиток відкритого ключа SSH" msgid "host" msgstr "вузол" msgid "hosts" msgstr "вузли" msgid "Host" msgstr "Вузол" msgid "Host name" msgstr "Ðазва вузла" msgid "A description of this host" msgstr "ÐžÐ¿Ð¸Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вузла" msgid "Locality" msgstr "ÐдреÑа" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "ÐдреÑа Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÑƒÐ·Ð»Ð° (наприклад, «Київ, Україна»)" msgid "Host location (e.g. \"Lab 2\")" msgstr "Ð Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ð²ÑƒÐ·Ð»Ð° (наприклад, «Lab 2»)" msgid "Platform" msgstr "Платформа" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "Ðпаратна платформа вузла (наприклад, «Lenovo T61»)" msgid "Operating system" msgstr "Операційна ÑиÑтема" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "Операційна ÑиÑтема вузла Ñ– Ñ—Ñ— верÑÑ–Ñ (наприклад, «Fedora 9\")" msgid "User password" msgstr "Пароль кориÑтувача" msgid "Password used in bulk enrollment" msgstr "Пароль Ð´Ð»Ñ Ð·Ð°Ð³Ð°Ð»ÑŒÐ½Ð¾Ð³Ð¾ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑ”Ñтраційними запиÑами" msgid "Generate a random password to be used in bulk enrollment" msgstr "" "Створити випадковий пароль, Ñкий буде викориÑтано Ð´Ð»Ñ Ð·Ð°Ð³Ð°Ð»ÑŒÐ½Ð¾Ñ— реєÑтрації" msgid "Random password" msgstr "Випадковий пароль" msgid "Base-64 encoded server certificate" msgstr "Сертифікат Ñервера у кодуванні Base-64" msgid "Principal name" msgstr "Ðазва реєÑтраційного запиÑу" msgid "MAC address" msgstr "MAC-адреÑа" msgid "Hardware MAC address(es) on this host" msgstr "Ðпаратні MAC-адреÑи цього вузла" msgid "SSH public key" msgstr "Відкритий ключ SSH" msgid "" "Host category (semantics placed on this attribute are for local " "interpretation)" msgstr "" "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð²ÑƒÐ·Ð»Ñ–Ð² (Ñемантика Ñ€Ð¾Ð·Ñ‚Ð°ÑˆÑƒÐ²Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ атрибуту призначена Ð´Ð»Ñ " "локальної обробки)" msgid "Add a new host." msgstr "Додати новий Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð°." #, python-format msgid "Added host \"%(value)s\"" msgstr "Додано вузол «%(value)s»" msgid "force host name even if not in DNS" msgstr "примуÑове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ вузла, навіть Ñкщо назви немає у DNS" msgid "skip reverse DNS detection" msgstr "пропуÑтити зворотне Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ DNS" msgid "Add the host to DNS with this IP address" msgstr "Додати Ð·Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð° до DNS з цією IP-адреÑою" #, python-format msgid "The host was added but the DNS update failed with: %(exc)s" msgstr "" "Ð—Ð°Ð¿Ð¸Ñ Ð²ÑƒÐ·Ð»Ð° було додано, але Ñпроба Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ DNS зазнала невдачі: %(exc)s" msgid "Delete a host." msgstr "Вилучити вузол." #, python-format msgid "Deleted host \"%(value)s\"" msgstr "Вилучено вузол «%(value)s»" msgid "Remove entries from DNS" msgstr "Вилучити запиÑи з DNS" msgid "Modify information about a host." msgstr "Змінити дані щодо вузла." #, python-format msgid "Modified host \"%(value)s\"" msgstr "Змінено вузол «%(value)s»" msgid "Kerberos principal name for this host" msgstr "Ðазва реєÑтраційного запиÑу Kerberos Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вузла" msgid "Update DNS entries" msgstr "Оновити запиÑи DNS" msgid "Password cannot be set on enrolled host." msgstr "Ðе можна визначати пароль Ð´Ð»Ñ Ð²ÑƒÐ·Ð»Ð° з визначеною роллю." msgid "cn is immutable" msgstr "cn Ñ” незмінним" msgid "Search for hosts." msgstr "Шукати вузли." #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d вузла" msgstr[1] "вÑтановлено відповідніÑть %(count)d вузлів" msgstr[2] "вÑтановлено відповідніÑть %(count)d вузлів" msgid "Display information about a host." msgstr "Показати дані щодо вузла." msgid "file to store certificate in" msgstr "файл, у Ñкому зберігатимутьÑÑ Ð´Ð°Ð½Ñ– Ñертифіката" #, python-format msgid "Certificate stored in file '%(file)s'" msgstr "Сертифікат збережено у файлі «%(file)s»" msgid "Disable the Kerberos key, SSL certificate and all services of a host." msgstr "Вимкнути ключ Kerberos, Ñертифікат SSL Ñ– вÑÑ– Ñлужби на вузлі." #, python-format msgid "Disabled host \"%(value)s\"" msgstr "Вимкнено вузол «%(value)s»" msgid "Add hosts that can manage this host." msgstr "Додати запиÑи вузлів, Ñкі можуть керувати цим вузлом." msgid "Remove hosts that can manage this host." msgstr "Вилучити запиÑи вузлів, Ñкі можуть керувати цим вузлом." msgid "" "\n" "Groups of hosts.\n" "\n" "Manage groups of hosts. This is useful for applying access control to a\n" "number of hosts by using Host-based Access Control.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host group:\n" " ipa hostgroup-add --desc=\"Baltimore hosts\" baltimore\n" "\n" " Add another new host group:\n" " ipa hostgroup-add --desc=\"Maryland hosts\" maryland\n" "\n" " Add members to the hostgroup (using Bash brace expansion):\n" " ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore\n" "\n" " Add a hostgroup as a member of another hostgroup:\n" " ipa hostgroup-add-member --hostgroups=baltimore maryland\n" "\n" " Remove a host from the hostgroup:\n" " ipa hostgroup-remove-member --hosts=box2 baltimore\n" "\n" " Display a host group:\n" " ipa hostgroup-show baltimore\n" "\n" " Delete a hostgroup:\n" " ipa hostgroup-del baltimore\n" msgstr "" "\n" "Групи вузлів.\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð°Ð¼Ð¸ вузлів. КориÑні Ð´Ð»Ñ Ð·Ð°ÑтоÑÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ\n" "до декількох вузлів на оÑнові заÑнованого на вузлах керуваннÑ\n" "доÑтупом (Host-based Access Control або HBAC).\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— групи вузлів:\n" " ipa hostgroup-add --desc=\"Baltimore hosts\" baltimore\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— групи вузлів:\n" " ipa hostgroup-add --desc=\"Maryland hosts\" maryland\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñників до групи вузлів з викориÑтаннÑм виразу Bash у фігурних " "дужках):\n" " ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸ вузлів Ñк учаÑника іншої групи вузлів:\n" " ipa hostgroup-add-member --hostgroups=baltimore maryland\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²ÑƒÐ·Ð»Ð° з групи вузлів:\n" " ipa hostgroup-remove-member --hosts=box2 baltimore\n" "\n" " Показ ÑпиÑку групи вузлів:\n" " ipa hostgroup-show baltimore\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸ вузлів:\n" " ipa hostgroup-del baltimore\n" msgid "host group" msgstr "група вузлів" msgid "host groups" msgstr "групи вузлів" msgid "Host Group" msgstr "Група вузлів" msgid "Host-group" msgstr "Група вузлів" msgid "Name of host-group" msgstr "Ðазва групи вузлів" msgid "A description of this host-group" msgstr "ÐžÐ¿Ð¸Ñ Ñ†Ñ–Ñ”Ñ— групи вузлів" msgid "Add a new hostgroup." msgstr "Додати нову групу вузлів." #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "Додано групу вузлів «%(value)s»" #, python-format msgid "" "netgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "Мережеву групу з назвою «%s» вже Ñтворено. Групи вузлів Ñ– мережеві групи " "мають Ñпільний проÑтір назв." msgid "Delete a hostgroup." msgstr "Вилучити групу вузлів." #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "Вилучено групу вузлів «%(value)s»" msgid "Modify a hostgroup." msgstr "Змінити групу вузлів." #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "Змінено групу вузлів «%(value)s»" msgid "Search for hostgroups." msgstr "Шукати групи вузлів." #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d групи вузлів" msgstr[1] "вÑтановлено відповідніÑть %(count)d груп вузлів" msgstr[2] "вÑтановлено відповідніÑть %(count)d груп вузлів" msgid "Display information about a hostgroup." msgstr "Показати дані щодо групи вузлів." msgid "Add members to a hostgroup." msgstr "Додати запиÑи до групи вузлів." msgid "Remove members from a hostgroup." msgstr "Вилучити запиÑи з групи вузлів." msgid "" "\n" "ID ranges\n" "\n" "Manage ID ranges used to map Posix IDs to SIDs and back.\n" "\n" "There are two type of ID ranges which are both handled by this utility:\n" "\n" " - the ID ranges of the local domain\n" " - the ID ranges of trusted remote domains\n" "\n" "Both types have the following attributes in common:\n" "\n" " - base-id: the first ID of the Posix ID range\n" " - range-size: the size of the range\n" "\n" "With those two attributes a range object can reserve the Posix IDs starting\n" "with base-id up to but not including base-id+range-size exclusively.\n" "\n" "Additionally an ID range of the local domain may set\n" " - rid-base: the first RID(*) of the corresponding RID range\n" " - secondary-rid-base: first RID of the secondary RID range\n" "\n" "and an ID range of a trusted domain must set\n" " - rid-base: the first RID of the corresponding RID range\n" " - sid: domain SID of the trusted domain\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for a trusted domain\n" "\n" "Since there might be more than one trusted domain the domain SID must be " "given\n" "while creating the ID range.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\\n" " --dom-sid=S-1-5-21-123-456-789 trusted_dom_range\n" "\n" "This ID range is then used by the IPA server and the SSSD IPA provider to\n" "assign Posix UIDs to users from the trusted domain.\n" "\n" "If e.g a range for a trusted domain is configured with the following " "values:\n" " base-id = 1200000\n" " range-size = 200000\n" " rid-base = 0\n" "the RIDs 0 to 199999 are mapped to the Posix ID from 1200000 to 13999999. " "So\n" "RID 1000 <-> Posix ID 1201000\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for the local domain\n" "\n" "To create an ID range for the local domain it is not necessary to specify a\n" "domain SID. But since it is possible that a user and a group can have the " "same\n" "value as Posix ID a second RID interval is needed to handle conflicts.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\\n" " --secondary-rid-base=1000000 local_range\n" "\n" "The data from the ID ranges of the local domain are used by the IPA server\n" "internally to assign SIDs to IPA users and groups. The SID will then be " "stored\n" "in the user or group objects.\n" "\n" "If e.g. the ID range for the local domain is configured with the values " "from\n" "the example above then a new user with the UID 1200007 will get the RID " "1007.\n" "If this RID is already used by a group the RID will be 1000007. This can " "only\n" "happen if a user or a group object was created with a fixed ID because the\n" "automatic assignment will not assign the same ID twice. Since there are " "only\n" "users and groups sharing the same ID namespace it is sufficient to have " "only\n" "one fallback range to handle conflicts.\n" "\n" "To find the Posix ID for a given RID from the local domain it has to be\n" "checked first if the RID falls in the primary or secondary RID range and\n" "the rid-base or the secondary-rid-base has to be subtracted, respectively,\n" "and the base-id has to be added to get the Posix ID.\n" "\n" "Typically the creation of ID ranges happens behind the scenes and this CLI\n" "must not be used at all. The ID range for the local domain will be created\n" "during installation or upgrade from an older version. The ID range for a\n" "trusted domain will be created together with the trust by 'ipa trust-" "add ...'.\n" "\n" "USE CASES:\n" "\n" " Add an ID range from a transitively trusted domain\n" "\n" " If the trusted domain (A) trusts another domain (B) as well and this " "trust\n" " is transitive 'ipa trust-add domain-A' will only create a range for\n" " domain A. The ID range for domain B must be added manually.\n" "\n" " Add an additional ID range for the local domain\n" "\n" " If the ID range of the local domain is exhausted, i.e. no new IDs can " "be\n" " assigned to Posix users or groups by the DNA plugin, a new range has to " "be\n" " created to allow new users and groups to be added. (Currently there is " "no\n" " connection between this range CLI and the DNA plugin, but a future " "version\n" " might be able to modify the configuration of the DNS plugin as well)\n" "\n" "In general it is not necessary to modify or delete ID ranges. If there is " "no\n" "other way to achieve a certain configuration than to modify or delete an ID\n" "range it should be done with great care. Because UIDs are stored in the " "file\n" "system and are used for access control it might be possible that users are\n" "allowed to access files of other users if an ID range got deleted and " "reused\n" "for a different domain.\n" "\n" "(*) The RID is typically the last integer of a user or group SID which " "follows\n" "the domain SID. E.g. if the domain SID is S-1-5-21-123-456-789 and a user " "from\n" "this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of " "the\n" "user. RIDs are unique in a domain, 32bit values and are used for users and\n" "groups.\n" "\n" "WARNING:\n" "\n" "DNA plugin in 389-ds will allocate IDs based on the ranges configured for " "the\n" "local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" "on the local ranges set via this family of commands.\n" "\n" "Manual configuration change has to be done in the DNA plugin configuration " "for\n" "the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to " "be\n" "modified to match the new range.\n" msgstr "" "\n" "Діапазони ідентифікаторів\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ð°Ð¼Ð¸ ідентифікаторів, викориÑтаних Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ\n" "ідентифікаторів POSIX на SID, Ñ– навпаки.\n" "\n" "За допомогою цієї програми можна керувати обома типами діапазонів " "ідентифікаторів:\n" "\n" " - діапазони ідентифікаторів локального домену\n" " - діапазони ідентифікаторів довірених віддалених доменів\n" "\n" "Обидва типи мають такі Ñпільні атрибути:\n" "\n" " - base-id: перший ідентифікатор діапазону ідентифікаторів POSIX\n" " - range-size: розмір діапазону\n" "\n" "Ðа оÑнові цих двох атрибутів об’єкт діапазону може зарезервувати " "ідентифікатори\n" "POSIX, починаючи з base-id аж до, але не включно, base-id+range-size.\n" "\n" "Крім того, можна вÑтановити діапазон ідентифікаторів локального домену\n" " - rid-base: перший RID(*) відповідного діапазону RID\n" " - secondary-rid-base: перший RID вторинного діапазону RID\n" "\n" "а діапазон ідентифікаторів довіреного домену Ñлід задавати за допомогою\n" " - rid-base: перший RID відповідного діапазону RID\n" " - dom_sid: SID довіреного домену\n" "\n" "\n" "\n" "ПРИКЛÐД: Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ діапазону ідентифікаторів Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену\n" "\n" "ОÑкільки може бути декілька довірених доменів, під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñƒ\n" "ідентифікаторів Ñлід вказати SID домену.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\\n" " --dom-sid=S-1-5-21-123-456-789 trusted_dom_range\n" "\n" "Цей діапазон ідентифікаторів потім викориÑтовуватиметьÑÑ Ñервером IPA\n" "та надавачем даних IPA SSSD Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ UID Posix кориÑтувачам з\n" "довіреного домену.\n" "\n" "Якщо, наприклад, налаштовано діапазон Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену з такими\n" "значеннÑми:\n" " base-id = 1200000\n" " range-size = 200000\n" " rid-base = 0\n" "RID від 0 до 199999 прив’ÑзуютьÑÑ Ð´Ð¾ ідентифікаторів Posix від 1200000 до\n" "13999999. Отже RID 1000 <-> Posix ID 1201000\n" "\n" "\n" "\n" "ПРИКЛÐД: Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ діапазону ідентифікаторів до локального домену\n" "\n" "Щоб Ñтворити діапазон ідентифікаторів Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену не потрібно\n" "вказувати SID домену. Ðле оÑкільки можливий конфлікт між ідентифікаторами\n" "кориÑтувача Ñ– групи та ідентифікаторами POSIX, потрібен вторинний інтервал\n" "RID.\n" "\n" " ipa range-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\\n" " --secondary-rid-base=1000000 local_range\n" "\n" "Дані з діапазонів ідентифікаторів локального домену викориÑтовуютьÑÑ\n" "Ñервером IPA на внутрішньому рівні Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ SID кориÑтувачам Ñ– " "групам\n" "IPA. SID буде збережено у об’єктах кориÑтувача або групи.\n" "\n" "Якщо, наприклад, Ð´Ð»Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñƒ ідентифікаторів локального домену визначено\n" "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· наведеного вище прикладу, новий кориÑтувач з UID 1200007 отримає\n" "RID 1007. Якщо цей RID вже буде викориÑтано групою, його буде змінено на " "1000007.\n" "Таке може трапитиÑÑ Ð»Ð¸ÑˆÐµ, Ñкщо об’єкт кориÑтувача або групи було Ñтворено з\n" "фікÑованим ідентифікатором, оÑкільки у разі автоматичного Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¾Ð´Ð¸Ð½\n" "ідентифікатор не може бути призначено двічі. ОÑкільки Ñпільний проÑтір назв\n" "Ñ” лише у кориÑтувачів Ñ– груп, доÑтатньо одного резервного діапазону длÑ\n" "того, щоб повніÑтю позбутиÑÑ ÐºÐ¾Ð½Ñ„Ð»Ñ–ÐºÑ‚Ñ–Ð².\n" "\n" "Ð”Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ‚Ð¾Ñ€Ð° POSIX за вказаним RID з локального домену " "Ñлід\n" "Ñпочатку перевірити, чи потраплÑÑ” RID у оÑновний або вторинний діапазон " "RID,\n" "також, щоб отримати ідентифікатор POSIX, Ñлід віднÑти від ідентифікатор rid-" "base\n" "або secondary-rid-base, відповідно, Ñ– додати base-id.\n" "\n" "Типово, ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñ–Ð² ідентифікаторів Ñ” зовні непомітним Ñ– потреби у\n" "цьому інтерфейÑÑ– командного Ñ€Ñдка не виникає. Діапазон ідентифікаторів\n" "Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену буде Ñтворено під Ñ‡Ð°Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð°Ð±Ð¾ оновленнÑ\n" "попередньої верÑÑ–Ñ—. Діапазон ідентифікаторів Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену буде\n" "Ñтворено разом з запиÑом довіри командою «ipa trust-add ...».\n" "Ðижче наведено можливі випадки викориÑÑ‚Ð°Ð½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ командного інтерфейÑу.\n" "\n" "ВИПÐДКИ ВИКОРИСТÐÐÐЯ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñƒ ідентифікаторів з перехідного довіреного домену\n" "\n" " Якщо довірений домен (A) довірÑєтьÑÑ Ñ–Ð½ÑˆÐ¾Ð¼Ñƒ домену (B) Ñ– цей запиÑ\n" " довіри Ñ” перехідним, «ipa trust-add домен-A» Ñтворить лише діапазон\n" " Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ A. Діапазон ідентифікаторів домену B має бути додано вручну.\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ð³Ð¾ діапазону ідентифікаторів Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену\n" "\n" " Якщо діапазон ідентифікаторів локального домену вичерпано, тобто " "додатком\n" " DNA не може бути призначено нові ідентифікатори кориÑтувачам або групам\n" " POSIX, має бути Ñтворено новий діапазон Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… " "кориÑтувачів\n" " та груп. (У поточній верÑÑ–Ñ— між цим командним інтерфейÑом Ñ– додатком " "DNA\n" " немає безпоÑереднього зв’Ñзку, але у майбутній верÑÑ–Ñ— може бути " "передбачено\n" " можливіÑть внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ Ñ– до налаштувань додатка DNS.)\n" "\n" "Загалом, потреби у зміні або вилученні діапазонів ідентифікаторів немає.\n" "Якщо немає іншого виходу, окрім внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ або Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñƒ\n" "ідентифікаторів, робити це Ñлід дуже обережно. ОÑкільки UID зберігаютьÑÑ Ñƒ\n" "файловій ÑиÑтемі Ñ– викориÑтовуютьÑÑ Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом, можлива " "ÑитуаціÑ,\n" "коли одні кориÑтувачі отримуватимуть доÑтуп до файлів інших кориÑтувачів\n" "у разі Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð´Ñ–Ð°Ð¿Ð°Ð·Ð¾Ð½Ñƒ ідентифікаторів Ñ– повторного його викориÑтаннÑ\n" "у іншому домені.\n" "\n" "(*) RID типово Ñ” оÑтаннім цілим чиÑлом SID кориÑтувача або групи, перед " "Ñкими\n" "має бути вказано SID домену. Ðаприклад, Ñкщо SID домену " "S-1-5-21-123-456-789, а\n" "кориÑтувач з цього домену має SID S-1-5-21-123-456-789-1010, RID " "кориÑтувача\n" "буде 1010. RID Ñ” унікальними в межах домену, Ñ” 32-бітовими значеннÑм Ñ–\n" "викориÑтовуютьÑÑ Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів Ñ– груп.\n" "\n" "ПОПЕРЕДЖЕÐÐЯ:\n" "\n" "Додаток DNA у 389-ds розміщуватиме ідентифікатори на оÑнові діапазонів\n" "налаштованих Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену. У поточній верÑÑ–Ñ— додаток DNA *не " "можна*\n" "переналаштовувати ÑамоÑтійно на оÑнові локальних діапазонів, вÑтановлених\n" "за допомогою цього ÑімейÑтва команд.\n" "\n" "Зміни налаштувань вручну має бути виконано у налаштуваннÑÑ… додатка DNA\n" "Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ діапазону. Зокрема Ñлід змінити атрибут dnaNextRange " "«cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config» так, щоб\n" "він відповідав новому діапазону.\n" msgid "ID Ranges" msgstr "Діапазони ідентифікаторів" msgid "ID Range" msgstr "Діапазон ідентифікаторів" msgid "local domain range" msgstr "локальний діапазон доменів" msgid "Active Directory winsync range" msgstr "Діапазон winsync Active Directory" msgid "Active Directory domain range" msgstr "Діапазон доменів Active Directory" msgid "Active Directory trust range with POSIX attributes" msgstr "Діапазон довіри Active Directory з атрибутами POSIX" msgid "IPA trust range" msgstr "Діапазон довіри IPA" msgid "Range name" msgstr "Ðазва діапазону" msgid "First Posix ID of the range" msgstr "Перший ідентифікатор POSIX діапазону" msgid "Number of IDs in the range" msgstr "КількіÑть ідентифікаторів у діапазоні" msgid "First RID of the corresponding RID range" msgstr "Перший RID відповідного діапазону RID" msgid "First RID of the secondary RID range" msgstr "Перший RID вторинного діапазону RID" msgid "Domain SID of the trusted domain" msgstr "SID довіреного домену" msgid "Name of the trusted domain" msgstr "Ðазва довіреного домену" msgid "Range type" msgstr "Тип діапазону" msgid "ID range type, one of {vals}" msgstr "Тип діапазону ідентифікаторів, одне з таких значень: {vals}" msgid "" "range modification leaving objects with ID out of the defined range is not " "allowed" msgstr "" "не можна виконувати зміни діапазону, у результаті Ñких виникають об’єкти з " "ідентифікаторами поза визначеним діапазоном" msgid "" "Cannot perform SID validation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA on the server" msgstr "" "Виконати дію з перевірки SID без вÑтановленої підтримки Samba 4 неможливо. " "ПереконайтеÑÑ, що вами вÑтановлено на Ñервері підпакунок IPA server-trust-ad." msgid "" "Cross-realm trusts are not configured. Make sure you have run ipa-adtrust-" "install on the IPA server first" msgstr "" "Зв’Ñзки довіри між облаÑÑ‚Ñми не налаштовано. Спочатку запуÑтіть ipa-adtrust-" "install на Ñервері IPA." msgid "SID is not recognized as a valid SID for a trusted domain" msgstr "SID не розпізнано Ñк чинний SID Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену" msgid "" "\n" " Add new ID range.\n" "\n" " To add a new ID range you always have to specify\n" "\n" " --base-id\n" " --range-size\n" "\n" " Additionally\n" "\n" " --rid-base\n" " --secondary-rid-base\n" "\n" " may be given for a new ID range for the local domain while\n" "\n" " --rid-base\n" " --dom-sid\n" "\n" " must be given to add a new range for a trusted AD domain.\n" "\n" " WARNING:\n" "\n" " DNA plugin in 389-ds will allocate IDs based on the ranges configured " "for the\n" " local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" " on the local ranges set via this family of commands.\n" "\n" " Manual configuration change has to be done in the DNA plugin " "configuration for\n" " the new local range. Specifically, The dnaNextRange attribute of " "'cn=Posix\n" " IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has " "to be\n" " modified to match the new range.\n" " " msgstr "" "\n" " Додати новий діапазон ідентифікаторів.\n" "\n" " Ð”Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ діапазону ідентифікаторів вам Ñлід завжди " "вказувати\n" "\n" " --base-id\n" " --range-size\n" "\n" " Крім того, може бути надано\n" "\n" " --rid-base\n" " --econdary-rid-base\n" "\n" " Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ діапазону ідентифікаторів Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену Ñ–\n" "\n" " --rid-base\n" " --dom-sid\n" "\n" " Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ діапазону Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену AD.\n" "\n" " ПОПЕРЕДЖЕÐÐЯ:\n" "\n" " Додаток DNA у 389-ds визначатиме ідентифікатори у діапазонах, " "налаштованих\n" " Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену. У поточній верÑÑ–Ñ— додаток DNA *не може* змінити\n" " влаÑні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° оÑнові локальних діапазонів, вÑтановлених за\n" " допомогою цього ÑімейÑтва команд.\n" "\n" " Ð”Ð»Ñ Ð²Ð½ÐµÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ щодо локального діапазону Ñлід змінити налаштуваннÑ\n" " додатка DNA вручну. Зокрема, Ñлід внеÑти зміни до атрибута 'cn=Posix\n" " IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' " "відповідно\n" " до параметрів нового діапазону.\n" " " #, python-format msgid "Added ID range \"%(value)s\"" msgstr "Додано діапазон ідентифікаторів «%(value)s»" msgid "Options dom-sid and dom-name cannot be used together" msgstr "Параметри dom-sid Ñ– dom-name не можна викориÑтовувати разом" msgid "" "SID for the specified trusted domain name could not be found. Please specify " "the SID directly using dom-sid option." msgstr "" "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ SID Ð´Ð»Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¾Ð³Ð¾ довіреного домену. Будь лаÑка, вкажіть " "SID безпоÑередньо за допомогою параметра dom-sid." msgid "" "IPA Range type must be one of ipa-ad-trust or ipa-ad-trust-posix when SID of " "the trusted domain is specified." msgstr "" "Якщо вказано SID довіреного домену, типом діапазону IPA має бути ipa-ad-" "trust або ipa-ad-trust-posix." msgid "Options dom-sid/dom-name and secondary-rid-base cannot be used together" msgstr "" "Параметри dom-sid/dom-name Ñ– secondary-rid-base не можна викориÑтовувати " "разом" msgid "Options dom-sid/dom-name and rid-base must be used together" msgstr "Параметри dom-sid/dom-name Ñ– rid-base Ñлід викориÑтовувати разом" msgid "" "IPA Range type must not be one of ipa-ad-trust or ipa-ad-trust-posix when " "SID of the trusted domain is not specified." msgstr "" "Якщо не вказано SID довіреного домену, типом діапазону IPA не може бути ipa-" "ad-trust або ipa-ad-trust-posix." msgid "Options secondary-rid-base and rid-base must be used together" msgstr "Параметри secondary-rid-base Ñ– rid-base Ñлід викориÑтовувати разом" msgid "Primary RID range and secondary RID range cannot overlap" msgstr "" "ОÑновний діапазон RID Ñ– вторинний діапазон RID не повинні перекриватиÑÑ" msgid "" "You must specify both rid-base and secondary-rid-base options, because ipa-" "adtrust-install has already been run." msgstr "" "Вам Ñлід вказати обидва параметри, rid-base Ñ– secondary-rid-base, оÑкільки " "вже запущено ipa-adtrust-install." msgid "Delete an ID range." msgstr "Вилучити діапазон ідентифікаторів." #, python-format msgid "Deleted ID range \"%(value)s\"" msgstr "Вилучено діапазон ідентифікаторів «%(value)s»" msgid "Search for ranges." msgstr "Шукати діапазони." #, python-format msgid "%(count)d range matched" msgid_plural "%(count)d ranges matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d діапазону" msgstr[1] "вÑтановлено відповідніÑть %(count)d діапазонів" msgstr[2] "вÑтановлено відповідніÑть %(count)d діапазонів" msgid "Display information about a range." msgstr "Показати дані щодо діапазону." msgid "Modify ID range." msgstr "Змінити діапазон ідентифікаторів." #, python-format msgid "Modified ID range \"%(value)s\"" msgstr "Змінено діапазон ідентифікаторів «%(value)s»" msgid "Options dom-sid and secondary-rid-base cannot be used together" msgstr "Параметри dom-sid Ñ– secondary-rid-base не можна викориÑтовувати разом" msgid "Options dom-sid and rid-base must be used together" msgstr "Параметри dom-sid Ñ– rid-base Ñлід викориÑтовувати разом" msgid "Name of object to export" msgstr "Ðазва об’єкта, Ñкий Ñлід екÑпортувати" msgid "Name of method to export" msgstr "Ðазва методу, Ñкий буде екÑпортовано" msgid "Name of command to export" msgstr "Ðазва команди Ð´Ð»Ñ ÐµÐºÑпортуваннÑ" msgid "Dict of JSON encoded IPA Objects" msgstr "Словник закодованих JSON об’єктів IPA" msgid "Dict of JSON encoded IPA Methods" msgstr "Словник JSON-закодованих методів IPA" msgid "Dict of JSON encoded IPA Commands" msgstr "Словник закодованих JSON команд IPA" msgid "Your session has expired. Please re-login." msgstr "" "Строк роботи у вашому ÑеанÑÑ– вичерпано. Будь лаÑка, увійдіть до ÑиÑтеми ще " "раз." msgid "Apply" msgstr "ЗаÑтоÑувати" msgid "Are you sure you want to proceed with the action." msgstr "Ви Ñправді хочете виконати цю дію?" msgid "Are you sure you want to delete ${object}" msgstr "Ви Ñправді хочете вилучити ${object}" msgid "Are you sure you want to disable ${object}" msgstr "Ви Ñправді хочете вимкнути ${object}" msgid "Are you sure you want to enable ${object}" msgstr "Ви Ñправді хочете увімкнути ${object}" msgid "Actions" msgstr "Дії" msgid "Add RunAs ${other_entity} into ${entity} ${primary_key}" msgstr "Додати ${other_entity} запуÑк від імені до ${entity} ${primary_key}" msgid "Add RunAs Groups into ${entity} ${primary_key}" msgstr "Додати групи запуÑку від імені до ${entity} ${primary_key}" msgid "Add ${other_entity} Managing ${entity} ${primary_key}" msgstr "Додати ${other_entity}, ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ${entity} ${primary_key}" msgid "Add ${other_entity} into ${entity} ${primary_key}" msgstr "Додати ${other_entity} до ${entity} ${primary_key}" msgid "Add Allow ${other_entity} into ${entity} ${primary_key}" msgstr "Додано дозвіл ${other_entity} до ${entity} ${primary_key}" msgid "Add Deny ${other_entity} into ${entity} ${primary_key}" msgstr "Додано заборону ${other_entity} до ${entity} ${primary_key}" msgid "Add ${entity} ${primary_key} into ${other_entity}" msgstr "Додати ${entity} ${primary_key} до ${other_entity}" msgid "${count} item(s) added" msgstr "Додано ${count} запиÑів" msgid "Direct Membership" msgstr "БезпоÑÐµÑ€ÐµÐ´Ð½Ñ ÑƒÑ‡Ð°Ñть" msgid "Indirect Membership" msgstr "ОпоÑередкована учаÑть" msgid "No entries." msgstr "Ðемає запиÑів." msgid "Showing ${start} to ${end} of ${total} entries." msgstr "Показано запиÑи від ${start} до ${end} з ${total} запиÑів." msgid "Remove RunAs ${other_entity} from ${entity} ${primary_key}" msgstr "Вилучити ${other_entity} запуÑку від імені з ${entity} ${primary_key}" msgid "Remove RunAs Groups from ${entity} ${primary_key}" msgstr "Вилучити групи запуÑку від імені з ${entity} ${primary_key}" msgid "Remove ${other_entity} Managing ${entity} ${primary_key}" msgstr "Вилучити ${other_entity}, ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ${entity} ${primary_key}" msgid "Remove ${other_entity} from ${entity} ${primary_key}" msgstr "Вилучити ${other_entity} з ${entity} ${primary_key}" msgid "Remove Allow ${other_entity} from ${entity} ${primary_key}" msgstr "Вилучити дозвіл ${other_entity} з ${entity} ${primary_key}" msgid "Remove Deny ${other_entity} from ${entity} ${primary_key}" msgstr "Вилучити заборону ${other_entity} з ${entity} ${primary_key}" msgid "Remove ${entity} ${primary_key} from ${other_entity}" msgstr "Вилучити ${entity} ${primary_key} з ${other_entity}" msgid "${count} item(s) removed" msgstr "Вилучено ${count} запиÑів" msgid "Show Results" msgstr "Показати результати" msgid "Add" msgstr "Додати" msgid "Add and Add Another" msgstr "Додати Ñ– додати ще" msgid "Add and Close" msgstr "Додати Ñ– закрити" msgid "Add and Edit" msgstr "Додати Ñ– змінити" msgid "Add Many" msgstr "Додати багато" msgid "Back" msgstr "Ðазад" msgid "Cancel" msgstr "СкаÑувати" msgid "Close" msgstr "Закрити" msgid "Disable" msgstr "Вимкнути" msgid "Edit" msgstr "Змінити" msgid "Enable" msgstr "Увімкнути" msgid "Find" msgstr "Знайти" msgid "Get" msgstr "Отримати" msgid "Issue" msgstr "Створити" msgid "OK" msgstr "Гаразд" msgid "Refresh" msgstr "Оновити" msgid "Delete" msgstr "Вилучити" msgid "Reset" msgstr "Скинути" msgid "Reset Password and Login" msgstr "Скинути пароль Ñ– увійти" msgid "Restore" msgstr "Відновити" msgid "Retry" msgstr "Повторити" msgid "Revoke" msgstr "Відкликати" msgid "Set" msgstr "Ð’Ñтановити" msgid "Update" msgstr "Оновити" msgid "View" msgstr "ПереглÑд" msgid "Collapse All" msgstr "Згорнути вÑÑ–" msgid "Expand All" msgstr "Розгорнути вÑÑ–" msgid "General" msgstr "Загальне" msgid "Identity Settings" msgstr "Параметри профілю" msgid "${entity} ${primary_key} Settings" msgstr "Параметри ${primary_key} ${entity}" msgid "Back to Top" msgstr "ПовернутиÑÑ Ð´Ð¾ початку" msgid "${entity} ${primary_key} updated" msgstr "Оновлено ${primary_key} ${entity}" msgid "${entity} successfully added" msgstr "${entity} уÑпішно додано" msgid "Add ${entity}" msgstr "Додати ${entity}" msgid "Available" msgstr "ДоÑтупний" msgid "Some operations failed." msgstr "ДеÑкі з дій не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸." msgid "Operations Error" msgstr "Помилка під Ñ‡Ð°Ñ Ð¾Ð±Ñ€Ð¾Ð±ÐºÐ¸" msgid "Confirmation" msgstr "ПідтвердженнÑ" msgid "This page has unsaved changes. Please save or revert." msgstr "" "Ðа цій Ñторінці виÑвлено незбережені зміни. Будь лаÑка, збережіть зміни або " "ÑкаÑуйте Ñ—Ñ…." msgid "Unsaved Changes" msgstr "Ðезбережені зміни" msgid "Edit ${entity}" msgstr "Змінити ${entity}" msgid "Hide details" msgstr "Сховати подробиці" msgid "Prospective" msgstr "Очікуваний" msgid "Redirection" msgstr "ПереÑпрÑмуваннÑ" msgid "Select entries to be removed." msgstr "Виберіть запиÑи, Ñкі Ñлід вилучити." msgid "Remove ${entity}" msgstr "Вилучити ${entity}" msgid "Show details" msgstr "Показати подробиці" msgid "Validation error" msgstr "Помилка під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸" msgid "Input form contains invalid or missing values." msgstr "" "У форму Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… не введено деÑкі з даних або у формі міÑÑ‚ÑтьÑÑ " "некоректні запиÑи." msgid "Please try the following options:" msgstr "Будь лаÑка, Ñпробуйте такі параметри:" msgid "If the problem persists please contact the system administrator." msgstr "" "Якщо проблему не вдаÑтьÑÑ ÑƒÑунути, звернітьÑÑ Ð´Ð¾ адмініÑтратора ÑиÑтеми." msgid "Refresh the page." msgstr "Оновити Ñторінку." msgid "Reload the browser." msgstr "Перезавантажити переглÑдач." msgid "Return to the main page and retry the operation" msgstr "ПовернутиÑÑ Ð´Ð¾ головної Ñторінки Ñ– повторити Ñпробу" msgid "An error has occurred (${error})" msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° (${error})" msgid "HTTP Error" msgstr "Помилка HTTP" msgid "Internal Error" msgstr "Ð’Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°" msgid "IPA Error" msgstr "Помилка IPA" msgid "No response" msgstr "Ðемає відповіді" msgid "Unknown Error" msgstr "Ðевідома помилка" msgid "URL" msgstr "ÐдреÑа" msgid "${primary_key} is managed by:" msgstr "${primary_key} керуєтьÑÑ:" msgid "${primary_key} members:" msgstr "УчаÑники ${primary_key}:" msgid "${primary_key} is a member of:" msgstr "${primary_key} міÑтитьÑÑ Ñƒ:" msgid "Settings" msgstr "Параметри" msgid "Search" msgstr "Пошук" msgid "False" msgstr "ÐÑ–" msgid "Inherited from server configuration" msgstr "УÑпадковано з налаштувань Ñервера" msgid "MS-PAC" msgstr "MS-PAC" msgid "Override inherited settings" msgstr "Перевизначити уÑпадковані параметри" msgid "PAD" msgstr "PAD" msgid "" "To login with username and password, enter them in the fields below then " "click Login." msgstr "" "Щоб увійти з викориÑтаннÑм певного імені кориÑтувача Ñ– паролÑ, вкажіть Ñ—Ñ… у " "наведених нижче полÑÑ…, а потім натиÑніть кнопку «Увійти»." msgid "Logged In As" msgstr "Вхід до ÑиÑтеми від імені" msgid "" "To login with Kerberos, please make sure you have valid tickets (obtainable " "via kinit) and configured the browser correctly, then click Login." msgstr "" "Щоб увійти за допомогою Kerberos, будь лаÑка, переконайтеÑÑ, що маєте чинні " "квитки (ці квитки можна отримати за допомогою kinit) Ñ– що програму Ð´Ð»Ñ " "переглÑду Ñторінок інтернету налаштовано належним чином, а потім натиÑніть кнопку «Увійти»." msgid "Login" msgstr "Увійти" msgid "Logout" msgstr "Вийти" msgid "Logout error" msgstr "Помилка під Ñ‡Ð°Ñ Ð²Ð¸Ñ…Ð¾Ð´Ñƒ" msgid "Username" msgstr "КориÑтувач" msgid "number of passwords" msgstr "кількіÑть паролів" msgid "seconds" msgstr "Ñекунд" msgid "Attribute" msgstr "Ðтрибут" msgid "Add Condition into ${pkey}" msgstr "Додати умову до ${pkey}" msgid "Add Rule" msgstr "Додати правило" msgid "Default host group" msgstr "Типова група вузлів" msgid "Default user group" msgstr "Типова група кориÑтувачів" msgid "Exclusive" msgstr "Виключна" msgid "Expression" msgstr "Вираз" msgid "Host group rule" msgstr "Правило групи вузлів" msgid "Host group rules" msgstr "Правила груп вузлів" msgid "Inclusive" msgstr "Включна" msgid "User group rule" msgstr "Правило групи кориÑтувачів" msgid "User group rules" msgstr "Правила груп кориÑтувачів" msgid "Automount Location Settings" msgstr "Параметри запиÑу автомонтуваннÑ" msgid "Map Type" msgstr "Тип карти" msgid "Direct" msgstr "БезпоÑередній" msgid "Indirect" msgstr "ОпоÑередкований" msgid "AA Compromise" msgstr "ÐšÐ¾Ð¼Ð¿Ñ€Ð¾Ð¼ÐµÑ‚Ð°Ñ†Ñ–Ñ AA" msgid "Affiliation Changed" msgstr "Змінено міÑце роботи" msgid "CA Compromise" msgstr "ÐšÐ¾Ð¼Ð¿Ñ€Ð¾Ð¼ÐµÑ‚Ð°Ñ†Ñ–Ñ CA" msgid "Certificates" msgstr "Сертифікати" msgid "Certificate Hold" msgstr "ВлаÑник Ñертифіката" msgid "Cessation of Operation" msgstr "СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ñ–Ñ—" msgid "Common Name" msgstr "Звичайне ім'Ñ" msgid "Expires On" msgstr "Строк дії" msgid "Issued on from" msgstr "Видано з" msgid "Issued on to" msgstr "Видано до" msgid "Maximum serial number" msgstr "МакÑимальний Ñерійний номер" msgid "Minimum serial number" msgstr "Мінімальний Ñерійний номер" msgid "Revoked on from" msgstr "Відкликано з" msgid "Revoked on to" msgstr "Відкликано до" msgid "Valid not after from" msgstr "Чинний не пізніше піÑлÑ" msgid "Valid not after to" msgstr "Чинний не пізніше до" msgid "Valid not before from" msgstr "Чинний не раніше від" msgid "Valid not before to" msgstr "Чинний не раніше" msgid "Fingerprints" msgstr "Відбитки" msgid "Issue New Certificate for ${entity} ${primary_key}" msgstr "Створити Ñертифікат Ð´Ð»Ñ ${primary_key} ${entity}" msgid "Issued By" msgstr "Видавець" msgid "Issued On" msgstr "Видано" msgid "Issued To" msgstr "Видано длÑ" msgid "Key Compromise" msgstr "ÐšÐ¾Ð¼Ð¿Ñ€Ð¾Ð¼ÐµÑ‚Ð°Ñ†Ñ–Ñ ÐºÐ»ÑŽÑ‡Ð°" msgid "MD5 Fingerprint" msgstr "Відбиток MD5" msgid "No Valid Certificate" msgstr "Ðемає чинних Ñертифікатів" msgid "New Certificate" msgstr "Ðовий Ñертифікат" msgid "Note" msgstr "Ðотатка" msgid "Organization" msgstr "УÑтанова" msgid "Organizational Unit" msgstr "Підрозділ уÑтанови" msgid "Privilege Withdrawn" msgstr "Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ÐºÐ»Ð¸ÐºÐ°Ð½Ð¾" msgid "Reason for Revocation" msgstr "Причина відкликаннÑ" msgid "Remove from CRL" msgstr "Вилучити з CRL" msgid "" "
  1. Create a certificate database or use an existing one. To create a " "new database:
    # certutil -N -d <database path>
  2. " "
  3. Create a CSR with subject CN=<hostname>,O=<realm>, " "for example:
    # certutil -R -d <database path> -a -g <key " "size> -s 'CN=${hostname},O=${realm}'
  4. Copy and paste the " "CSR (from -----BEGIN NEW CERTIFICATE REQUEST----- to -----END " "NEW CERTIFICATE REQUEST-----) into the text area below:
" msgstr "" "
  1. Створити базу даних Ñертифікатів або ÑкориÑтатиÑÑ Ð²Ð¶Ðµ Ñтвореною. " "Щоб Ñтворити нову базу даних, віддайте команду:
    # certutil -N -d " "<шлÑÑ… до бази даних>
  2. Створити CSR з призначеннÑм " "CN=<назва вузла>,O=<облаÑть>, наприклад:
    # " "certutil -R -d <шлÑÑ… до бази даних> -a -g <розмір ключа> -s 'CN=" "${hostname},O=${realm}'
  3. Скопіюйте Ñ– вÑтавте CSR (від " "-----BEGIN NEW CERTIFICATE REQUEST----- до -----END NEW " "CERTIFICATE REQUEST-----) до облаÑті Ð´Ð»Ñ Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ñ‚ÐµÐºÑту, розташованої " "нижче:
" msgid "Certificate requested" msgstr "ÐадіÑлано запит щодо Ñертифікації" msgid "Restore Certificate for ${entity} ${primary_key}" msgstr "Відновити Ñертифікат Ð´Ð»Ñ ${primary_key} ${entity}" msgid "Restore Certificate" msgstr "Відновити Ñертифікат" msgid "" "To confirm your intention to restore this certificate, click the \"Restore\" " "button." msgstr "" "Щоб підтвердити ваш намір відновити цей Ñертифікат, натиÑніть кнопку " "«Відновити»." msgid "Certificate restored" msgstr "Сертифікат відновлено" msgid "Revoke Certificate for ${entity} ${primary_key}" msgstr "Відкликати Ñертифікат Ð´Ð»Ñ ${primary_key} ${entity}" msgid "Revoke Certificate" msgstr "Відкликати Ñертифікат" msgid "" "To confirm your intention to revoke this certificate, select a reason from " "the pull-down list, and click the \"Revoke\" button." msgstr "" "Щоб підтвердити ваш намір відкликати цей Ñертифікат, виберіть причину зі " "Ñпадного ÑпиÑку Ñ– натиÑніть кнопку «Відкликати»." msgid "Certificate Revoked" msgstr "Сертифікат відкликано" msgid "SHA1 Fingerprint" msgstr "Відбиток SHA1" msgid "Superseded" msgstr "Замінено" msgid "Unspecified" msgstr "Ðе вказано" msgid "Valid Certificate Present" msgstr "Є чинний Ñертифікат" msgid "Validity" msgstr "КоректніÑть" msgid "Certificate for ${entity} ${primary_key}" msgstr "Сертифікат Ð´Ð»Ñ ${primary_key} ${entity}" msgid "Group Options" msgstr "Параметри групи" msgid "Search Options" msgstr "Параметри пошуку" msgid "SELinux Options" msgstr "Параметри SELinux" msgid "Service Options" msgstr "Параметри Ñлужби" msgid "User Options" msgstr "Параметри кориÑтувача" msgid "Forward first" msgstr "Спочатку переÑпрÑмувати" msgid "Forwarding disabled" msgstr "ПереÑпрÑÐ¼Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾" msgid "Forward only" msgstr "Лише переÑпрÑмовувати" msgid "Options" msgstr "Параметри" msgid "Data" msgstr "Дані" msgid "DNS record was deleted because it contained no data." msgstr "Ð—Ð°Ð¿Ð¸Ñ DNS було вилучено, оÑкільки у ньому не міÑтилоÑÑ Ð¶Ð¾Ð´Ð½Ð¸Ñ… даних." msgid "Other Record Types" msgstr "Інші типи запиÑів" msgid "Address not valid, can't redirect" msgstr "ÐдреÑа Ñ” некоректною. ПереÑпрÑÐ¼ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ðµ." msgid "Create dns record" msgstr "Створити Ð·Ð°Ð¿Ð¸Ñ DNS" msgid "Creating record." msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу." msgid "Record creation failed." msgstr "Спроба ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу зазнала невдачі." msgid "Checking if record exists." msgstr "Перевірка, чи Ñ–Ñнує запиÑ." msgid "Record not found." msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð½Ðµ знайдено." msgid "Redirection to PTR record" msgstr "ПереÑпрÑÐ¼Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° Ð·Ð°Ð¿Ð¸Ñ PTR" msgid "Zone found: ${zone}" msgstr "ВиÑвлено зону: ${zone}" msgid "Target reverse zone not found." msgstr "Ðе знайдено зворотної зони призначеннÑ." msgid "Fetching DNS zones." msgstr "ÐžÑ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… щодо зон DNS." msgid "An error occurred while fetching dns zones." msgstr "Під Ñ‡Ð°Ñ Ñпроби Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… щодо зон DNS ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°." msgid "You will be redirected to DNS Zone." msgstr "Ð’Ð°Ñ Ð±ÑƒÐ´Ðµ переÑпрÑмовано до зони DNS." msgid "Standard Record Types" msgstr "Стандартні типи запиÑів" msgid "Records for DNS Zone" msgstr "ЗапиÑи зони DNS" msgid "Record Type" msgstr "Тип запиÑу" msgid "DNS Zone Settings" msgstr "Параметри зони DNS" msgid "Add Permission" msgstr "Додати права доÑтупу" msgid "Remove Permission" msgstr "Вилучити права доÑтупу" msgid "Group Settings" msgstr "Параметри групи" msgid "External" msgstr "Зовнішній" msgid "Change to external group" msgstr "Змінити на зовнішню групу" msgid "Change to POSIX group" msgstr "Змінити на групу POSIX" msgid "Normal" msgstr "Звичайний" msgid "POSIX" msgstr "POSIX" msgid "Group Type" msgstr "Тип групи" msgid "Any Host" msgstr "Будь-Ñкий вузол" msgid "Any Service" msgstr "Будь-Ñка Ñлужба" msgid "Anyone" msgstr "Будь-хто" msgid "Accessing" msgstr "ДоÑтуп" msgid "Rule status" msgstr "Стан правила" msgid "Via Service" msgstr "Проміжна Ñлужба" msgid "Specified Hosts and Groups" msgstr "Вказані вузли Ñ– групи" msgid "Specified Services and Groups" msgstr "Вказані Ñлужби Ñ– групи" msgid "Specified Users and Groups" msgstr "Вказані кориÑтувачі Ñ– групи" msgid "Who" msgstr "Хто" msgid "Access Denied" msgstr "ДоÑтуп заборонено" msgid "Access Granted" msgstr "Ðадано доÑтуп" msgid "Include Disabled" msgstr "Ð’ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾" msgid "Include Enabled" msgstr "Ð’ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð¾" msgid "HBAC Test" msgstr "ТеÑÑ‚ HBAC" msgid "Matched" msgstr "Ð’Ñтановлено відповідніÑть" msgid "Missing values: " msgstr "Пропущені значеннÑ: " msgid "New Test" msgstr "Ðовий текÑÑ‚" msgid "Rules" msgstr "Правила" msgid "Run Test" msgstr "ЗапуÑтити теÑт…" msgid "Specify external ${entity}" msgstr "Вкажіть зовнішній ${entity}" msgid "Unmatched" msgstr "Ðевідповідний" msgid "Host Certificate" msgstr "Сертифікат вузла" msgid "Host Name" msgstr "Ðазва вузла" msgid "Delete Key, Unprovision" msgstr "Вилучити ключ, ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð±Ð°Ñ‡ÐµÐ½Ð½Ñ" msgid "Host Settings" msgstr "Параметри вузла" msgid "Enrolled" msgstr "ЗареєÑтровано" msgid "Enrollment" msgstr "РеєÑтраціÑ" msgid "Fully Qualified Host Name" msgstr "Повна назва вузла" msgid "Kerberos Key" msgstr "Ключ Kerberos" msgid "Kerberos Key Not Present" msgstr "Ключа Kerberos немає" msgid "Kerberos Key Present, Host Provisioned" msgstr "Маємо ключ Kerberos, вузол передбачено" msgid "One-Time-Password" msgstr "Одноразовий пароль" msgid "One-Time-Password Not Present" msgstr "Одноразового Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð½ÐµÐ¼Ð°Ñ”" msgid "One-Time-Password Present" msgstr "Є одноразовий пароль" msgid "Reset OTP" msgstr "Скинути ОП" msgid "Reset One-Time-Password" msgstr "Скинути одноразовий пароль" msgid "Set OTP" msgstr "Одноразовий пароль" msgid "OTP set" msgstr "Ð’Ñтановлено одноразовий пароль" msgid "Set One-Time-Password" msgstr "Ð’Ñтановити одноразовий пароль" msgid "Unprovision" msgstr "СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð±Ð°Ñ‡ÐµÐ½Ð½Ñ" msgid "Are you sure you want to unprovision this host?" msgstr "Ви Ñправді бажаєте ÑкаÑувати Ð¿ÐµÑ€ÐµÐ´Ð±Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вузла?" msgid "Unprovisioning ${entity}" msgstr "СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ´Ð±Ð°Ñ‡ÐµÐ½Ð½Ñ ${entity}" msgid "Host unprovisioned" msgstr "Вузол не передбачено" msgid "Host Group Settings" msgstr "Параметри групи вузлів" msgid "Kerberos Ticket Policy" msgstr "Правила квитків Kerberos" msgid "Netgroup Settings" msgstr "Параметри мережевої групи" msgid "User" msgstr "КориÑтувач" msgid "Identity" msgstr "Профіль" msgid "Permission with invalid target specification" msgstr "Права доÑтупу з некоректним визначеннÑм призначеннÑ" msgid "Privilege Settings" msgstr "Параметри уповноваженнÑ" msgid "Password Policy" msgstr "Правила Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²" msgid "Range Settings" msgstr "Параметри діапазону" msgid "Base ID" msgstr "ОÑнова ID" msgid "Primary RID base" msgstr "Головна оÑнова RID" msgid "Range size" msgstr "Розмір діапазону" msgid "Domain SID" msgstr "Домен SID" msgid "Secondary RID base" msgstr "Вторинна оÑнова RID" msgid "Active Directory domain" msgstr "Домен Active Directory" msgid "Active Directory domain with POSIX attributes" msgstr "Домен Active Directory з атрибутами POSIX" msgid "Local domain" msgstr "Локальний домен" msgid "IPA trust" msgstr "Довіра IPA" msgid "Active Directory winsync" msgstr "winsync Active Directory" msgid "Realm Domains" msgstr "Домени облаÑті" msgid "Check DNS" msgstr "Перевірка DNS" msgid "Do you also want to perform DNS check?" msgstr "Хочете також виконати перевірку DNS?" msgid "Force Update" msgstr "ПримуÑове оновленнÑ" msgid "Role Settings" msgstr "Параметри ролей" msgid "Service Certificate" msgstr "Сертифікат Ñлужби" msgid "Service Settings" msgstr "Параметри Ñлужби" msgid "Provisioning" msgstr "ПередбаченнÑ" msgid "Are you sure you want to unprovision this service?" msgstr "Ви Ñправді бажаєте ÑкаÑувати Ð¿ÐµÑ€ÐµÐ´Ð±Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ†Ñ–Ñ”Ñ— Ñлужби?" msgid "Service unprovisioned" msgstr "Службу не передбачено" msgid "Kerberos Key Present, Service Provisioned" msgstr "Маємо ключ Kerberos, Ñлужбу передбачено" msgid "SSH public keys" msgstr "Відкриті ключі SSH" msgid "SSH public key:" msgstr "Відкритий ключ SSH:" msgid "Set SSH key" msgstr "Ð’Ñтановити ключ SSH" msgid "Show/Set key" msgstr "Показати або вÑтановити ключ" msgid "Modified: key not set" msgstr "Змінено: ключ не вÑтановлено" msgid "Modified" msgstr "Змінено" msgid "New: key not set" msgstr "Ðовий: ключ не вÑтановлено" msgid "New: key set" msgstr "Ðовий: ключ вÑтановлено" msgid "Groups" msgstr "Групи" msgid "Commands" msgstr "Команди" msgid "Allow" msgstr "Дозволити" msgid "Any Command" msgstr "Будь-Ñка команда" msgid "Any Group" msgstr "Будь-Ñка група" msgid "Run Commands" msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´" msgid "Deny" msgstr "Відмовити" msgid "Access this host" msgstr "ДоÑтуп до цього вузла" msgid "Option added" msgstr "Додано параметр" msgid "${count} option(s) removed" msgstr "Вилучено ${count} параметрів" msgid "As Whom" msgstr "Від імені" msgid "Specified Commands and Groups" msgstr "Вказані команди Ñ– групи" msgid "Specified Groups" msgstr "Вказані групи" msgid "Account" msgstr "Обліковий запиÑ" msgid "Administrative account" msgstr "ÐдмініÑтративний обліковий запиÑ" msgid "SID blacklists" msgstr "Чорні ÑпиÑки SID" msgid "Trust Settings" msgstr "Параметри довіри" msgid "Domain" msgstr "Домен" msgid "Establish using" msgstr "Ð’Ñтановити за допомогою" msgid "Domain NetBIOS name" msgstr "Ðазва домену у NetBIOS" msgid "Domain Security Identifier" msgstr "Ідентифікатор безпеки домену" msgid "Pre-shared password" msgstr "Попередньо оприлюднений пароль" msgid "Trust direction" msgstr "ÐапрÑмок довіри" msgid "Trust status" msgstr "Стан довіри" msgid "Trust type" msgstr "Тип довіри" msgid "Account Settings" msgstr "Параметри облікового запиÑу" msgid "Account Status" msgstr "Стан облікового запиÑу" msgid "Contact Settings" msgstr "Параметри контакту" msgid "Employee Information" msgstr "ВідомоÑті щодо працівника" msgid "Error changing account status" msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби зміни Ñтану облікового запиÑу" msgid "Password expiration" msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії паролÑ" msgid "Mailing Address" msgstr "ÐдреÑа ел. пошти" msgid "Misc. Information" msgstr "Інша інформаціÑ" msgid "" "Are you sure you want to ${action} the user?
The change will take effect " "immediately." msgstr "" "Ви Ñправді бажаєте виконати щодо кориÑтувача дію «${action}»?
Зміни буде " "внеÑено негайно." msgid "Click to ${action}" msgstr "ÐатиÑніть, щоб ${action}" msgid "Current Password" msgstr "Поточний пароль" msgid "Current password is required" msgstr "Слід вказати поточний пароль" msgid "Your password expires in ${days} days." msgstr "Строк дії вашого Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð±ÑƒÐ´Ðµ вичерпано за ${days} днів." msgid "The password or username you entered is incorrect." msgstr "Вами введено помилкове Ñ–Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача або пароль." msgid "New Password" msgstr "Ðовий пароль" msgid "New password is required" msgstr "Слід вказати новий пароль" msgid "Password change complete" msgstr "Зміну Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¾" msgid "Passwords must match" msgstr "Паролі мають збігатиÑÑ" msgid "Password reset was not successful." msgstr "Ðе вдалоÑÑ Ñкинути пароль." msgid "Reset Password" msgstr "Скинути пароль" msgid "Reset your password." msgstr "Скинути ваш пароль." msgid "Verify Password" msgstr "Повторіть пароль" msgid "Are you sure you want to delete selected entries?" msgstr "Ви Ñправді бажаєте вилучити позначені запиÑи?" msgid "${count} item(s) deleted" msgstr "Вилучено ${count} запиÑів" msgid "Are you sure you want to disable selected entries?" msgstr "Ви Ñправді хочете вимкнути позначені запиÑи?" msgid "${count} item(s) disabled" msgstr "Вимкнено ${count} запиÑів" msgid "Are you sure you want to enable selected entries?" msgstr "Ви Ñправді бажаєте увімкнути позначені запиÑи?" msgid "${count} item(s) enabled" msgstr "Увімкнено ${count} запиÑів" msgid "Some entries were not deleted" msgstr "ДеÑкі з запиÑів не вилучено" msgid "Quick Links" msgstr "Швидкі поÑиланнÑ" msgid "Select All" msgstr "Вибрати вÑе" msgid "" "Query returned more results than the configured size limit. Displaying the " "first ${counter} results." msgstr "" "За запитом повернуто більше за налаштоване макÑимальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ€ÐµÐ·ÑƒÐ»ÑŒÑ‚Ð°Ñ‚Ñ–Ð². " "Показано лише перші ${counter} результатів." msgid "Unselect All" msgstr "СкаÑувати вибір вÑього" msgid "Disabled" msgstr "Вимкнено" msgid "Audit" msgstr "Ðудит" msgid "Automember" msgstr "Ðвтоматична учаÑть" msgid "Automount" msgstr "Ðвтоматичне монтуваннÑ" msgid "DNS" msgstr "DNS" msgid "Host Based Access Control" msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові вузлів" msgid "IPA Server" msgstr "Сервер IPA" msgid "Policy" msgstr "Правила" msgid "Role Based Access Control" msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом на оÑнові ролей" msgid "Sudo" msgstr "Sudo" msgid "Trusts" msgstr "ЗапиÑи довіри" msgid "True" msgstr "Так" msgid "Next" msgstr "Далі" msgid "Page" msgstr "Сторінка" msgid "Prev" msgstr "Ðазад" msgid "undo" msgstr "ÑкаÑувати" msgid "undo all" msgstr "ÑкаÑувати вÑÑ– дії" msgid "Text does not match field pattern" msgstr "ТекÑÑ‚ не відповідає шаблону полÑ" msgid "Must be a decimal number" msgstr "Має бути деÑÑтковим чиÑлом" msgid "Must be an integer" msgstr "Має бути цілим чиÑлом" msgid "Not a valid IP address" msgstr "Ðекоректна IP-адреÑа" msgid "Not a valid IPv4 address" msgstr "Ðекоректна адреÑа IPv4" msgid "Not a valid IPv6 address" msgstr "Ðекоректна адреÑа IPv6" msgid "Maximum value is ${value}" msgstr "МакÑимальним Ñ” Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ${value}" msgid "Minimum value is ${value}" msgstr "Мінімальним Ñ” Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ${value}" msgid "Not a valid network address" msgstr "Ðекоректна адреÑа у мережі" msgid "'${port}' is not a valid port" msgstr "«${port}» не Ñ” коректним визначеннÑм порту" msgid "Required field" msgstr "Обов’Ñзкове поле" msgid "Unsupported value" msgstr "Ðепідтримуване значеннÑ" msgid "Dict of I18N messages" msgstr "Словник перекладених повідомлень" msgid "" "\n" "Kerberos ticket policy\n" "\n" "There is a single Kerberos ticket policy. This policy defines the\n" "maximum ticket lifetime and the maximum renewal age, the period during\n" "which the ticket is renewable.\n" "\n" "You can also create a per-user ticket policy by specifying the user login.\n" "\n" "For changes to the global policy to take effect, restarting the KDC service\n" "is required, which can be achieved using:\n" "\n" "service krb5kdc restart\n" "\n" "Changes to per-user policies take effect immediately for newly requested\n" "tickets (e.g. when the user next runs kinit).\n" "\n" "EXAMPLES:\n" "\n" " Display the current Kerberos ticket policy:\n" " ipa krbtpolicy-show\n" "\n" " Reset the policy to the default:\n" " ipa krbtpolicy-reset\n" "\n" " Modify the policy to 8 hours max life, 1-day max renewal:\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Display effective Kerberos ticket policy for user 'admin':\n" " ipa krbtpolicy-show admin\n" "\n" " Reset per-user policy for user 'admin':\n" " ipa krbtpolicy-reset admin\n" "\n" " Modify per-user policy for user 'admin':\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgstr "" "\n" "Правила квитків Kerberos\n" "\n" "Передбачено єдині правила квитків Kerberos. Ці правила визначають\n" "макÑимальний Ñтрок дії квитка та макÑимальний вік оновленнÑ, період,\n" "протÑгом Ñкого квиток можна поновити.\n" "\n" "Крім того, ви можете Ñтворити правила Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ñ… кориÑтувачів\n" "шлÑхом Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ–Ð¼ÐµÐ½Ñ– кориÑтувача.\n" "\n" "Щоб зміни у загальних правилах набули чинноÑті, Ñлід перезапуÑтити\n" "Ñлужбу KDC. Це можна зробити за допомогою такої команди:\n" "\n" "service krb5kdc restart\n" "\n" "Зміни у окремих правилах Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів набудуть чинноÑті негайно\n" "Ð´Ð»Ñ ÐºÐ²Ð¸Ñ‚ÐºÑ–Ð² нових запитів (наприклад, у відповідь на наÑтупний\n" "запуÑк кориÑтувачем kinit).\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Показ поточних правил квитків Kerberos:\n" " ipa krbtpolicy-show\n" "\n" " Відновити типові правила:\n" " ipa krbtpolicy-reset\n" "\n" " Зміна правил на 8-годинний Ñтрок дії, 1-денний Ñтрок поновленнÑ:\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Показ поточних правил квитків Kerberos Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача «admin»:\n" " ipa krbtpolicy-show admin\n" "\n" " Відновити окремі правила Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача «admin»:\n" " ipa krbtpolicy-reset admin\n" "\n" " Зміна окремих правил Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача «admin»:\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgid "kerberos ticket policy settings" msgstr "параметри правил квитків kerberos" msgid "Manage ticket policy for specific user" msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°Ð¼Ð¸ обробки квитків певного кориÑтувача" msgid "Max life" msgstr "МакÑ. Ñтрок дії" msgid "Maximum ticket life (seconds)" msgstr "МакÑимальний Ñтрок дії квитка (у Ñекундах)" msgid "Max renew" msgstr "МакÑ. вік поновленнÑ" msgid "Maximum renewable age (seconds)" msgstr "МакÑимальний вік, протÑгом Ñкого можливе Ð¿Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ (у Ñекундах)" msgid "Modify Kerberos ticket policy." msgstr "Змінити правила квитків Kerberos." msgid "Display the current Kerberos ticket policy." msgstr "Показати поточні правила квитків Kerberos." msgid "Reset Kerberos ticket policy to the default values." msgstr "Відновити типові правила квитків Kerberos." msgid "" "\n" "Migration to IPA\n" "\n" "Migrate users and groups from an LDAP server to IPA.\n" "\n" "This performs an LDAP query against the remote server searching for\n" "users and groups in a container. In order to migrate passwords you need\n" "to bind as a user that can read the userPassword attribute on the remote\n" "server. This is generally restricted to high-level admins such as\n" "cn=Directory Manager in 389-ds (this is the default bind user).\n" "\n" "The default user container is ou=People.\n" "\n" "The default group container is ou=Groups.\n" "\n" "Users and groups that already exist on the IPA server are skipped.\n" "\n" "Two LDAP schemas define how group members are stored: RFC2307 and\n" "RFC2307bis. RFC2307bis uses member and uniquemember to specify group\n" "members, RFC2307 uses memberUid. The default schema is RFC2307bis.\n" "\n" "The schema compat feature allows IPA to reformat data for systems that\n" "do not support RFC2307bis. It is recommended that this feature is disabled\n" "during migration to reduce system overhead. It can be re-enabled after\n" "migration. To migrate with it enabled use the \"--with-compat\" option.\n" "\n" "Migrated users do not have Kerberos credentials, they have only their\n" "LDAP password. To complete the migration process, users need to go\n" "to http://ipa.example.com/ipa/migration and authenticate using their\n" "LDAP password in order to generate their Kerberos credentials.\n" "\n" "Migration is disabled by default. Use the command ipa config-mod to\n" "enable it:\n" "\n" " ipa config-mod --enable-migration=TRUE\n" "\n" "If a base DN is not provided with --basedn then IPA will use either\n" "the value of defaultNamingContext if it is set or the first value\n" "in namingContexts set in the root of the remote LDAP server.\n" "\n" "Users are added as members to the default user group. This can be a\n" "time-intensive task so during migration this is done in a batch\n" "mode for every 100 users. As a result there will be a window in which\n" "users will be added to IPA but will not be members of the default\n" "user group.\n" "\n" "EXAMPLES:\n" "\n" " The simplest migration, accepting all defaults:\n" " ipa migrate-ds ldap://ds.example.com:389\n" "\n" " Specify the user and group container. This can be used to migrate user\n" " and group data from an IPA v1 server:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Since IPA v2 server already contain predefined groups that may collide " "with\n" " groups in migrated (IPA v1) server (for example admins, ipausers), users\n" " having colliding group as their primary group may happen to belong to\n" " an unknown group on new IPA v2 server.\n" " Use --group-overwrite-gid option to overwrite GID of already existing " "groups\n" " to prevent this issue:\n" " ipa migrate-ds --group-overwrite-gid \\\n" " --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Migrated users or groups may have object class and accompanied attributes\n" " unknown to the IPA v2 server. These object classes and attributes may be\n" " left out of the migration process:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " --user-ignore-objectclass=radiusprofile \\\n" " --user-ignore-attribute=radiusgroupname \\\n" " ldap://ds.example.com:389\n" "\n" "LOGGING\n" "\n" "Migration will log warnings and errors to the Apache error log. This\n" "file should be evaluated post-migration to correct or investigate any\n" "issues that were discovered.\n" "\n" "For every 100 users migrated an info-level message will be displayed to\n" "give the current progress and duration to make it possible to track\n" "the progress of migration.\n" "\n" "If the log level is debug, either by setting debug = True in\n" "/etc/ipa/default.conf or /etc/ipa/server.conf, then an entry will be " "printed\n" "for each user added plus a summary when the default user group is\n" "updated.\n" msgstr "" "\n" "Перехід на IPA\n" "\n" "ПеренеÑÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів Ñ– груп з Ñервера LDAP на IPA.\n" "\n" "ÐадÑилає запит LDAP до віддаленого Ñервера з метою пошуку кориÑтувачів\n" "Ñ– груп у контейнері. З метою перенеÑÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð² вам Ñлід прив’ÑзатиÑÑ\n" "до Ñервера від імені кориÑтувача, Ñкий може читати атрибут userPassword\n" "на Ñервері. Перелік таких кориÑтувачів зазвичай обмежено адмініÑтраторами\n" "вищого рівнÑ, зокрема cn=Directory Manager на 389-ds (типовий кориÑтувач\n" "bind).\n" "\n" "Типовим контейнером кориÑтувачів Ñ” ou=People.\n" "\n" "Типовим контейнером груп Ñ” ou=Groups.\n" "\n" "ЗапиÑи кориÑтувачів Ñ– груп, Ñкі вже Ñтворено на Ñервері IPA буде\n" "пропущено.\n" "\n" "Дві Ñхеми LDAP визначають ÑпоÑіб Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів учаÑників групи:\n" "RFC2307 Ñ– RFC2307bis. RFC2307bis викориÑтовує атрибути member Ñ–\n" "uniquemember Ð´Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÑƒÑ‡Ð°Ñників групи, RFC2307 викориÑтовує\n" "memberUid. Типовою Ñ” Ñхема RFC2307bis.\n" "\n" "За допомогою додатка compat IPA може повторно форматувати дані Ð´Ð»Ñ ÑиÑтем,\n" "де не передбачено підтримки RFC2307bis. РекомендуєтьÑÑ Ð²Ð¸Ð¼Ð¸ÐºÐ°Ñ‚Ð¸ цей додаток\n" "під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑеннÑ, щоб зменшити Ð½Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ð° ÑиÑтему. Ви зможете\n" "увімкнути його піÑÐ»Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑеннÑ. Щоб перенеÑти дані з увімкненим додатком\n" "ÑкориÑтайтеÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ «--with-compat».\n" "\n" "ПеренеÑені кориÑтувачі не матимуть реєÑтраційних запиÑів Kerberos,\n" "перенеÑено буде лише пароль LDAP. Щоб завершити Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑеннÑ,\n" "кориÑтувачам Ñлід відкрити Ñторінку\n" "http://ipa.example.com/ipa/migration Ñ– пройти Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°\n" "допомогою Ð¿Ð°Ñ€Ð¾Ð»Ñ LDAP з метою ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу реєÑтраційних даних\n" "Kerberos.\n" "\n" "Типово перенеÑÐµÐ½Ð½Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾. Ð”Ð»Ñ Ð¹Ð¾Ð³Ð¾ Ð²Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ ÑкориÑтайтеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ\n" "ipa config-mod:\n" "\n" " ipa config-mod --enable-migration=TRUE\n" "\n" "Якщо оÑновний DN не буде надано за допомогою --basedn, IPA " "викориÑтовуватиме\n" "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ defaultNamingContext, Ñкщо його вÑтановлено, або перше Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñƒ\n" "наборі namingContexts у кореневій теці віддаленого Ñервера LDAP.\n" "\n" "ЗапиÑи кориÑтувачів додають до типової групи кориÑтувачів. ÐŸÑ€Ð¾Ñ†ÐµÑ Ñ‚Ð°ÐºÐ¾Ð³Ð¾\n" "Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ðµ бути доволі тривалим, отже під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð²Ñ–Ð½ " "виконуєтьÑÑ\n" "у пакетному режимі, пакетами по 100 кориÑтувачів. У результаті буде певний\n" "період, коли запиÑи кориÑтувачів вже буде додано до IPA, але ці кориÑтувачі\n" "ще не будуть учаÑниками типової групи кориÑтувачів.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " ÐайпроÑтіше перенеÑÐµÐ½Ð½Ñ Ð· типовими параметрами:\n" " ipa migrate-ds ldap://ds.example.com:389\n" "\n" " Ð’Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ñ–Ð² кориÑтувача Ñ– групи. Можна ÑкориÑтатиÑÑ Ð´Ð»Ñ\n" " перенеÑÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… кориÑтувача Ñ– групи з Ñервера IPA верÑÑ–Ñ— 1:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " ОÑкільки на Ñервері IPA верÑÑ–Ñ— 2 вже передбачено попередньо\n" " визначені групи, Ñкі можуть збігатиÑÑ Ð· групами, Ñкі переноÑÑтьÑÑ Ð·\n" " Ñервера (IPA верÑÑ–Ñ— 1), наприклад admins, ipausers, кориÑтувачів з\n" " таких груп може бути перенеÑено до невідомої (unknown) групи на\n" " новому Ñервері IPA верÑÑ–Ñ— 2.\n" " СкориÑтайтеÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ --group-overwrite-gid Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñу\n" " ідентифікатора групи вже Ñтворених груп Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ñ†Ñ–Ð¹\n" " незручноÑті:\n" " ipa migrate-ds --group-overwrite-gid \\\n" " --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " ПеренеÑені дані кориÑтувачів та груп можуть міÑтити клаÑи об’єктів та " "Ñупутні\n" " атрибути, невідомі Ñерверу IPA верÑÑ–Ñ— 2. Ці клаÑти об’єктів та атрибутів\n" " може бути виключено з процедури перенеÑÐµÐ½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ…:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " --user-ignore-objectclass=radiusprofile \\\n" " --user-ignore-attribute=radiusgroupname \\\n" " ldap://ds.example.com:389\n" "\n" "ВЕДЕÐÐЯ ЖУРÐÐЛУ\n" "\n" "Під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· попередженнÑми та запиÑами помилок\n" "додаватимутьÑÑ Ð´Ð¾ журналу помилок Apache. З відповідним файлом Ñлід\n" "ознайомитиÑÑ Ð¿Ñ–ÑÐ»Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° виÑвленнÑ\n" "помилок, Ñкі могли ÑтатиÑÑ.\n" "\n" "Ð”Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ пакета зі 100 перенеÑених запиÑів кориÑтувачів буде показано\n" "інформаційне повідомленнÑ, призначене Ð´Ð»Ñ Ð¾Ñ†Ñ–Ð½ÐºÐ¸ поÑтупу обробки та\n" "Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ—Ñ— тривалоÑті.\n" "\n" "Якщо визначено рівень Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ñƒ debug за допомогою вÑтановленнÑ\n" "debug = True у /etc/ipa/default.conf або у /etc/ipa/server.conf,\n" "Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ перенеÑеного запиÑу додаватиметьÑÑ Ð²Ð»Ð°Ñний запиÑ, також\n" "додаватиметьÑÑ Ñ€ÐµÐ·ÑŽÐ¼Ðµ щодо кожного Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ñ— групи\n" "кориÑтувачів.\n" #, python-format msgid "" "Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually." msgstr "" "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Kerberos %s вже Ñ–Ñнує. СкориÑтайтеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ «ipa user-" "mod», щоб вÑтановити його параметри вручну." #, python-format msgid "" "Unable to determine if Kerberos principal %s already exists. Use 'ipa user-" "mod' to set it manually." msgstr "" "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸, чи Ñ–Ñнує вже реєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Kerberos %s. " "СкориÑтайтеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ «ipa user-mod», щоб вÑтановити його параметри вручну." msgid "" "Failed to add user to the default group. Use 'ipa group-add-member' to add " "manually." msgstr "" "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ кориÑтувача до типової групи. Додати кориÑтувача вручну " "можна за допомогою команди «ipa group-add-member»." msgid "Migration of LDAP search reference is not supported." msgstr "Підтримки перенеÑÐµÐ½Ð½Ñ Ð¿Ð¾ÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ LDAP не передбачено." msgid "Malformed DN" msgstr "Помилкове Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ DN" #, python-format msgid "%(user)s is not a POSIX user" msgstr "%(user)s не Ñ” кориÑтувачем з групи POSIX" msgid "" ". Check GID of the existing group. Use --group-overwrite-gid option to " "overwrite the GID" msgstr "" ". Перевірте ідентифікатор вже Ñтвореної групи. СкориÑтайтеÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ --" "group-overwrite-gid Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ·Ð°Ð¿Ð¸Ñу ідентифікатора групи" msgid "Invalid LDAP URI." msgstr "Ðекоректна адреÑа LDAP." msgid "Migrate users and groups from DS to IPA." msgstr "ПеренеÑти дані кориÑтувачів Ñ– груп з DS до IPA." msgid "LDAP URI" msgstr "URI LDAP" msgid "LDAP URI of DS server to migrate from" msgstr "URI LDAP Ñервера DS, з Ñкого здійÑнюватиметьÑÑ Ð¼Ñ–Ð³Ñ€Ð°Ñ†Ñ–Ñ" msgid "bind password" msgstr "пароль прив’Ñзки" msgid "Bind DN" msgstr "DN Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²'Ñзки" msgid "User container" msgstr "Контейнер кориÑтувачів" msgid "DN of container for users in DS relative to base DN" msgstr "DN контейнера кориÑтувачів у DS відноÑно до оÑновного DN" msgid "Group container" msgstr "Контейнер груп" msgid "DN of container for groups in DS relative to base DN" msgstr "DN контейнера груп у DS відноÑно до оÑновного DN" msgid "User object class" msgstr "ÐšÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² кориÑтувача" msgid "Objectclasses used to search for user entries in DS" msgstr "КлаÑи об’єктів, викориÑтаних Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ запиÑів кориÑтувачів у DS" msgid "Group object class" msgstr "ÐšÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² групи" msgid "Objectclasses used to search for group entries in DS" msgstr "КлаÑи об’єктів, викориÑтаних Ð´Ð»Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ запиÑів груп у DS" msgid "Ignore user object class" msgstr "Ігнорувати ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² кориÑтувача" msgid "Objectclasses to be ignored for user entries in DS" msgstr "КлаÑи об’єктів, Ñкі буде проігноровано Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів кориÑтувачів у DS" msgid "Ignore user attribute" msgstr "Ігнорувати атрибут кориÑтувача" msgid "Attributes to be ignored for user entries in DS" msgstr "Ðтрибути, Ñкі буде проігноровано Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів кориÑтувачів у DS" msgid "Ignore group object class" msgstr "Ігнорувати ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² групи" msgid "Objectclasses to be ignored for group entries in DS" msgstr "КлаÑи об’єктів, Ñкі буде проігноровано Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів груп у DS" msgid "Ignore group attribute" msgstr "Ігнорувати атрибут групи" msgid "Attributes to be ignored for group entries in DS" msgstr "Ðтрибути, Ñкі буде проігноровано Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів груп у DS" msgid "Overwrite GID" msgstr "ПерезапиÑати ідентифікатор групи" msgid "" "When migrating a group already existing in IPA domain overwrite the group " "GID and report as success" msgstr "" "Під Ñ‡Ð°Ñ Ð¿ÐµÑ€ÐµÐ½ÐµÑÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð¸, Ñку вже Ñтворено у домені IPA буде перезапиÑано " "ідентифікатор групи Ñ– повідомлено про уÑпіх" msgid "LDAP schema" msgstr "Схема LDAP" msgid "" "The schema used on the LDAP server. Supported values are RFC2307 and " "RFC2307bis. The default is RFC2307bis" msgstr "" "Схема, викориÑтана на Ñервері LDAP. Підтримувані значеннÑ: RFC2307 Ñ– " "RFC2307bis. Типове значеннÑ: RFC2307bis" msgid "Continue" msgstr "Продовжити" msgid "" "Continuous operation mode. Errors are reported but the process continues" msgstr "" "Режим неперервної обробки. Програма повідомлÑÑ” про помилки, але продовжує " "обробку." msgid "Base DN" msgstr "Кореневий DN" msgid "Base DN on remote LDAP server" msgstr "ОÑновний DN на віддаленому Ñервері LDAP" msgid "Ignore compat plugin" msgstr "Ігнорувати додаток compat" msgid "Allows migration despite the usage of compat plugin" msgstr "Уможливлює перенеÑеннÑ, незважаючи на викориÑÑ‚Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ° compat" msgid "Lists of objects migrated; categorized by type." msgstr "СпиÑки об’єктів, міграцію Ñких виконано; впорÑдкований за типами." msgid "Lists of objects that could not be migrated; categorized by type." msgstr "" "СпиÑки об’єктів, міграцію Ñких не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸; впорÑдкований за типами." msgid "False if migration mode was disabled." msgstr "False, Ñкщо режим міграції було вимкнено." msgid "False if migration fails because the compatibility plug-in is enabled." msgstr "" "False, Ñкщо перенеÑÐµÐ½Ð½Ñ Ð·Ð°Ð·Ð½Ð°Ñ” невдачі через ÑƒÐ²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ° ÑуміÑноÑті." #, python-format msgid "%s to exclude from migration" msgstr "%s, Ñкі Ñлід виключити з перенеÑеннÑ" msgid "" "search results for objects to be migrated\n" "have been truncated by the server;\n" "migration process might be incomplete\n" msgstr "" "ÑпиÑок результатів пошуку об’єктів міграції\n" "було обрізано Ñервером; ймовірно,\n" "Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð¼Ñ–Ð³Ñ€Ð°Ñ†Ñ–Ñ— не завершено\n" msgid "Migration mode is disabled. Use 'ipa config-mod' to enable it." msgstr "" "Режим міграції вимкнено. СкориÑтайтеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ «ipa config-mod», щоб " "увімкнути його." msgid "" "Passwords have been migrated in pre-hashed format.\n" "IPA is unable to generate Kerberos keys unless provided\n" "with clear text passwords. All migrated users need to\n" "login at https://your.domain/ipa/migration/ before they\n" "can use their Kerberos accounts." msgstr "" "Міграцію запиÑів паролів здійÑнено у форматі до хешуваннÑ.\n" "IPA не вдаÑтьÑÑ Ñтворити ключі Kerberos, Ñкщо не буде\n" "надано текÑтових паролів. Ð’Ñім кориÑтувачам з перенеÑеними\n" "запиÑами, доведетьÑÑ Ð¿Ñ€Ð¾Ð¹Ñ‚Ð¸ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð°\n" "https://your.domain/ipa/migration/ до того, Ñк вони зможуть\n" "ÑкориÑтатиÑÑ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¸Ð¼Ð¸ запиÑами Kerberos." #, python-format msgid "" "%(container)s LDAP search did not return any result (search base: " "%(search_base)s, objectclass: %(objectclass)s)" msgstr "" "Пошуком LDAP у %(container)s не повернуто жодного результату (оÑнова пошуку: " "%(search_base)s, ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð²: %(objectclass)s)" msgid "Default group for new users not found" msgstr "Типової групи Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… кориÑтувачів не знайдено" msgid "" "\n" "Misc plug-ins\n" msgstr "" "\n" "Інші додатки\n" msgid "Show environment variables." msgstr "Показати змінні Ñередовища." #, python-format msgid "%(count)d variables" msgstr "%(count)d змінних" msgid "" "retrieve and print all attributes from the server. Affects command output." msgstr "" "отримати Ñ– вивеÑти вÑÑ– атрибути з Ñервера. СтоÑуєтьÑÑ Ð»Ð¸ÑˆÐµ виводу команд." msgid "Total number of variables env (>= count)" msgstr "КількіÑть змінних env (>= count)" msgid "Number of variables returned (<= total)" msgstr "КількіÑть повернутих змінних (<= загальної)" msgid "Show all loaded plugins." msgstr "Показати ÑпиÑок завантажених додатків." #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "завантажено %(count)d додаток" msgstr[1] "завантажено %(count)d додатки" msgstr[2] "завантажено %(count)d додатків" msgid "Number of plugins loaded" msgstr "КількіÑть завантажених додатків" msgid "" "\n" "Netgroups\n" "\n" "A netgroup is a group used for permission checking. It can contain both\n" "user and host values.\n" "\n" "EXAMPLES:\n" "\n" " Add a new netgroup:\n" " ipa netgroup-add --desc=\"NFS admins\" admins\n" "\n" " Add members to the netgroup:\n" " ipa netgroup-add-member --users=tuser1 --users=tuser2 admins\n" "\n" " Remove a member from the netgroup:\n" " ipa netgroup-remove-member --users=tuser2 admins\n" "\n" " Display information about a netgroup:\n" " ipa netgroup-show admins\n" "\n" " Delete a netgroup:\n" " ipa netgroup-del admins\n" msgstr "" "\n" "Мережеві групи\n" "\n" "Мережева група — група Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ прав доÑтупу. Може міÑтити значеннÑ\n" "кориÑтувачів та вузлів.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— мережевої групи:\n" " ipa netgroup-add --desc=\"NFS admins\" admins\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñників до мережевої групи:\n" " ipa netgroup-add-member --users=tuser1 --users=tuser2 admins\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача з мережевої групи:\n" " ipa netgroup-remove-member --users=tuser2 admins\n" "\n" " Показ даних щодо мережевої групи:\n" " ipa netgroup-show admins\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¼ÐµÑ€ÐµÐ¶ÐµÐ²Ð¾Ñ— групи:\n" " ipa netgroup-del admins\n" msgid "Member Host" msgstr "Вузол-учаÑник" msgid "netgroup" msgstr "мережева група" msgid "netgroups" msgstr "мережеві групи" msgid "Netgroups" msgstr "Мережеві групи" msgid "Netgroup" msgstr "Мережева група" msgid "Netgroup name" msgstr "Ðазва мережевої групи" msgid "Netgroup description" msgstr "ÐžÐ¿Ð¸Ñ Ð¼ÐµÑ€ÐµÐ¶ÐµÐ²Ð¾Ñ— групи" msgid "NIS domain name" msgstr "Ðазва домену NIS" msgid "IPA unique ID" msgstr "Унікальний ід. IPA" msgid "Add a new netgroup." msgstr "Додати нову мережеву групу." #, python-format msgid "Added netgroup \"%(value)s\"" msgstr "Додано групу мережеву групу «%(value)s»" #, python-format msgid "" "hostgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "Група вузлів з назвою «%s» вже Ñтворено. Групи вузлів Ñ– мережеві групи мають " "Ñпільний проÑтір назв." msgid "Delete a netgroup." msgstr "Вилучити мережеву групу." #, python-format msgid "Deleted netgroup \"%(value)s\"" msgstr "Вилучено мережеву групу «%(value)s»" msgid "Modify a netgroup." msgstr "Змінити мережеву групу." #, python-format msgid "Modified netgroup \"%(value)s\"" msgstr "Змінено мережеву групу «%(value)s»" msgid "Search for a netgroup." msgstr "Шукати мережеву групу." #, python-format msgid "%(count)d netgroup matched" msgid_plural "%(count)d netgroups matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d групи" msgstr[1] "вÑтановлено відповідніÑть %(count)d груп" msgstr[2] "вÑтановлено відповідніÑть %(count)d груп" msgid "search for managed groups" msgstr "шукати керовані групи" msgid "Display information about a netgroup." msgstr "Показати дані щодо мережевої групи." msgid "Add members to a netgroup." msgstr "Додати учаÑників до мережевої групи." msgid "Remove members from a netgroup." msgstr "Вилучити учаÑників з мережевої групи." msgid "" "\n" "Set a user's password\n" "\n" "If someone other than a user changes that user's password (e.g., Helpdesk\n" "resets it) then the password will need to be changed the first time it\n" "is used. This is so the end-user is the only one who knows the password.\n" "\n" "The IPA password policy controls how often a password may be changed,\n" "what strength requirements exist, and the length of the password history.\n" "\n" "EXAMPLES:\n" "\n" " To reset your own password:\n" " ipa passwd\n" "\n" " To change another user's password:\n" " ipa passwd tuser1\n" msgstr "" "\n" "Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача\n" "\n" "Якщо ÑкаÑÑŒ ÑÑ‚Ð¾Ñ€Ð¾Ð½Ð½Ñ Ð¾Ñоба змінює пароль кориÑтувача (наприклад його\n" "відновлює допоміжний перÑонал), новий пароль має бути змінено під\n" "Ñ‡Ð°Ñ Ð¹Ð¾Ð³Ð¾ першого викориÑтаннÑ. Метою такого ÑпоÑобу дій Ñ” забезпеченнÑ\n" "Ñитуації, коли пароль буде відомий лише тому, хто ним кориÑтуєтьÑÑ.\n" "\n" "Правила щодо паролів IPA керують чаÑтотою зміни паролÑ, вимогами щодо\n" "ÑкладноÑті Ð¿Ð°Ñ€Ð¾Ð»Ñ Ñ‚Ð° об’ємом журналу зміни паролів.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Щоб Ñкинути ваш влаÑний пароль, виконайте команду:\n" " ipa passwd\n" "\n" " Щоб змінити пароль іншого кориÑтувача, виконайте команду:\n" " ipa passwd tuser1\n" msgid "Set a user's password." msgstr "Ð’Ñтановити пароль кориÑтувача." #, python-format msgid "Changed password for \"%(value)s\"" msgstr "Змінити пароль «%(value)s»" msgid "Invalid credentials" msgstr "РеєÑтраційні дані вказано з помилками" msgid "" "\n" "Permissions\n" "\n" "A permission enables fine-grained delegation of rights. A permission is\n" "a human-readable form of a 389-ds Access Control Rule, or instruction " "(ACI).\n" "A permission grants the right to perform a specific task such as adding a\n" "user, modifying a group, etc.\n" "\n" "A permission may not contain other permissions.\n" "\n" "* A permission grants access to read, write, add or delete.\n" "* A privilege combines similar permissions (for example all the permissions\n" " needed to add a user).\n" "* A role grants a set of privileges to users, groups, hosts or hostgroups.\n" "\n" "A permission is made up of a number of different parts:\n" "\n" "1. The name of the permission.\n" "2. The target of the permission.\n" "3. The rights granted by the permission.\n" "\n" "Rights define what operations are allowed, and may be one or more\n" "of the following:\n" "1. write - write one or more attributes\n" "2. read - read one or more attributes\n" "3. add - add a new entry to the tree\n" "4. delete - delete an existing entry\n" "5. all - all permissions are granted\n" "\n" "Read permission is granted for most attributes by default so the read\n" "permission is not expected to be used very often.\n" "\n" "Note the distinction between attributes and entries. The permissions are\n" "independent, so being able to add a user does not mean that the user will\n" "be editable.\n" "\n" "There are a number of allowed targets:\n" "1. type: a type of object (user, group, etc).\n" "2. memberof: a member of a group or hostgroup\n" "3. filter: an LDAP filter\n" "4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a\n" " super-set of the \"type\" target.\n" "5. targetgroup: grant access to modify a specific group (such as granting\n" " the rights to manage group membership)\n" "\n" "EXAMPLES:\n" "\n" " Add a permission that grants the creation of users:\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Add a permission that grants the ability to manage group membership:\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgstr "" "\n" "Права доÑтупу\n" "\n" "Права доÑтупу надають змогу точно налаштувати уповноваженнÑ. Права доÑтупу\n" "визначаютьÑÑ Ð·Ð²Ð¸Ñ‡Ð°Ð¹Ð½Ð¸Ð¼ текÑтом у форматі правила ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом 389-ds\n" "або інÑтрукції (ACI). Права доÑтупу надають можливіÑть виконувати певне\n" "завданнÑ, зокрема Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача, внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до запиÑу\n" "групи.\n" "\n" "Права доÑтупу можуть міÑтити інші права доÑтупу.\n" "\n" "* Право доÑтупу надає доÑтуп до читаннÑ, запиÑу, Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ вилученнÑ.\n" "* Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ñ”Ð´Ð½ÑƒÑŽÑ‚ÑŒ у Ñобі подібні права доÑтупу (наприклад вÑÑ–\n" " права доÑтупу, потрібні Ð´Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача).\n" "* Роль надає кориÑтувачам, групам, вузлам або групам вузлів певний набір\n" " уповноважень.\n" "\n" "Право доÑтупу ÑкладаєтьÑÑ Ð· декількох різних чаÑтин:\n" "\n" "1. Ðазви права доÑтупу.\n" "2. ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð° доÑтупу.\n" "3. Прав, Ñкі надаютьÑÑ.\n" "\n" "Права визначають набір дозволених дій Ñ– можуть ÑкладатиÑÑ Ð· одного або\n" "декількох таких запиÑів:\n" "1. write — Ð·Ð°Ð¿Ð¸Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ або декількох атрибутів\n" "2. read — Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ або декількох атрибутів\n" "3. add — Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ запиÑу до ієрархії\n" "4. delete — Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²Ð¶Ðµ Ñтвореного запиÑу\n" "5. all — Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… прав доÑтупу\n" "\n" "Типово, право доÑтупу до Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ð°Ñ”Ñ‚ÑŒÑÑ Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆÐ¾Ñті атрибутів, отже\n" "право доÑтупу «read» не викориÑтовуватиметьÑÑ Ñ‡Ð°Ñто.\n" "\n" "Ð—Ð°ÑƒÐ²Ð°Ð¶ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ відмінноÑтей між атрибутами та запиÑами. Права доÑтупу\n" "Ñ” незалежними, отже можливіÑть Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача не означає\n" "можливоÑті вноÑити зміни до доданого запиÑу.\n" "\n" "Передбачено декілька можливих цілей:\n" "1. type: тип об’єкта (user, group тощо).\n" "2. memberof: учаÑник групи кориÑтувачів або вузлів\n" "3. filter: фільтр LDAP\n" "4. subtree: фільтр LDAP, що визначає чаÑтину DIT LDAP DIT. Ðадмножина\n" " цілі «type».\n" "5. targetgroup: надати доÑтуп до внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до запиÑу певної групи\n" " (зокрема до ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñтю у групі)\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð° доÑтупу до ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів кориÑтувачів:\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð° доÑтупу до можливоÑті ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñтю у групі:\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgid "Permission Type" msgstr "Тип прав доÑтупу" msgid "permission" msgstr "права доÑтупу" msgid "permissions" msgstr "права доÑтупу" msgid "Permission name" msgstr "Ðазва прав доÑтупу" msgid "Permissions to grant (read, write, add, delete, all)" msgstr "Права доÑтупу, Ñкі Ñлід надати (read, write, add, delete, all)" msgid "" "Type of IPA object (user, group, host, hostgroup, service, netgroup, dns)" msgstr "" "Тип об’єкта IPA (user (кориÑтувач), group (група), host (вузол), hostgroup " "(група вузлів), service (Ñлужба), netgroup (мережева група), dns)" msgid "Member of group" msgstr "УчаÑник групи" msgid "Target members of a group" msgstr "Цільові учаÑники групи" msgid "Subtree to apply permissions to" msgstr "Піддерево, до Ñкого буде заÑтоÑовано права доÑтупу" msgid "User group to apply permissions to" msgstr "Група кориÑтувачів, до Ñкої буде заÑтоÑовано права доÑтупу" msgid "Add a new permission." msgstr "Додати нові права доÑтупу." #, python-format msgid "Added permission \"%(value)s\"" msgstr "Додано права доÑтупу «%(value)s»" msgid "Add a system permission without an ACI" msgstr "Додати ÑиÑтемні права доÑтупу без ACI" msgid "Permission type" msgstr "Тип прав доÑтупу" msgid "Delete a permission." msgstr "Вилучити права доÑтупу." #, python-format msgid "Deleted permission \"%(value)s\"" msgstr "Вилучено права доÑтупу «%(value)s»" msgid "force delete of SYSTEM permissions" msgstr "примуÑове Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð² доÑтупу SYSTEM" msgid "A SYSTEM permission may not be removed" msgstr "Права доÑтупу SYSTEM не можна вилучати" msgid "Modify a permission." msgstr "Змінити права доÑтупу." #, python-format msgid "Modified permission \"%(value)s\"" msgstr "Змінено права доÑтупу «%(value)s»" msgid "A SYSTEM permission may not be modified" msgstr "Права доÑтупу SYSTEM не можна змінювати" msgid "New name can not be empty" msgstr "Ðова назва має бути непорожньою" msgid "Search for permissions." msgstr "Знайти права доÑтупу." #, python-format msgid "%(count)d permission matched" msgid_plural "%(count)d permissions matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d запиÑу" msgstr[1] "вÑтановлено відповідніÑть %(count)d запиÑів" msgstr[2] "вÑтановлено відповідніÑть %(count)d запиÑів" msgid "Display information about a permission." msgstr "Показати дані щодо прав доÑтупу." msgid "" "\n" "Ping the remote IPA server to ensure it is running.\n" "\n" "The ping command sends an echo request to an IPA server. The server\n" "returns its version information. This is used by an IPA client\n" "to confirm that the server is available and accepting requests.\n" "\n" "The server from xmlrpc_uri in /etc/ipa/default.conf is contacted first.\n" "If it does not respond then the client will contact any servers defined\n" "by ldap SRV records in DNS.\n" "\n" "EXAMPLES:\n" "\n" " Ping an IPA server:\n" " ipa ping\n" " ------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " ------------------------------------------\n" "\n" " Ping an IPA server verbosely:\n" " ipa -v ping\n" " ipa: INFO: trying https://ipa.example.com/ipa/xml\n" " ipa: INFO: Forwarding 'ping' to server 'https://ipa.example.com/ipa/xml'\n" " -----------------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " -----------------------------------------------------\n" msgstr "" "\n" "Перевірка віддаленого Ñервера IPA з метою переконатиÑÑ, що він Ñ” " "працездатним.\n" "\n" "Програма ping надÑилає луна-запит до Ñервера IPA. Сервер повертає\n" "дані щодо його верÑÑ–Ñ—. Ці дані викориÑтовуютьÑÑ ÐºÐ»Ñ–Ñ”Ð½Ñ‚Ð¾Ð¼ IPA\n" "Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ, що Ñервер Ñ” доÑтупним Ñ– що він приймає запити.\n" "\n" "Сервер з xmlrpc_uri у /etc/ipa/default.conf перевірÑєтьÑÑ Ð¿ÐµÑ€ÑˆÐ¸Ð¼.\n" "Якщо він не відповідає, клієнт намагаєтьÑÑ Ð²Ñтановити зв’Ñзок з\n" "будь-Ñким Ñервером, визначеним запиÑами SRV ldap у DNS.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Перевірити луна-імпульÑом Ñервер IPA:\n" " ipa ping\n" " ------------------------------------------\n" " Сервер IPA верÑÑ–Ñ— 2.1.9. ВерÑÑ–Ñ API 2.20\n" " ------------------------------------------\n" "\n" " Перевірити луна-імпульÑом Ñервер IPA Ñ– отримати докладні дані:\n" " ipa -v ping\n" " ipa: INFO: trying https://ipa.example.com/ipa/xml\n" " ipa: INFO: Forwarding 'ping' to server u'https://ipa.example.com/ipa/" "xml'\n" " -----------------------------------------------------\n" " Сервер IPA верÑÑ–Ñ— 2.1.9. ВерÑÑ–Ñ API 2.20\n" " -----------------------------------------------------\n" msgid "Ping a remote server." msgstr "Перевірити луна-імпульÑом (пінгом) віддалений Ñервер." msgid "" "\n" "Kerberos pkinit options\n" "\n" "Enable or disable anonymous pkinit using the principal\n" "WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with\n" "pkinit support.\n" "\n" "EXAMPLES:\n" "\n" " Enable anonymous pkinit:\n" " ipa pkinit-anonymous enable\n" "\n" " Disable anonymous pkinit:\n" " ipa pkinit-anonymous disable\n" "\n" "For more information on anonymous pkinit see:\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgstr "" "\n" "Параметри pkinit Kerberos\n" "\n" "Ð’Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð°Ð±Ð¾ Ð²Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð°Ð½Ð¾Ð½Ñ–Ð¼Ð½Ð¾Ð³Ð¾ pkinit за допомогою реєÑтраційного\n" "запиÑу WELLKNOWN/ANONYMOUS@REALM. Має бути вÑтановлено Ñервер з\n" "підтримкою pkinit.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð’Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð°Ð½Ð¾Ð½Ñ–Ð¼Ð½Ð¾Ð³Ð¾ pkinit:\n" " ipa pkinit-anonymous enable\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð°Ð½Ð¾Ð½Ñ–Ð¼Ð½Ð¾Ð³Ð¾ pkinit:\n" " ipa pkinit-anonymous disable\n" "\n" "Щоб дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про анонімний pkinit відвідайте цю Ñторінку:\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgid "pkinit" msgstr "pkinit" msgid "PKINIT" msgstr "PKINIT" #, python-format msgid "Unknown command %s" msgstr "Ðевідома команда, «%s»" msgid "Enable or Disable Anonymous PKINIT." msgstr "Увімкнути або вимкнути анонімний PKINIT." msgid "" "\n" "Privileges\n" "\n" "A privilege combines permissions into a logical task. A permission provides\n" "the rights to do a single task. There are some IPA operations that require\n" "multiple permissions to succeed. A privilege is where permissions are\n" "combined in order to perform a specific task.\n" "\n" "For example, adding a user requires the following permissions:\n" " * Creating a new user entry\n" " * Resetting a user password\n" " * Adding the new user to the default IPA users group\n" "\n" "Combining these three low-level tasks into a higher level task in the\n" "form of a privilege named \"Add User\" makes it easier to manage Roles.\n" "\n" "A privilege may not contain other privileges.\n" "\n" "See role and permission for additional information.\n" msgstr "" "\n" "УповноваженнÑ\n" "\n" "Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ñ”Ð´Ð½ÑƒÑ” права доÑтупу у одне логічне завданнÑ. Право доÑтупу\n" "надає можливіÑть виконувати лише одне завданнÑ. У IPA Ñ” декілька дій,\n" "Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñких потребує одразу декількох прав доÑтупу. Ð’ уповноваженні такі\n" "права доÑтупу поєднуютьÑÑ Ð· метою Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— дії.\n" "\n" "Ðаприклад, Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача потребує таких прав доÑтупу:\n" " * право ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача;\n" " * право ÑÐºÐ¸Ð´Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача;\n" " * право Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача до типової групи кориÑтувачів IPA.\n" "\n" "ÐŸÐ¾Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ†Ð¸Ñ… трьох низькорівневих завдань у виÑокорівневе Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ñƒ\n" "форматі ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð· назвою «Add User» полегшує ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ð¾Ð»Ñми.\n" "\n" "Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð½Ðµ може міÑтити інших уповноважень.\n" "\n" "Щоб дізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ, ознайомтеÑÑ Ð· довідною щодо ролей та прав доÑтупу.\n" msgid "privilege" msgstr "уповноваженнÑ" msgid "privileges" msgstr "уповноваженнÑ" msgid "Privileges" msgstr "УповноваженнÑ" msgid "Privilege" msgstr "УповноваженнÑ" msgid "Privilege name" msgstr "Ðазва уповноваженнÑ" msgid "Privilege description" msgstr "ÐžÐ¿Ð¸Ñ ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ" msgid "Add a new privilege." msgstr "Додати нове уповноваженнÑ." #, python-format msgid "Added privilege \"%(value)s\"" msgstr "Додано ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Delete a privilege." msgstr "Вилучити уповноваженнÑ." #, python-format msgid "Deleted privilege \"%(value)s\"" msgstr "Вилучено ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Modify a privilege." msgstr "Змінити уповноваженнÑ." #, python-format msgid "Modified privilege \"%(value)s\"" msgstr "Змінено ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Â«%(value)s»" msgid "Search for privileges." msgstr "Знайти уповноваженнÑ." #, python-format msgid "%(count)d privilege matched" msgid_plural "%(count)d privileges matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d уповноваженнÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d уповноваженнÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d уповноважень" msgid "Display information about a privilege." msgstr "Показати дані щодо уповноваженнÑ." msgid "Add members to a privilege." msgstr "Додати учаÑників до запиÑу уповноваженнÑ." msgid "Add permissions to a privilege." msgstr "Додати права доÑтупу до уповноваженнÑ." msgid "Number of permissions added" msgstr "КількіÑть доданих прав доÑтупу" msgid "Remove permissions from a privilege." msgstr "Вилучити права доÑтупу з уповноваженнÑ." msgid "Number of permissions removed" msgstr "КількіÑть вилучених запиÑів прав доÑтупу" msgid "" "\n" "Password policy\n" "\n" "A password policy sets limitations on IPA passwords, including maximum\n" "lifetime, minimum lifetime, the number of passwords to save in\n" "history, the number of character classes required (for stronger passwords)\n" "and the minimum password length.\n" "\n" "By default there is a single, global policy for all users. You can also\n" "create a password policy to apply to a group. Each user is only subject\n" "to one password policy, either the group policy or the global policy. A\n" "group policy stands alone; it is not a super-set of the global policy plus\n" "custom settings.\n" "\n" "Each group password policy requires a unique priority setting. If a user\n" "is in multiple groups that have password policies, this priority determines\n" "which password policy is applied. A lower value indicates a higher priority\n" "policy.\n" "\n" "Group password policies are automatically removed when the groups they\n" "are associated with are removed.\n" "\n" "EXAMPLES:\n" "\n" " Modify the global policy:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Add a new group password policy:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Display the global password policy:\n" " ipa pwpolicy-show\n" "\n" " Display a group password policy:\n" " ipa pwpolicy-show localadmins\n" "\n" " Display the policy that would be applied to a given user:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modify a group password policy:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" msgstr "" "\n" "Правила паролів\n" "\n" "Правила паролів вÑтановлюють Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð² IPA,\n" "зокрема макÑимальний Ñтрок дії, мінімальний Ñтрок дії, кількіÑть паролів,\n" "Ñкі зберігатимутьÑÑ Ñƒ журналі, потрібна кількіÑть клаÑів Ñимволів (длÑ\n" "Ñкладних паролів) та мінімальну довжину паролÑ.\n" "\n" "Типово, визначено одні загальні правила Ð´Ð»Ñ Ð²ÑÑ–Ñ… кориÑтувачів. Ви можете\n" "Ñтворити правило паролів, Ñке ÑтоÑуватиметьÑÑ Ð¾Ð´Ð½Ñ–Ñ”Ñ— групи. Ð”Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾\n" "кориÑтувача може бути викориÑтано лише один набір правил паролів: груповий\n" "або загальний. Групові правила паролів Ñ” незалежними, вони не Ñ” загальними\n" "правилами з додаваннÑм нетипових параметрів.\n" "\n" "Ð”Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ набору групових правил паролів має бути вÑтановлено окреме\n" "Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ñ–Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ñƒ. Якщо кориÑтувач Ñ” учаÑником декількох груп, Ð´Ð»Ñ Ñких\n" "вÑтановлено правила паролів, пріоритет визначає, Ñкі з правил має бути\n" "заÑтоÑовано. Менші Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð°ÑŽÑ‚ÑŒ вищому пріоритету правил.\n" "\n" "Групові правила паролів автоматично вилучаютьÑÑ Ð¿Ñ–Ð´ Ñ‡Ð°Ñ Ð²Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ\n" "відповідних груп.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " ВнеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до загальних правил:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¸Ñ… групових правил паролів:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Показ загальних правил паролів:\n" " ipa pwpolicy-show\n" "\n" " Показ групових правил паролів:\n" " ipa pwpolicy-show localadmins\n" "\n" " Показ правил, Ñкі має бути заÑтоÑовано до певного кориÑтувача:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " ВнеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до групових правил паролів:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" #, python-format msgid "priority must be a unique value (%(prio)d already used by %(gname)s)" msgstr "" "пріоритет повинен мати унікальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ (%(prio)d вже викориÑтано Ð´Ð»Ñ " "%(gname)s)" msgid "password policy" msgstr "правила Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²" msgid "password policies" msgstr "правила щодо паролів" msgid "Max failures" msgstr "МакÑ. к-ть помилок" msgid "Consecutive failures before lockout" msgstr "КількіÑть помилок Ð´Ð»Ñ Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ" msgid "Failure reset interval" msgstr "Проміжок ÑÐºÐ¸Ð´Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº" msgid "Period after which failure count will be reset (seconds)" msgstr "" "Проміжок чаÑу, по завершенню Ñкого кількіÑть помилок буде Ñкинуто (у " "Ñекундах)" msgid "Lockout duration" msgstr "ТриваліÑть блокуваннÑ" msgid "Period for which lockout is enforced (seconds)" msgstr "Проміжок чаÑу, протÑгом Ñкого діÑтиме Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ (у Ñекундах)" msgid "Password Policies" msgstr "Правила щодо паролів" msgid "Group" msgstr "Група" msgid "Manage password policy for specific group" msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°Ð¼Ð¸ обробки паролів Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ñ— групи" msgid "Max lifetime (days)" msgstr "МакÑ. Ñтрок дії (у днÑÑ…)" msgid "Maximum password lifetime (in days)" msgstr "МакÑимальний Ñтрок дії Ð¿Ð°Ñ€Ð¾Ð»Ñ (у днÑÑ…)" msgid "Min lifetime (hours)" msgstr "Мін. Ñтрок дії (у годинах)" msgid "Minimum password lifetime (in hours)" msgstr "Мінімальний Ñтрок дії Ð¿Ð°Ñ€Ð¾Ð»Ñ (у годинах)" msgid "History size" msgstr "Розмір журналу" msgid "Password history size" msgstr "Розмір журналу паролів" msgid "Character classes" msgstr "КлаÑи Ñимволів" msgid "Minimum number of character classes" msgstr "Мінімальна кількіÑть клаÑів Ñимволів" msgid "Min length" msgstr "Мін. довжина" msgid "Minimum length of password" msgstr "Мінімальна довжина паролÑ" msgid "Priority of the policy (higher number means lower priority" msgstr "Пріоритет правил (більше чиÑло — нижчий пріоритет)" msgid "Maximum password life must be greater than minimum." msgstr "" "МакÑимальний Ñтрок дії Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð¼Ð°Ñ” перевищувати мінімальний Ñтрок його дії." msgid "Add a new group password policy." msgstr "Додати нову групу правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." msgid "Delete a group password policy." msgstr "Вилучити групу правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." msgid "cannot delete global password policy" msgstr "неможливо вилучити загальні правила паролів" msgid "Modify a group password policy." msgstr "Змінити групу правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." msgid "priority cannot be set on global policy" msgstr "Ð´Ð»Ñ Ð·Ð°Ð³Ð°Ð»ÑŒÐ½Ð¸Ñ… правил не може вÑтановлювати пріоритети" msgid "Display information about password policy." msgstr "Показати дані щодо групи правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." msgid "Display effective policy for a specific user" msgstr "Показати поточні правила Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ð³Ð¾ кориÑтувача" msgid "Search for group password policies." msgstr "Знайти групу правил Ð´Ð»Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ–Ð²." msgid "" "\n" "Realm domains\n" "\n" "Manage the list of domains associated with IPA realm.\n" "\n" "EXAMPLES:\n" "\n" " Display the current list of realm domains:\n" " ipa realmdomains-show\n" "\n" " Replace the list of realm domains:\n" " ipa realmdomains-mod --domain=example.com\n" " ipa realmdomains-mod --domain={example1.com,example2.com,example3.com}\n" "\n" " Add a domain to the list of realm domains:\n" " ipa realmdomains-mod --add-domain=newdomain.com\n" "\n" " Delete a domain from the list of realm domains:\n" " ipa realmdomains-mod --del-domain=olddomain.com\n" msgstr "" "\n" "Домени облаÑті\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑпиÑком доменів, пов’Ñзаних з облаÑтю IPA.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Показати поточний ÑпиÑок доменів облаÑті:\n" " ipa realmdomains-show\n" "\n" " Замірити ÑпиÑок доменів облаÑті:\n" " ipa realmdomains-mod --domain=example.com\n" " ipa realmdomains-mod --domain={example1.com,example2.com,example3.com}\n" "\n" " Додати домен до ÑпиÑку доменів облаÑті:\n" " ipa realmdomains-mod --add-domain=newdomain.com\n" "\n" " Вилучити домен зі ÑпиÑку доменів облаÑті:\n" " ipa realmdomains-mod --del-domain=olddomain.com\n" msgid "Realm domains" msgstr "Домени облаÑті" msgid "Add domain" msgstr "Додати домен" msgid "Delete domain" msgstr "Вилучити домен" msgid "Modify realm domains." msgstr "Змінити домени облаÑті." msgid "Force adding domain even if not in DNS" msgstr "ПримуÑове Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ, навіть Ñкщо назви немає у DNS" msgid "" "you cannot specify the --domain option together with --add-domain or --del-" "domain" msgstr "" "не можна вказувати параметр --domain разом з параметром --add-domain або --" "del-domain" msgid "cannot delete domain of IPA server" msgstr "не можна вилучати домен Ñервера IPA" #, python-format msgid "no SOA or NS records found for domains: %s" msgstr "не знайдено запиÑів SOA або NS Ð´Ð»Ñ Ñ‚Ð°ÐºÐ¸Ñ… доменів: %s" #, python-format msgid "no SOA or NS records found for domain %s" msgstr "не знайдено запиÑів SOA або NS Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ %s" msgid "Display the list of realm domains." msgstr "Показати ÑпиÑок доменів облаÑті." msgid "" "\n" "Roles\n" "\n" "A role is used for fine-grained delegation. A permission grants the ability\n" "to perform given low-level tasks (add a user, modify a group, etc.). A\n" "privilege combines one or more permissions into a higher-level abstraction\n" "such as useradmin. A useradmin would be able to add, delete and modify " "users.\n" "\n" "Privileges are assigned to Roles.\n" "\n" "Users, groups, hosts and hostgroups may be members of a Role.\n" "\n" "Roles can not contain other roles.\n" "\n" "EXAMPLES:\n" "\n" " Add a new role:\n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" "\n" " Add some privileges to this role:\n" " ipa role-add-privilege --privileges=addusers junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege --privileges=add_user_to_default_group " "junioradmin\n" "\n" " Add a group of users to this role:\n" " ipa group-add --desc=\"User admins\" useradmins\n" " ipa role-add-member --groups=useradmins junioradmin\n" "\n" " Display information about a role:\n" " ipa role-show junioradmin\n" "\n" " The result of this is that any users in the group 'junioradmin' can\n" " add users, reset passwords or add a user to the default IPA user group.\n" msgstr "" "\n" "Ролі\n" "\n" "Роль викориÑтовуєтьÑÑ Ð´Ð»Ñ ÑƒÑ‚Ð¾Ñ‡Ð½ÐµÐ½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð² доÑтупу. Право " "доÑтупу\n" "надає можливіÑть виконувати деÑкі низькорівневі Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ (Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу\n" "кориÑтувача, внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до групи тощо). Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ñ”Ð´Ð½ÑƒÑŽÑ‚ÑŒ одне або " "декілька\n" "прав доÑтупу у виÑокорівневу абÑтракцію, наприклад «адмініÑтратор " "кориÑтувачів»\n" "(useradmin). Такий useradmin зможе додавати, вилучати Ñ– вноÑити зміни до " "запиÑів\n" "кориÑтувачів.\n" "\n" "Ð£Ð¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð²â€™ÑзуютьÑÑ Ð· ролÑми.\n" "\n" "УчаÑниками ролі можуть бути кориÑтувачі, групи, вузли та групи вузлів.\n" "\n" "Ролі можуть міÑтити інші ролі.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— ролі:\n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½ÑŒ до цієї ролі:\n" " ipa role-add-privilege --privileges=addusers junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege --privileges=add_user_to_default_group " "junioradmin\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів до цієї ролі:\n" " ipa group-add --desc=\"User admins\" useradmins\n" " ipa role-add-member --groups=useradmins junioradmin\n" "\n" " Показ даних щодо ролі:\n" " ipa role-show junioradmin\n" "\n" " Результатом Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ буде те, що вÑÑ– кориÑтувачі групи " "«useradmins»\n" " зможуть додавати запиÑи кориÑтувачів, Ñкидати паролі або додавати " "кориÑтувача\n" " до типової групи кориÑтувачів IPA.\n" msgid "role" msgstr "роль" msgid "roles" msgstr "ролі" msgid "Role" msgstr "Роль" msgid "Role name" msgstr "Ðазва ролі" msgid "A description of this role-group" msgstr "ÐžÐ¿Ð¸Ñ Ñ†Ñ–Ñ”Ñ— групи ролей" msgid "Add a new role." msgstr "Додати нову роль." #, python-format msgid "Added role \"%(value)s\"" msgstr "Додано роль «%(value)s»" msgid "Delete a role." msgstr "Вилучити роль." #, python-format msgid "Deleted role \"%(value)s\"" msgstr "Вилучено роль «%(value)s»" msgid "Modify a role." msgstr "Змінити роль." #, python-format msgid "Modified role \"%(value)s\"" msgstr "Змінено роль «%(value)s»" msgid "Search for roles." msgstr "Знайти ролі." #, python-format msgid "%(count)d role matched" msgid_plural "%(count)d roles matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d ролі" msgstr[1] "вÑтановлено відповідніÑть %(count)d ролей" msgstr[2] "вÑтановлено відповідніÑть %(count)d ролей" msgid "Display information about a role." msgstr "Показати дані щодо ролі." msgid "Add members to a role." msgstr "Додати учаÑників до запиÑу ролі." msgid "Remove members from a role." msgstr "Вилучити учаÑників з запиÑу ролі." msgid "Add privileges to a role." msgstr "Додати ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð´Ð¾ запиÑу ролі." msgid "Number of privileges added" msgstr "КількіÑть доданих уповноважень" msgid "Remove privileges from a role." msgstr "Вилучити ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ Ð· запиÑу ролі." msgid "Number of privileges removed" msgstr "КількіÑть вилучених уповноважень" msgid "" "\n" "Self-service Permissions\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "A Self-service permission defines what an object can change in its own " "entry.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add a self-service rule to allow users to manage their address (using Bash\n" " brace expansion):\n" " ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c," "st} \"Users manage their own address\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones.\n" " Add telephoneNumber to the list (using Bash brace expansion):\n" " ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} " "\"Users manage their own address\"\n" "\n" " Display our updated rule:\n" " ipa selfservice-show \"Users manage their own address\"\n" "\n" " Delete a rule:\n" " ipa selfservice-del \"Users manage their own address\"\n" msgstr "" "\n" "Права доÑтупу ÑамообÑлуговуваннÑ\n" "\n" "Права доÑтупу надають змогу точно налаштувати уповноваженнÑ. За допомогою\n" "правил ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупом та інÑтрукцій (ACI) надаютьÑÑ Ð¿Ñ€Ð°Ð²Ð° доÑтупу до\n" "Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð²ÐºÐ°Ð·Ð°Ð½Ð¸Ñ… завдань, зокрема Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñів кориÑтувачів,\n" "внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½ до запиÑів груп тощо.\n" "\n" "Права доÑтупу ÑамообÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð°ÑŽÑ‚ÑŒ права об’єкта на внеÑÐµÐ½Ð½Ñ Ð·Ð¼Ñ–Ð½\n" "до влаÑного запиÑу.\n" "\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° ÑамообÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑƒÐ¼Ð¾Ð¶Ð»Ð¸Ð²Ð»ÐµÐ½Ð½Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ " "кориÑтувачами\n" " влаÑною адреÑою (з викориÑтаннÑм виразу Bash у фігурних дужках):\n" " ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c," "st} \"Users manage their own address\"\n" "\n" " Якщо ви керуєте ÑпиÑком атрибутів, вам Ñлід включити до ÑпиÑку вÑÑ– " "атрибути,\n" " зокрема вже Ñтворені. Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ telephoneNumber до ÑпиÑку (з викориÑтаннÑм " "виразу Bash у фігурних дужках):\n" " ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} " "\"Users manage their own address\"\n" "\n" " Показ нашого оновленого правила:\n" " ipa selfservice-show \"Users manage their own address\"\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°:\n" " ipa selfservice-del \"Users manage their own address\"\n" msgid "self service permission" msgstr "права доÑтупу автоÑлужби" msgid "self service permissions" msgstr "права доÑтупу до автоÑлужби" msgid "Self Service Permissions" msgstr "Права доÑтупу до ÑамообÑлуговуваннÑ" msgid "Self Service Permission" msgstr "Права доÑтупу автоÑлужби" msgid "Self-service name" msgstr "Ðазва ÑамообÑлуговуваннÑ" msgid "Attributes to which the permission applies." msgstr "Ðтрибути, до Ñких заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ доÑтупу." msgid "Add a new self-service permission." msgstr "Додати нові права доÑтупу автоÑлужби." #, python-format msgid "Added selfservice \"%(value)s\"" msgstr "Додано ÑамообÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Delete a self-service permission." msgstr "Вилучити права доÑтупу автоÑлужби." #, python-format msgid "Deleted selfservice \"%(value)s\"" msgstr "Вилучено ÑамообÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Modify a self-service permission." msgstr "Змінити права доÑтупу автоÑлужби." #, python-format msgid "Modified selfservice \"%(value)s\"" msgstr "Змінено ÑамообÑÐ»ÑƒÐ³Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Â«%(value)s»" msgid "Search for a self-service permission." msgstr "Шукати права доÑтупу автоÑлужби." #, python-format msgid "%(count)d selfservice matched" msgid_plural "%(count)d selfservices matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d ÑамообÑлуговуваннÑ" msgstr[1] "вÑтановлено відповідніÑть %(count)d ÑамообÑлуговуваннÑ" msgstr[2] "вÑтановлено відповідніÑть %(count)d ÑамообÑлуговувань" msgid "Display information about a self-service permission." msgstr "Показати дані щодо прав доÑтупу автоÑлужби." msgid "" "\n" "SELinux User Mapping\n" "\n" "Map IPA users to SELinux users by host.\n" "\n" "Hosts, hostgroups, users and groups can be either defined within\n" "the rule or it may point to an existing HBAC rule. When using\n" "--hbacrule option to selinuxusermap-find an exact match is made on the\n" "HBAC rule name, so only one or zero entries will be returned.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that sets all users to xguest_u:s0 on the host " "\"server\":\n" " ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1\n" " ipa selinuxusermap-add-host --hosts=server.example.com test1\n" "\n" " Create a rule, \"test2\", that sets all users to guest_u:s0 and uses an " "existing HBAC rule for users and hosts:\n" " ipa selinuxusermap-add --usercat=all --hbacrule=webserver --" "selinuxuser=guest_u:s0 test2\n" "\n" " Display the properties of a rule:\n" " ipa selinuxusermap-show test2\n" "\n" " Create a rule for a specific user. This sets the SELinux context for\n" " user john to unconfined_u:s0-s0:c0.c1023 on any machine:\n" " ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0." "c1023 john_unconfined\n" " ipa selinuxusermap-add-user --users=john john_unconfined\n" "\n" " Disable a rule:\n" " ipa selinuxusermap-disable test1\n" "\n" " Enable a rule:\n" " ipa selinuxusermap-enable test1\n" "\n" " Find a rule referencing a specific HBAC rule:\n" " ipa selinuxusermap-find --hbacrule=allow_some\n" "\n" " Remove a rule:\n" " ipa selinuxusermap-del john_unconfined\n" "\n" "SEEALSO:\n" "\n" " The list controlling the order in which the SELinux user map is applied\n" " and the default SELinux user are available in the config-show command.\n" msgstr "" "\n" "Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¾Ñті кориÑтувачів SELinux\n" "\n" "Ð’Ñтановити відповідніÑть кориÑтувачів IPA кориÑтувачам SELinux за вузлами.\n" "\n" "Вузли, групи вузлів, кориÑтувачі Ñ– групи можна визначати або\n" "в межах правила, або може вказувати на вже Ñтворене правило HBAC.\n" "У разі викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð° --hbacrule команди selinuxusermap-find\n" "буде вÑтановлено точну відповідніÑть за назвою правила HBAC, отже буде\n" "повернуто один або жодного запиÑу.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°, «test1», Ñке вÑтановлює вÑÑ–Ñ… кориÑтувачів у xguest_u:s0 " "на вузлі «server»:\n" " ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1\n" " ipa selinuxusermap-add-host --hosts=serverexample.com test1\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°, \"test2\", Ñке вÑтановлює вÑÑ–Ñ… кориÑтувачів у guest_u:s0 " "Ñ– викориÑтовує вже Ñтворене правило HBAC Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів Ñ– вузлів:\n" " ipa selinuxusermap-add --usercat=all --hbacrule=webserver --" "selinuxuser=guest_u:s0 test2\n" "\n" " Показ влаÑтивоÑтей правил:\n" " ipa selinuxusermap-show test2\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° Ð´Ð»Ñ Ð¿ÐµÐ²Ð½Ð¾Ð³Ð¾ кориÑтувача. Ð’Ñтановлює контекÑÑ‚ SELinux Ð´Ð»Ñ " "кориÑтувача\n" " john у unconfined_u:s0-s0:c0.c1023 на вÑÑ–Ñ… комп’ютерах:\n" " ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0." "c1023 john_unconfined\n" " ipa selinuxusermap-add-user --users=john john_unconfined\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°:\n" " ipa selinuxusermap-disable test1\n" "\n" " Ð£Ð²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°:\n" " ipa selinuxusermap-enable test1\n" "\n" " Пошук правила, що поÑилаєтьÑÑ Ð½Ð° певне правило HBAC:\n" " ipa selinuxusermap-find --hbacrule=allow_some\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°:\n" " ipa selinuxusermap-del john_unconfined\n" "\n" "ТÐКОЖ ОЗÐÐЙОМТЕСЯ:\n" "\n" " ЗаÑтоÑовуєтьÑÑ ÑпиÑок, Ñкий визначає порÑдок, у Ñкому вÑтановлюєтьÑÑ\n" " відповідніÑть кориÑтувачів. Типового кориÑтувача можна за допомогою\n" " програми config-show.\n" msgid "HBAC rule and local members cannot both be set" msgstr "Ðе можна одночаÑно вказувати правило HBAC Ñ– локальних учаÑників" msgid "Invalid SELinux user name, only a-Z and _ are allowed" msgstr "" "Ðекоректне Ñ–Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача SELinux, у імені можна викориÑтовувати лише " "Ñимволи a-Z Ñ– _" msgid "Invalid MLS value, must match s[0-15](-s[0-15])" msgstr "" "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ MLS. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¼Ð°Ñ” відповідати шаблону s[0-15](-s[0-15])" msgid "" "Invalid MCS value, must match c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123]" msgstr "" "Ðекоректне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ MCS. Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¼Ð°Ñ” відповідати шаблону c[0-1023]." "c[0-1023] Ñ–/або шаблону c[0-1023]-c[0-c0123]" msgid "SELinux user map list not found in configuration" msgstr "СпиÑку карт кориÑтувачів SELinux у налаштуваннÑÑ… не виÑвлено" #, python-format msgid "SELinux user %(user)s not found in ordering list (in config)" msgstr "" "ЗапиÑу кориÑтувача SELinux %(user)s не виÑвлено у порÑдковому ÑпиÑку (у " "налаштуваннÑÑ…)" msgid "SELinux User Map rule" msgstr "Правило карти кориÑтувачів SELinux" msgid "SELinux User Map rules" msgstr "Правила карти кориÑтувачів SELinux" msgid "SELinux User Maps" msgstr "Карти кориÑтувачів SELinux" msgid "SELinux User Map" msgstr "Карта кориÑтувачів SELinux" msgid "SELinux User" msgstr "КориÑтувач SELinux" msgid "HBAC Rule that defines the users, groups and hostgroups" msgstr "Правило HBAC, Ñке визначає кориÑтувачів, групи Ñ– групи вузлів" #, python-format msgid "HBAC rule %(rule)s not found" msgstr "Ðе знайдено правила HBAC %(rule)s" msgid "Create a new SELinux User Map." msgstr "Створити карту кориÑтувачів SELinux." #, python-format msgid "Added SELinux User Map \"%(value)s\"" msgstr "Додано карту кориÑтувачів SELinux «%(value)s»" msgid "Delete a SELinux User Map." msgstr "Вилучити карту кориÑтувачів SELinux." #, python-format msgid "Deleted SELinux User Map \"%(value)s\"" msgstr "Вилучено карту кориÑтувачів SELinux «%(value)s»" msgid "Modify a SELinux User Map." msgstr "Змінити карту кориÑтувачів SELinux." #, python-format msgid "Modified SELinux User Map \"%(value)s\"" msgstr "Змінено карту кориÑтувачів SELinux «%(value)s»" msgid "Search for SELinux User Maps." msgstr "Шукати карти кориÑтувачів SELinux." #, python-format msgid "%(count)d SELinux User Map matched" msgid_plural "%(count)d SELinux User Maps matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d карти кориÑтувачів SELinux" msgstr[1] "вÑтановлено відповідніÑть %(count)d карт кориÑтувачів SELinux" msgstr[2] "вÑтановлено відповідніÑть %(count)d карт кориÑтувачів SELinux" msgid "Display the properties of a SELinux User Map rule." msgstr "Показати влаÑтивоÑті правила карти кориÑтувачів SELinux." msgid "Enable an SELinux User Map rule." msgstr "Увімкнути правило карти кориÑтувачів SELinux." #, python-format msgid "Enabled SELinux User Map \"%(value)s\"" msgstr "Увімкнено карту кориÑтувачів SELinux «%(value)s»" msgid "Disable an SELinux User Map rule." msgstr "Вимкнути правило карти кориÑтувачів SELinux." #, python-format msgid "Disabled SELinux User Map \"%(value)s\"" msgstr "Вимкнено карту кориÑтувачів SELinux «%(value)s»" msgid "Add users and groups to an SELinux User Map rule." msgstr "Додати кориÑтувачів Ñ– групи до правила карти кориÑтувачів SELinux." msgid "Remove users and groups from an SELinux User Map rule." msgstr "Вилучити кориÑтувачів Ñ– групи з правила карти кориÑтувачів SELinux." msgid "Add target hosts and hostgroups to an SELinux User Map rule." msgstr "" "Додати вузли Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð° групи вузлів до правила карти кориÑтувачів " "SELinux." msgid "Remove target hosts and hostgroups from an SELinux User Map rule." msgstr "" "Вилучити вузли Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð° групи вузлів з правила карти кориÑтувачів " "SELinux." msgid "" "\n" "Services\n" "\n" "A IPA service represents a service that runs on a host. The IPA service\n" "record can store a Kerberos principal, an SSL certificate, or both.\n" "\n" "An IPA service can be managed directly from a machine, provided that\n" "machine has been given the correct permission. This is true even for\n" "machines other than the one the service is associated with. For example,\n" "requesting an SSL certificate using the host service principal credentials\n" "of the host. To manage a service using host credentials you need to\n" "kinit as the host:\n" "\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\n" "\n" "Adding an IPA service allows the associated service to request an SSL\n" "certificate or keytab, but this is performed as a separate step; they\n" "are not produced as a result of adding the service.\n" "\n" "Only the public aspect of a certificate is stored in a service record;\n" "the private key is not stored.\n" "\n" "EXAMPLES:\n" "\n" " Add a new IPA service:\n" " ipa service-add HTTP/web.example.com\n" "\n" " Allow a host to manage an IPA service certificate:\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\n" " ipa role-add-member --hosts=web.example.com certadmin\n" "\n" " Override a default list of supported PAC types for the service:\n" " ipa service-mod HTTP/web.example.com --pac-type=MS-PAC\n" "\n" " A typical use case where overriding the PAC type is needed is NFS.\n" " Currently the related code in the Linux kernel can only handle Kerberos\n" " tickets up to a maximal size. Since the PAC data can become quite large " "it\n" " is recommended to set --pac-type=NONE for NFS services.\n" "\n" " Delete an IPA service:\n" " ipa service-del HTTP/web.example.com\n" "\n" " Find all IPA services associated with a host:\n" " ipa service-find web.example.com\n" "\n" " Find all HTTP services:\n" " ipa service-find HTTP\n" "\n" " Disable the service Kerberos key and SSL certificate:\n" " ipa service-disable HTTP/web.example.com\n" "\n" " Request a certificate for an IPA service:\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\n" "\n" " Generate and retrieve a keytab for an IPA service:\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\n" "\n" msgstr "" "\n" "Служби\n" "\n" "Служба IPA — Ñлужба, Ñка виконуєтьÑÑ Ð½Ð° вузлі. Ð—Ð°Ð¿Ð¸Ñ Ñлужби IPA\n" "може зберігати реєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Kerberos, Ñертифікат SSL або те Ñ–\n" "Ñ– інше.\n" "\n" "Службою IPA можна керувати безпоÑередньо з певного комп’ютера, Ñкщо\n" "цьому комп’ютеру надано належні права доÑтупу. Таке ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð¶Ð½Ð°\n" "виконувати навіть з комп’ютерів, не пов’Ñзаних з відповідною Ñлужбою.\n" "Ðаприклад, ви можете надіÑлати запит щодо Ñертифіката SSL за допомогою\n" "реєÑтраційних даних запиÑу Ñлужби вузла. Ð”Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñлужбою за\n" "допомогою реєÑтраційних даних вузла вам Ñлід запуÑтити kinit від імені\n" "відповідного вузла:\n" "\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\n" "\n" "Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñлужби IPA надає змогу пов’Ñзаній Ñлужбі надÑилати запити щодо\n" "Ñертифіката SSL або таблиці ключів, але це Ñлід виконувати Ñк окремий\n" "крок: доÑтуп до цих даних не Ñ” прÑмим результатом Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ñлужби.\n" "\n" "У запиÑÑ– Ñлужби зберігаєтьÑÑ Ð»Ð¸ÑˆÐµ відкрита чаÑтина даних Ñертифіката;\n" "закритий ключ не зберігаєтьÑÑ.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ñ— Ñлужби IPA:\n" " ipa service-add HTTP/web.example.com\n" "\n" " ÐÐ°Ð´Ð°Ð½Ð½Ñ Ð²ÑƒÐ·Ð»Ñƒ доÑтупу до ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñертифікатом Ñлужби IPA:\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\n" " ipa role-add-member --hosts=web.example.com certadmin\n" "\n" " ÐŸÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ð³Ð¾ ÑпиÑку підтримуваних типів PAC Ð´Ð»Ñ Ñлужби:\n" " ipa service-mod HTTP/web.example.com --pac-type=MS-PAC\n" "\n" " Типовим випадком викориÑтаннÑ, коли потрібне Ð¿ÐµÑ€ÐµÐ²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ñƒ PAC, Ñ” " "NFS.\n" " У поточній верÑÑ–Ñ— відповідний код у Ñдрі Linux може оброблÑти квитки " "Kerberos\n" " лише до певного макÑимального розміру. ОÑкільки дані PAC можуть мати " "доволі\n" " великий об’єм, варто вÑтановити --pac-type=NONE Ð´Ð»Ñ Ñлужб NFS.\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñлужби IPA:\n" " ipa service-del HTTP/web.example.com\n" "\n" " Пошук вÑÑ–Ñ… Ñлужб IPA, пов’Ñзаних з вузлом:\n" " ipa service-find web.example.com\n" "\n" " Пошук вÑÑ–Ñ… Ñлужб HTTP:\n" " ipa service-find HTTP\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ ÐºÐ»ÑŽÑ‡Ð° Ñлужби Kerberos Ñ– Ñертифіката SSL:\n" " ipa service-disable HTTP/web.example.com\n" "\n" " ÐадÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ щодо Ñертифіката Ð´Ð»Ñ Ñлужби IPA:\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ– Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– ключів Ð´Ð»Ñ Ñлужби IPA:\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\n" "\n" msgid "Requires pre-authentication" msgstr "Вимагає попереднього розпізнаваннÑ" msgid "Pre-authentication is required for the service" msgstr "Ð”Ð»Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ з цією Ñлужбою потрібне попереднє розпізнаваннÑ" msgid "Trusted for delegation" msgstr "Довірено Ð´Ð»Ñ ÑƒÐ¿Ð¾Ð²Ð½Ð¾Ð²Ð°Ð¶ÐµÐ½Ð½Ñ" msgid "Client credentials may be delegated to the service" msgstr "РеєÑтраційні дані клієнта може бути передано Ñлужбі" msgid "missing service" msgstr "не виÑтачає запиÑу Ñлужби" msgid "blank service" msgstr "порожній Ð·Ð°Ð¿Ð¸Ñ Ñлужби" msgid "unable to determine realm" msgstr "не вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ облаÑть" msgid "This principal is required by the IPA master" msgstr "Цей реєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Ð¿Ð¾Ñ‚Ñ€Ñ–Ð±ÐµÐ½ оÑновному Ñерверу IPA" msgid "service" msgstr "Ñлужба" msgid "services" msgstr "Ñлужби" msgid "Service principal" msgstr "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Ñлужби" msgid "PAC type" msgstr "Тип PAC" msgid "" "Override default list of supported PAC types. Use 'NONE' to disable PAC " "support for this service, e.g. this might be necessary for NFS services." msgstr "" "Перевизначити типовий ÑпиÑок підтримуваних типів PAC. СкориÑтайтеÑÑ " "значеннÑм «NONE», щоб вимкнути підтримку PAC Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— Ñлужби. Це, наприклад, " "може бути необхідним Ð´Ð»Ñ Ñлужб NFS." msgid "NONE value cannot be combined with other PAC types" msgstr "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ NONE не можна поєднувати з іншими типами PAC" msgid "Add a new IPA new service." msgstr "Додати нову Ñлужбу IPA." #, python-format msgid "Added service \"%(value)s\"" msgstr "Додано Ñлужбу «%(value)s»" msgid "force principal name even if not in DNS" msgstr "" "примуÑове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð½Ð°Ð·Ð²Ð¸ реєÑтраційного запиÑу, навіть Ñкщо назви немає у DNS" #, python-format msgid "The host '%s' does not exist to add a service to." msgstr "Ðе Ñ–Ñнує вузла «%s», до Ñкого Ñлід було додати Ñлужбу." msgid "Delete an IPA service." msgstr "Вилучити Ñлужбу IPA." #, python-format msgid "Deleted service \"%(value)s\"" msgstr "Вилучено Ñлужбу «%(value)s»" msgid "Modify an existing IPA service." msgstr "Змінити вже Ñтворену Ñлужбу IPA." #, python-format msgid "Modified service \"%(value)s\"" msgstr "Змінено Ñлужбу «%(value)s»" msgid "Search for IPA services." msgstr "Знайти Ñлужби IPA." #, python-format msgid "%(count)d service matched" msgid_plural "%(count)d services matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d Ñлужби" msgstr[1] "вÑтановлено відповідніÑть %(count)d Ñлужб" msgstr[2] "вÑтановлено відповідніÑть %(count)d Ñлужб" msgid "Display information about an IPA service." msgstr "Показати дані щодо Ñлужби IPA." msgid "Add hosts that can manage this service." msgstr "Додати вузли, Ñкі можуть керувати цією Ñлужбою." msgid "Remove hosts that can manage this service." msgstr "Вилучити вузли, Ñкі можуть керувати цією Ñлужбою." msgid "Disable the Kerberos key and SSL certificate of a service." msgstr "Вимкнути ключ Kerberos Ñ– Ñертифікат SSL Ñлужби." #, python-format msgid "Disabled service \"%(value)s\"" msgstr "Вимкнено Ñлужбу «%(value)s»" msgid "" "\n" "Sudo Commands\n" "\n" "Commands used as building blocks for sudo\n" "\n" "EXAMPLES:\n" "\n" " Create a new command\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Remove a command\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgstr "" "\n" "Команди sudo\n" "\n" "Команди, викориÑтані Ñк будівельні блоки Ð´Ð»Ñ sudo\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу команди\n" " ipa sudocmd-add --desc='Ð§Ð¸Ñ‚Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² журналу' /usr/bin/less\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgid "commands for controlling sudo configuration" msgstr "команди ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñм sudo" msgid "sudo command" msgstr "команда sudo" msgid "sudo commands" msgstr "команди sudo" msgid "Sudo Commands" msgstr "Команди sudo" msgid "Sudo Command" msgstr "Команда sudo" msgid "A description of this command" msgstr "ÐžÐ¿Ð¸Ñ Ñ†Ñ–Ñ”Ñ— команди" msgid "Create new Sudo Command." msgstr "Створити Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸ sudo." #, python-format msgid "Added Sudo Command \"%(value)s\"" msgstr "Додано команду sudo «%(value)s»" msgid "Delete Sudo Command." msgstr "Вилучити Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¸ sudo." #, python-format msgid "Deleted Sudo Command \"%(value)s\"" msgstr "Вилучено команду sudo «%(value)s»" msgid "Modify Sudo Command." msgstr "Змінити команду sudo." #, python-format msgid "Modified Sudo Command \"%(value)s\"" msgstr "Змінено команду sudo «%(value)s»" msgid "Search for Sudo Commands." msgstr "Знайти команди sudo." #, python-format msgid "%(count)d Sudo Command matched" msgid_plural "%(count)d Sudo Commands matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d команд sudo" msgstr[1] "вÑтановлено відповідніÑть %(count)d команд sudo" msgstr[2] "вÑтановлено відповідніÑть %(count)d команд sudo" msgid "Display Sudo Command." msgstr "Показати команду sudo." msgid "" "\n" "Groups of Sudo Commands\n" "\n" "Manage groups of Sudo Commands.\n" "\n" "EXAMPLES:\n" "\n" " Add a new Sudo Command Group:\n" " ipa sudocmdgroup-add --desc='administrators commands' admincmds\n" "\n" " Remove a Sudo Command Group:\n" " ipa sudocmdgroup-del admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/" "vim admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa group-remove-member --sudocmds=/usr/bin/less admincmds\n" "\n" " Show a Sudo Command Group:\n" " ipa group-show localadmins\n" msgstr "" "\n" "Групи команд sudo\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ€ÑƒÐ¿Ð°Ð¼Ð¸ команд sudo.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Додати нову групу команд sudo:\n" " ipa sudocmdgroup-add --desc='administrators commands' admincmds\n" "\n" " Вилучити групу команд sudo:\n" " ipa sudocmdgroup-del admincmds\n" "\n" " ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñтю групи команд sudo, команди:\n" " ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/" "vim admincmds\n" "\n" " ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñтю групи команд sudo, команди:\n" " ipa group-remove-member --sudocmds=/usr/bin/less admincmds\n" "\n" " Показ групи команд sudo:\n" " ipa group-show localadmins\n" msgid "sudo command group" msgstr "група команд sudo" msgid "sudo command groups" msgstr "групи команд sudo" msgid "Sudo Command Group" msgstr "Група команд sudo" msgid "Create new Sudo Command Group." msgstr "Створити групу команд sudo." #, python-format msgid "Added Sudo Command Group \"%(value)s\"" msgstr "Додано групу команд sudo «%(value)s»" msgid "Delete Sudo Command Group." msgstr "Вилучити групу команд sudo." #, python-format msgid "Deleted Sudo Command Group \"%(value)s\"" msgstr "Вилучено групу команд sudo «%(value)s»" msgid "Modify Sudo Command Group." msgstr "Змінити групу команд sudo." #, python-format msgid "Modified Sudo Command Group \"%(value)s\"" msgstr "Змінено групу команд sudo «%(value)s»" msgid "Search for Sudo Command Groups." msgstr "Шукати групи команд sudo." #, python-format msgid "%(count)d Sudo Command Group matched" msgid_plural "%(count)d Sudo Command Groups matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d групи команд sudo" msgstr[1] "вÑтановлено відповідніÑть %(count)d груп команд sudo" msgstr[2] "вÑтановлено відповідніÑть %(count)d груп команд sudo" msgid "Display Sudo Command Group." msgstr "Показати групу команд sudo." msgid "Add members to Sudo Command Group." msgstr "Додати учаÑників до групи команд sudo." msgid "Remove members from Sudo Command Group." msgstr "Вилучити учаÑників з групи команд sudo." msgid "" "\n" "Sudo Rules\n" "\n" "Sudo (su \"do\") allows a system administrator to delegate authority to\n" "give certain users (or groups of users) the ability to run some (or all)\n" "commands as root or another user while providing an audit trail of the\n" "commands and their arguments.\n" "\n" "FreeIPA provides a means to configure the various aspects of Sudo:\n" " Users: The user(s)/group(s) allowed to invoke Sudo.\n" " Hosts: The host(s)/hostgroup(s) which the user is allowed to to invoke " "Sudo.\n" " Allow Command: The specific command(s) permitted to be run via Sudo.\n" " Deny Command: The specific command(s) prohibited to be run via Sudo.\n" " RunAsUser: The user(s) or group(s) of users whose rights Sudo will be " "invoked with.\n" " RunAsGroup: The group(s) whose gid rights Sudo will be invoked with.\n" " Options: The various Sudoers Options that can modify Sudo's behavior.\n" "\n" "An order can be added to a sudorule to control the order in which they\n" "are evaluated (if the client supports it). This order is an integer and\n" "must be unique.\n" "\n" "FreeIPA provides a designated binddn to use with Sudo located at:\n" "uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com\n" "\n" "To enable the binddn run the following command to set the password:\n" "LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -" "ZZ -D \"cn=Directory Manager\" uid=sudo,cn=sysaccounts,cn=etc,dc=example," "dc=com\n" "\n" "For more information, see the FreeIPA Documentation to Sudo.\n" msgstr "" "\n" "Правила sudo\n" "\n" "Sudo (su \"do\") надає змогу адмініÑтраторові ÑиÑтеми уповноважити\n" "певних кориÑтувачів (або групи кориÑтувачів) на Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð¿ÐµÐ²Ð½Ð¸Ñ… (або\n" "вÑÑ–Ñ…) команд від імені адмініÑтратора або іншого кориÑтувача зі\n" "збереженнÑм можливоÑті Ð¾Ð·Ð½Ð°Ð¹Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· журналом команд Ñ– аргументів.\n" "\n" "У FreeIPA передбачено можливіÑть Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ñ–Ð·Ð½Ð¾Ð¼Ð°Ð½Ñ–Ñ‚Ð½Ð¸Ñ… аÑпектів\n" "роботи sudo:\n" " КориÑтувачі: кориÑтувачі Ñ– групи, Ñким можна викориÑтовувати sudo.\n" " Вузли: вузли Ñ– групи вузлів, кориÑтувачам Ñких можна викориÑтовувати " "sudo.\n" " Дозволена команда: команда, Ñку можна виконувати за допомогою sudo.\n" " Заборонена команда: команда, Ñку не можна виконувати за допомогою sudo.\n" " КориÑтувач запуÑку: кориÑтувач або група кориÑтувачів, від імені Ñких " "виконуєтьÑÑ sudo.\n" " Група запуÑку: група, з ідентифікатором Ñкої буде запущено sudo.\n" " Параметри: різноманітні параметри sudoers, Ñкі можуть змінювати поведінку " "sudo.\n" "\n" "До правила sudo може бути додано порÑдковий номер з метою ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ " "порÑдком, у Ñкому\n" "заÑтоÑовуютьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð° (Ñкщо клієнтом передбачено можливіÑть впорÑÐ´ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ " "правил).\n" "ПорÑдковий номер Ñ” цілим чиÑлом, унікальним Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ з правил правила.\n" "\n" "FreeIPA надає підпиÑаний binddn Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð· sudo з адреÑою:\n" "uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com\n" "\n" "Щоб увімкнути binddn, виконайте таку команду Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ:\n" "LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -" "ZZ -D \"cn=Directory Manager\" uid=sudo,cn=sysaccounts,cn=etc,dc=example," "dc=com\n" "\n" "Докладніші відомоÑті можна знайти у документації до FreeIPA з sudo.\n" msgid "Commands for controlling sudo configuration" msgstr "Команди ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñм sudo" msgid "this option has been deprecated." msgstr "цей параметр вважаєтьÑÑ Ð·Ð°Ñтарілим." msgid "sudo rule" msgstr "правило sudo" msgid "sudo rules" msgstr "правила sudo" msgid "Sudo Rules" msgstr "Правила Sudo" msgid "Sudo Rule" msgstr "Правило sudo" msgid "Command category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´" msgid "Command category the rule applies to" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´, до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "RunAs User category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð·Ð°Ð¿ÑƒÑку від імені кориÑтувачів" msgid "RunAs User category the rule applies to" msgstr "" "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð·Ð°Ð¿ÑƒÑку від імені кориÑтувачів, до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "RunAs Group category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð·Ð°Ð¿ÑƒÑку від імені групи" msgid "RunAs Group category the rule applies to" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð·Ð°Ð¿ÑƒÑку від імені групи, до Ñкої заÑтоÑовуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾" msgid "Sudo order" msgstr "ПорÑдок sudo" msgid "integer to order the Sudo rules" msgstr "ціле чиÑло Ð´Ð»Ñ Ð²Ð¿Ð¾Ñ€ÑÐ´ÐºÐ¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð» sudo" msgid "Sudo Allow Commands" msgstr "Дозволені команди sudo" msgid "Sudo Deny Commands" msgstr "Заборонені команди sudo" msgid "Sudo Allow Command Groups" msgstr "Групи дозволених команд sudo" msgid "Sudo Deny Command Groups" msgstr "Групи заборонених команд sudo" msgid "RunAs Users" msgstr "КориÑтувачі запуÑку від імені" msgid "Run as a user" msgstr "ЗапуÑк від кориÑтувача" msgid "Groups of RunAs Users" msgstr "Групи кориÑтувачів запуÑку від імені" msgid "Run as any user within a specified group" msgstr "ЗапуÑкати від імені будь-Ñкого кориÑтувача вказаної групи" msgid "External User" msgstr "Зовнішній кориÑтувач" msgid "External User the rule applies to (sudorule-find only)" msgstr "" "Зовнішній кориÑтувач, до Ñкого заÑтоÑовуватиметьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ (лише sudorule-" "find)" msgid "RunAs External User" msgstr "Зовнішній кориÑтувач Ð´Ð»Ñ RunAs" msgid "External User the commands can run as (sudorule-find only)" msgstr "" "Зовнішній кориÑтувач, від імені Ñкого можна віддавати команди (лише sudorule-" "find)" msgid "RunAs External Group" msgstr "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð³Ñ€ÑƒÐ¿Ð° Ð´Ð»Ñ RunAs" msgid "External Group the commands can run as (sudorule-find only)" msgstr "" "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð³Ñ€ÑƒÐ¿Ð°, від імені Ñкої можна віддавати команди (лише sudorule-find)" msgid "Sudo Option" msgstr "Пункт sudo" msgid "RunAs Groups" msgstr "Групи запуÑку від імені" msgid "Run with the gid of a specified POSIX group" msgstr "ЗапуÑкати з ідентифікатором вказаної групи POSIX" #, python-format msgid "order must be a unique value (%(order)d already used by %(rule)s)" msgstr "" "порÑдковий номер повинен мати унікальне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ (%(order)d вже викориÑтано " "Ð´Ð»Ñ %(rule)s)" msgid "Create new Sudo Rule." msgstr "Створити правило sudo." #, python-format msgid "Added Sudo Rule \"%(value)s\"" msgstr "Додано правило sudo «%(value)s»" msgid "Delete Sudo Rule." msgstr "Вилучити правило sudo." #, python-format msgid "Deleted Sudo Rule \"%(value)s\"" msgstr "Вилучено правило sudo «%(value)s»" msgid "Modify Sudo Rule." msgstr "Змінити правило sudo." #, python-format msgid "Modified Sudo Rule \"%(value)s\"" msgstr "Змінено правило sudo «%(value)s»" msgid "" "command category cannot be set to 'all' while there are allow or deny " "commands" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— команд Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all», доки Ñ” запиÑи " "дозволу або заборони команд" msgid "user runAs category cannot be set to 'all' while there are users" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— запуÑку від імені кориÑтувачів Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ " "«all», доки Ñ” запиÑи Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ñ… кориÑтувачів" msgid "group runAs category cannot be set to 'all' while there are groups" msgstr "" "не можна вÑтановлювати Ð´Ð»Ñ ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ— запуÑку від імені груп Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Â«all», " "доки Ñ” запиÑи Ð´Ð»Ñ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ñ… груп" msgid "Search for Sudo Rule." msgstr "Знайти правило sudo." #, python-format msgid "%(count)d Sudo Rule matched" msgid_plural "%(count)d Sudo Rules matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d правила sudo" msgstr[1] "вÑтановлено відповідніÑть %(count)d правил sudo" msgstr[2] "вÑтановлено відповідніÑть %(count)d правил sudo" msgid "Display Sudo Rule." msgstr "Показати правило sudo." msgid "Enable a Sudo Rule." msgstr "Увімкнути правило sudo." #, python-format msgid "Enabled Sudo Rule \"%s\"" msgstr "Увімкнено правило sudo «%s»" msgid "Disable a Sudo Rule." msgstr "Вимкнути правило sudo." #, python-format msgid "Disabled Sudo Rule \"%s\"" msgstr "Вимкнено правило «%s»" msgid "Add commands and sudo command groups affected by Sudo Rule." msgstr "Додати команди Ñ– групи команд sudo, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "commands cannot be added when command category='all'" msgstr "не можна додавати команди, Ñкщо ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´=«all»" msgid "Remove commands and sudo command groups affected by Sudo Rule." msgstr "Вилучити команди Ñ– групи команд sudo, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "Add users and groups affected by Sudo Rule." msgstr "Додати запиÑи кориÑтувачів та груп, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "Remove users and groups affected by Sudo Rule." msgstr "Вилучити запиÑи кориÑтувачів та груп, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "Add hosts and hostgroups affected by Sudo Rule." msgstr "Додати вузли та групи вузлів, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "Remove hosts and hostgroups affected by Sudo Rule." msgstr "Вилучити вузли та групи вузлів, Ñких ÑтоÑуєтьÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð¾ sudo." msgid "Add users and groups for Sudo to execute as." msgstr "" "Додати кориÑтувачів та групи Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ sudo від їхнього імені." msgid "users cannot be added when runAs user or runAs group category='all'" msgstr "" "не можна додавати запиÑи кориÑтувачів, Ñкщо ÐºÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ñ–Ñ Ð·Ð°Ð¿ÑƒÑку від імені " "кориÑтувачів або запуÑку від імені груп=«all»" #, python-format msgid "RunAsUser does not accept '%(name)s' as a user name" msgstr "Ðе можна вказувати «%(name)s» Ñк Ñ–Ð¼â€™Ñ ÐºÐ¾Ñ€Ð¸Ñтувача у запиÑÑ– RunAsUser" #, python-format msgid "RunAsUser does not accept '%(name)s' as a group name" msgstr "Ðазва групи «%(name)s» Ñ” неприйнÑтною Ð´Ð»Ñ RunAsUser" msgid "Remove users and groups for Sudo to execute as." msgstr "" "Вилучити кориÑтувачів та групи Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´ sudo від їхнього імені." msgid "Add group for Sudo to execute as." msgstr "Додати групу Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð´Ð¾ запиÑу sudo." #, python-format msgid "RunAsGroup does not accept '%(name)s' as a group name" msgstr "Ðазва групи «%(name)s» Ñ” неприйнÑтною Ð´Ð»Ñ RunAsGroup" msgid "Remove group for Sudo to execute as." msgstr "Вилучити групу Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð· запиÑу sudo." msgid "Add an option to the Sudo Rule." msgstr "Додати пункт до правила sudo." #, python-format msgid "Added option \"%(option)s\" to Sudo Rule \"%(rule)s\"" msgstr "До правила sudo «%(rule)s» додано параметр «%(option)s»" msgid "Remove an option from Sudo Rule." msgstr "Вилучити пункт з правила sudo." #, python-format msgid "Removed option \"%(option)s\" from Sudo Rule \"%(rule)s\"" msgstr "З правила sudo «%(rule)s» вилучено параметр «%(option)s»" msgid "" "\n" "Cross-realm trusts\n" "\n" "Manage trust relationship between IPA and Active Directory domains.\n" "\n" "In order to allow users from a remote domain to access resources in IPA\n" "domain, trust relationship needs to be established. Currently IPA supports\n" "only trusts between IPA and Active Directory domains under control of " "Windows\n" "Server 2008 or later, with functional level 2008 or later.\n" "\n" "Please note that DNS on both IPA and Active Directory domain sides should " "be\n" "configured properly to discover each other. Trust relationship relies on\n" "ability to discover special resources in the other domain via DNS records.\n" "\n" "Examples:\n" "\n" "1. Establish cross-realm trust with Active Directory using AD administrator\n" " credentials:\n" "\n" " ipa trust-add --type=ad --admin --" "password\n" "\n" "2. List all existing trust relationships:\n" "\n" " ipa trust-find\n" "\n" "3. Show details of the specific trust relationship:\n" "\n" " ipa trust-show \n" "\n" "4. Delete existing trust relationship:\n" "\n" " ipa trust-del \n" "\n" "Once trust relationship is established, remote users will need to be mapped\n" "to local POSIX groups in order to actually use IPA resources. The mapping " "should\n" "be done via use of external membership of non-POSIX group and then this " "group\n" "should be included into one of local POSIX groups.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" "\n" "\n" "GLOBAL TRUST CONFIGURATION\n" "\n" "When IPA AD trust subpackage is installed and ipa-adtrust-install is run,\n" "a local domain configuration (SID, GUID, NetBIOS name) is generated. These\n" "identifiers are then used when communicating with a trusted domain of the\n" "particular type.\n" "\n" "1. Show global trust configuration for Active Directory type of trusts:\n" "\n" " ipa trustconfig-show --type ad\n" "\n" "2. Modify global configuration for all trusts of Active Directory type and " "set\n" " a different fallback primary group (fallback primary group GID is used " "as\n" " a primary user GID if user authenticating to IPA domain does not have any " "other\n" " primary GID already set):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"alternative AD " "group\"\n" "\n" "3. Change primary fallback group back to default hidden group (any group " "with\n" " posixGroup object class is allowed):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"Default SMB Group" "\"\n" msgstr "" "\n" "Довіра між облаÑÑ‚Ñми\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð½Ð¾Ñинами довіри між доменами IPA Ñ– Active Directory.\n" "\n" "З метою Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу кориÑтувачам віддаленого домену до реÑурÑів у " "домені\n" "IPA Ñлід вÑтановити відноÑини довіри. У поточній верÑÑ–Ñ— у IPA передбачено\n" "підтримку довіри лише між доменами IPA Ñ– Active Directory під керуваннÑм " "Windows\n" "Server 2008 або новішої верÑÑ–Ñ— з функціональними можливоÑÑ‚Ñми Ñ€Ñ–Ð²Ð½Ñ 2008 " "або\n" "новішої верÑÑ–Ñ—.\n" "\n" "Будь лаÑка, зауважте, що Ñлід належним чином налаштувати DNS на обох " "доменах,\n" "IPA Ñ– Active Directory, щоб домени могли виÑвити один одного. " "ПрацездатніÑть\n" "відноÑин довіри залежить від можливоÑті виÑÐ²Ð»ÐµÐ½Ð½Ñ Ñпеціальних реÑурÑів у\n" "іншому домені за допомогою запиÑів DNS.\n" "\n" "Приклад:\n" "\n" "1. Ð’Ñтановити довіру між облаÑÑ‚Ñми з Active Directory за допомогою " "реєÑтраційних\n" " даних адмініÑтратора AD:\n" "\n" " ipa trust-add --type=ad <домен.ad> --admin <адмініÑтратор домену AD> --" "password\n" "\n" "2. Показати ÑпиÑок вÑÑ–Ñ… наÑвних відноÑин довіри:\n" "\n" " ipa trust-find\n" "\n" "3. Показати подробиці щодо певних відноÑин довіри:\n" "\n" " ipa trust-show <домен.ad>\n" "\n" "4. Вилучити наÑвні відноÑини довіри:\n" "\n" " ipa trust-del <домен.ad>\n" "\n" "Щойно відноÑини довіри буде вÑтановлено, віддалених кориÑтувачів Ñлід " "прив’Ñзати\n" "до локальних груп POSIX, щоб ÑкориÑтатиÑÑ Ñ€ÐµÑурÑами IPA. Прив’Ñзку Ñлід\n" "виконати за допомогою викориÑÑ‚Ð°Ð½Ð½Ñ Ð·Ð¾Ð²Ð½Ñ–ÑˆÐ½ÑŒÐ¾Ñ— учаÑті групи не-POSIX, а " "потім\n" "цю групу має бути включено до однієї з локальних груп POSIX.\n" "\n" "Приклади:\n" "\n" "1. Створити групу Ð´Ð»Ñ Ð¿Ñ€Ð¸Ð²â€™Ñзки адмініÑтраторів та їхньої локальної групи " "POSIX\n" " довіреного домену:\n" "\n" " ipa group-add --desc='<домен.ad> admins external map' ad_admins_external " "--external\n" " ipa group-add --desc='<домен.ad> admins' ad_admins\n" "\n" "2. Додати ідентифікатор безпеки Domain Admins домену <домен.ad> до групи " "ad_admins_external:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Дозволити прив’ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ ÑƒÑ‡Ð°Ñників групи ad_admins_external до групи POSIX " "ad_admins:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. Показати ÑпиÑок зовнішніх учаÑників групи ad_admins_external Ð´Ð»Ñ " "переглÑду їхніх SID:\n" "\n" " ipa group-show ad_admins_external\n" "\n" "\n" "ÐÐЛÐШТУВÐÐÐЯ ДОВІРИ ЗÐГÐЛЬÐОГО РІВÐЯ\n" "\n" "Якщо вÑтановлено підпакунок довіри AD IPA та запущено ipa-adtrust-install,\n" "ÑтворюютьÑÑ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ домену (SID, GUID, назва NetBIOS). " "ПіÑлÑ\n" "цього Ñтворені ідентифікатори викориÑтовуютьÑÑ Ð´Ð»Ñ Ð¾Ð±Ð¼Ñ–Ð½Ñƒ даними з\n" "довіреним доменом певного типу.\n" "\n" "1. Показати Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ загального Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ñ–Ð² довіри Active " "Directory:\n" "\n" " ipa trustconfig-show --type ad\n" "\n" "2. Змінити загальні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð»Ñ Ð²ÑÑ–Ñ… довір типу Active Directory Ñ–\n" " вÑтановити іншу резервну оÑновну групу (GID резервної оÑновної групи\n" " викориÑтовуєтьÑÑ Ñк GID оÑновного кориÑтувача, Ñкщо кориÑтувача\n" " розпізнано у домені IPA, але він не має жодного вже вÑтановленого\n" " оÑновного GID):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"alternative AD " "group\"\n" "\n" "3. Повернути Ð´Ð»Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð½Ð¾Ñ— оÑновної групи Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ñ— прихованої групи\n" " (будь-Ñкої групи, у Ñкій дозволено ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² posixGroup):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"Default SMB Group" "\"\n" msgid "Non-Active Directory domain" msgstr "Домен не-Active Directory" msgid "RFC4120-compliant Kerberos realm" msgstr "ОблаÑть Kerberos, ÑуміÑна з RFC4120" msgid "Trusting forest" msgstr "«ЛіÑ» довіри" msgid "Trusted forest" msgstr "Довірений «ліÑ»" msgid "Two-way trust" msgstr "Двобічна довіра" msgid "Established and verified" msgstr "Ð’Ñтановлено Ñ– перевірено" msgid "Waiting for confirmation by remote side" msgstr "Очікуємо на Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð· віддаленого боку" msgid "Unknown" msgstr "Ðевідомо" msgid "Trust type (ad for Active Directory, default)" msgstr "Тип довіри (типовим Ð´Ð»Ñ Active Directory Ñ” ad)" msgid "trust" msgstr "довіра" msgid "trusts" msgstr "запиÑи довіри" msgid "Trust" msgstr "Довіра" msgid "Realm name" msgstr "Ðазва облаÑті" msgid "SID blacklist incoming" msgstr "Чорний ÑпиÑок вхідних SID" msgid "SID blacklist outgoing" msgstr "Чорний ÑпиÑок вихідних SID" #, python-format msgid "invalid SID: %(value)s" msgstr "некоректний SID: %(value)s" msgid "" "\n" "Add new trust to use.\n" "\n" "This command establishes trust relationship to another domain\n" "which becomes 'trusted'. As result, users of the trusted domain\n" "may access resources of this domain.\n" "\n" "Only trusts to Active Directory domains are supported right now.\n" "\n" "The command can be safely run multiple times against the same domain,\n" "this will cause change to trust relationship credentials on both\n" "sides.\n" " " msgstr "" "\n" "Додати новий Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтаннÑ.\n" "\n" "За допомогою цієї команди можна вÑтановити відноÑини довіри з\n" "іншим доменом, Ñкий піÑÐ»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вважаєтьÑÑ Â«Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¸Ð¼Â». У результаті\n" "кориÑтувачі довіреного домену зможуть отримувати доÑтуп до реÑурÑів\n" "цього домену.\n" "\n" "У поточній верÑÑ–Ñ— передбачено підтримку лише відноÑин довіри з доменами\n" "Active Directory.\n" "\n" "Команду можна безпечно запуÑкати декілька разів Ð´Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñ– того Ñамого\n" "домену, такий запуÑк призводить до зміни у реєÑтраційних запиÑах відноÑин\n" "довіри з обох боків.\n" " " msgid "Active Directory domain administrator" msgstr "ÐдмініÑтратор домену Active Directory" msgid "Active directory domain administrator's password" msgstr "Пароль адмініÑтратора домену Active Directory" msgid "Domain controller for the Active Directory domain (optional)" msgstr "Контролер домену Active Directory (необов’Ñзковий)" msgid "Shared secret for the trust" msgstr "Оприлюднений ключ Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸" msgid "First Posix ID of the range reserved for the trusted domain" msgstr "" "Перший ідентифікатор POSIX діапазону, зарезервованого Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену" msgid "Size of the ID range reserved for the trusted domain" msgstr "" "Розмір діапазону ідентифікаторів, зарезервованого Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену" msgid "Type of trusted domain ID range, one of {vals}" msgstr "" "Тип діапазону ідентифікаторів довіреного домену, одне з таких значень: {vals}" #, python-format msgid "Added Active Directory trust for realm \"%(value)s\"" msgstr "Додано Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ Active Directory Ð´Ð»Ñ Ð¾Ð±Ð»Ð°Ñті «%(value)s»" msgid "AD Trust setup" msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ AD" msgid "" "Cannot perform join operation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA" msgstr "" "Виконати дію з Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð±ÐµÐ· вÑтановленої підтримки Samba 4 неможливо. " "ПереконайтеÑÑ, що вами вÑтановлено підпакунок IPA server-trust-ad." msgid "missing base_id" msgstr "не виÑтачає base_id" msgid "pysss_murmur is not available on the server and no base-id is given." msgstr "pysss_murmur на Ñервері не доÑтупний, отже base-id не надано." msgid "trust type" msgstr "тип довіри" msgid "only \"ad\" is supported" msgstr "передбачено підтримку лише «ad»" msgid "Trusted domain and administrator account use different realms" msgstr "" "Довіреним доменом Ñ– обліковим запиÑом адмініÑтратора викориÑтовуютьÑÑ Ñ€Ñ–Ð·Ð½Ñ– " "облаÑті" msgid "Realm administrator password should be specified" msgstr "Має бути вказано пароль адмініÑтратора облаÑті" msgid "id range type" msgstr "тип діапазону ідентифікаторів" msgid "" "Only the ipa-ad-trust and ipa-ad-trust-posix are allowed values for --range-" "type when adding an AD trust." msgstr "" "Якщо додаєтьÑÑ Ð·Ð²â€™Ñзок довіри AD, значеннÑм --range-type має бути лише ipa-" "ad-trust або ipa-ad-trust-posix." msgid "id range" msgstr "діапазон ідентифікаторів" msgid "" "An id range already exists for this trust. You should either delete the old " "range, or exclude --base-id/--range-size options from the command." msgstr "" "Ð”Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ зв’Ñзку довіри вже Ñ–Ñнує діапазон ідентифікаторів. Вам Ñлід або " "вилучити попередній діапазон, або виключити з команди параметри --base-id/--" "range-size." msgid "range exists" msgstr "діапазон вже Ñ–Ñнує" msgid "" "ID range with the same name but different domain SID already exists. The ID " "range for the new trusted domain must be created manually." msgstr "" "Вже Ñ–Ñнує діапазон ідентифікаторів з тією Ñамою назвою але іншим доменом " "SID. Діапазон ідентифікаторів Ð´Ð»Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ довіреного домену має бути Ñтворено " "вручну." msgid "range type change" msgstr "зміна типу діапазону" msgid "" "ID range for the trusted domain already exists, but it has a different type. " "Please remove the old range manually, or do not enforce type via --range-" "type option." msgstr "" "Діапазон ідентифікаторів Ð´Ð»Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¾Ð³Ð¾ домену вже Ñ–Ñнує, але належить до " "іншого типу. Будь лаÑка, вилучіть попередній діапазон вручну або не " "визначайте тип у примуÑовому порÑдку за допомогою параметра --range-type." #, python-format msgid "Re-established trust to domain \"%(value)s\"" msgstr "Відновлено довіру до домену «%(value)s»" #, python-format msgid "Unable to resolve domain controller for '%s' domain. " msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ контролер домену Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ «%s». " msgid "" "Forward policy is defined for it in IPA DNS, perhaps forwarder points to " "incorrect host?" msgstr "" "Ð”Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾ у DNS IPA визначено правила переÑпрÑмовуваннÑ. Можливо, " "переÑпрÑмовувач вказує не помилковий вузол?" #, python-format msgid "" "IPA manages DNS, please verify your DNS configuration and make sure that " "service records of the '%(domain)s' domain can be resolved. Examples how to " "configure DNS with CLI commands or the Web UI can be found in the " "documentation. " msgstr "" "IPA керує DNS. Будь лаÑка, переконайтеÑÑ, що поточні Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ DNS " "уможливлюють Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð°Ð´Ñ€ÐµÑ Ñлужбових запиÑів домену «%(domain)s». " "Приклади Ð½Ð°Ð»Ð°ÑˆÑ‚Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ DNS за допомогою командного інтерфейÑу або " "вебінтерфейÑу наведено у документації. " #, python-format msgid "" "Since IPA does not manage DNS records, ensure DNS is configured to resolve " "'%(domain)s' domain from IPA hosts and back." msgstr "" "ОÑкільки IPA не керує запиÑами DNS, Ñлід налаштувати DNS так, щоб ÑиÑтема " "визначала адреÑу домену «%(domain)s» за даними щодо вузлів IPA, Ñ– навпаки." msgid "Unable to verify write permissions to the AD" msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ð¸Ñ‚Ð¸ права доÑтупу на Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ AD" msgid "Not enough arguments specified to perform trust setup" msgstr "Вказано недоÑтатньо аргументів Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚Ð¾Ð²ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸" msgid "Delete a trust." msgstr "Вилучити Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸." #, python-format msgid "Deleted trust \"%(value)s\"" msgstr "Вилучено Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ «%(value)s»" msgid "" "\n" " Modify a trust (for future use).\n" "\n" " Currently only the default option to modify the LDAP attributes is\n" " available. More specific options will be added in coming releases.\n" " " msgstr "" "\n" " Змінити Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ (Ð´Ð»Ñ Ð½Ð°Ñтупного викориÑтаннÑ).\n" "\n" " У поточній верÑÑ–Ñ— можлива зміна лише типова зміна атрибутів LDAP.\n" " Додаткові варіанти буде додано у наÑтупних випуÑках.\n" " " #, python-format msgid "Modified trust \"%(value)s\" (change will be effective in 60 seconds)" msgstr "Змінено довіру «%(value)s» (зміни набудуть чинноÑті за 60 Ñекунд)" msgid "Search for trusts." msgstr "Шукати запиÑи довіри." #, python-format msgid "%(count)d trust matched" msgid_plural "%(count)d trusts matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d запиÑу довіри" msgstr[1] "вÑтановлено відповідніÑть %(count)d запиÑів довіри" msgstr[2] "вÑтановлено відповідніÑть %(count)d запиÑів довіри" msgid "Display information about a trust." msgstr "Показати дані щодо довіри." msgid "trust configuration" msgstr "довірені налаштуваннÑ" msgid "Global Trust Configuration" msgstr "Загальні довірені налаштуваннÑ" msgid "Security Identifier" msgstr "Ідентифікатор безпеки" msgid "NetBIOS name" msgstr "Ðазва NetBIOS" msgid "Domain GUID" msgstr "GUID домену" msgid "Fallback primary group" msgstr "Резервна оÑновна група" msgid "unsupported trust type" msgstr "непідтримуваний тип довіри" msgid "Modify global trust configuration." msgstr "Змінити Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ на загальному рівні." #, python-format msgid "Modified \"%(value)s\" trust configuration" msgstr "Змінено Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ «%(value)s»" msgid "Show global trust configuration." msgstr "Показати Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸ на загальному рівні." msgid "Resolve security identifiers of users and groups in trusted domains" msgstr "" "Визначати ідентифікатори безпеки кориÑтувачів та груп у довірених доменах" msgid "Security Identifiers (SIDs)" msgstr "Ідентифікатори безпеки (SID)" msgid "Name" msgstr "Ðазва" msgid "SID" msgstr "SID" msgid "Determine whether ipa-adtrust-install has been run on this system" msgstr "Визначити, чи було запущено ipa-adtrust-install Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— ÑиÑтеми" msgid "" "\n" "Users\n" "\n" "Manage user entries. All users are POSIX users.\n" "\n" "IPA supports a wide range of username formats, but you need to be aware of " "any\n" "restrictions that may apply to your particular environment. For example,\n" "usernames that start with a digit or usernames that exceed a certain length\n" "may cause problems for some UNIX systems.\n" "Use 'ipa config-mod' to change the username format allowed by IPA tools.\n" "\n" "Disabling a user account prevents that user from obtaining new Kerberos\n" "credentials. It does not invalidate any credentials that have already\n" "been issued.\n" "\n" "Password management is not a part of this module. For more information\n" "about this topic please see: ipa help passwd\n" "\n" "Account lockout on password failure happens per IPA master. The user-status\n" "command can be used to identify which master the user is locked out on.\n" "It is on that master the administrator must unlock the user.\n" "\n" "EXAMPLES:\n" "\n" " Add a new user:\n" " ipa user-add --first=Tim --last=User --password tuser1\n" "\n" " Find all users whose entries include the string \"Tim\":\n" " ipa user-find Tim\n" "\n" " Find all users with \"Tim\" as the first name:\n" " ipa user-find --first=Tim\n" "\n" " Disable a user account:\n" " ipa user-disable tuser1\n" "\n" " Enable a user account:\n" " ipa user-enable tuser1\n" "\n" " Delete a user:\n" " ipa user-del tuser1\n" msgstr "" "\n" "КориÑтувачі\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñами кориÑтувачів. Ð’ÑÑ– кориÑтувачі Ñ” кориÑтувачами POSIX.\n" "\n" "У IPA передбачено підтримку широкого діапазону форматів імен\n" "кориÑтувачів, але вам Ñлід враховувати вÑÑ– обмеженнÑ, Ñкі накладаютьÑÑ\n" "вашим робочим Ñередовищем. Ðаприклад, імена, що починаютьÑÑ Ð· цифри, або\n" "занадто довгі імена можуть Ñпричинити проблеми у деÑких ÑиÑтемах UNIX.\n" "СкориÑтайтеÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ «ipa config-mod» Ð´Ð»Ñ Ð·Ð¼Ñ–Ð½Ð¸ формату імені\n" "кориÑтувача, Ñке дозволÑтиметьÑÑ Ñ–Ð½Ñтрументами IPA.\n" "\n" "Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу кориÑтувача лише заборонить отриманнÑ\n" "кориÑтувачами нових реєÑтраційних даних Kerberos. Ð’ÑÑ– вже отримані\n" "реєÑтраційні дані не втратÑть Ñвоєї чинноÑті.\n" "\n" "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñми не Ñ” завданнÑм цього модулÑ. Докладніші дані щодо\n" "ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñми можна отримати у відповідь на команду ipa help passwd\n" "\n" "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу виконуєтьÑÑ Ð¾ÐºÑ€ÐµÐ¼Ð¸Ð¼ оÑновним вузлом IPA.\n" "Ð”Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¾Ñновного вузла, на Ñкому було заблоковано запиÑ, можна\n" "ÑкориÑтатиÑÑ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð¾ÑŽ user-status. ÐдмініÑтратор має розблоковувати\n" "кориÑтувача Ñаме на цьому оÑновному вузлі.\n" "\n" "ПРИКЛÐДИ:\n" "\n" " Ð”Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ кориÑтувача:\n" " ipa user-add --first=Ivan --last=Ivanenko --password tuser1\n" "\n" " Пошук вÑÑ–Ñ… кориÑтувачів, чиї запиÑи міÑÑ‚Ñть Ñ€Ñдок «Ivan»:\n" " ipa user-find Ivan\n" "\n" " Пошук вÑÑ–Ñ… кориÑтувачів з іменем (не прізвищем) «Ivan»:\n" " ipa user-find --first=Ivan\n" "\n" " Ð’Ð¸Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача:\n" " ipa user-disable tuser1\n" "\n" " Ð’Ð¼Ð¸ÐºÐ°Ð½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача:\n" " ipa user-enable tuser1\n" "\n" " Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð¿Ð¸Ñу кориÑтувача:\n" " ipa user-del tuser1\n" msgid "Kerberos keys available" msgstr "ДоÑтупні ключі Kerberos" msgid "Server" msgstr "Сервер" msgid "Failed logins" msgstr "КількіÑть невдалих Ñпроб увійти" msgid "Last successful authentication" msgstr "ОÑтаннє уÑпішне розпізнаваннÑ" msgid "Last failed authentication" msgstr "ОÑтаннє невдале розпізнаваннÑ" msgid "Time now" msgstr "Поточний чаÑ" msgid "must be TRUE or FALSE" msgstr "має дорівнювати TRUE або FALSE" msgid "user" msgstr "кориÑтувач" msgid "users" msgstr "кориÑтувачі" msgid "User login" msgstr "КориÑтувач" msgid "First name" msgstr "Ім'Ñ" msgid "Last name" msgstr "Прізвище" msgid "Full name" msgstr "Повне ім’Ñ" msgid "Display name" msgstr "Екранне ім'Ñ" msgid "Initials" msgstr "Ініціали" msgid "Home directory" msgstr "Домашній каталог" msgid "GECOS" msgstr "GECOS" msgid "Login shell" msgstr "Оболонка входу" msgid "Kerberos principal" msgstr "РеєÑтраційний Ð·Ð°Ð¿Ð¸Ñ Kerberos" msgid "Email address" msgstr "ÐдреÑа ел. пошти" msgid "Prompt to set the user password" msgstr "ÐадіÑлати запит щодо вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача" msgid "Generate a random user password" msgstr "Створити випадковий пароль Ð´Ð»Ñ ÐºÐ¾Ñ€Ð¸Ñтувача" msgid "UID" msgstr "UID" msgid "User ID Number (system will assign one if not provided)" msgstr "" "Ідентифікаційний номер кориÑтувача (ÑиÑтема призначить його, Ñкщо не буде " "вказано)" msgid "Group ID Number" msgstr "Ід. номер групи" msgid "Street address" msgstr "Ð’ÑƒÐ»Ð¸Ñ†Ñ Ñ– будинок" msgid "City" msgstr "МіÑто" msgid "State/Province" msgstr "ОблаÑть/провінціÑ" msgid "ZIP" msgstr "ІндекÑ" msgid "Telephone Number" msgstr "Ðомер телефону" msgid "Mobile Telephone Number" msgstr "Ðомер мобільного телефону" msgid "Pager Number" msgstr "Ðомер пейджера" msgid "Fax Number" msgstr "Ðомер факÑу" msgid "Org. Unit" msgstr "Підрозділ" msgid "Job Title" msgstr "ПоÑада" msgid "Manager" msgstr "Керівник" msgid "Car License" msgstr "ВодійÑька ліцензіÑ" msgid "Account disabled" msgstr "Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾" #, python-format msgid "invalid e-mail format: %(email)s" msgstr "некоректний формат адреÑи електронної пошти: %(email)s" #, python-format msgid "manager %(manager)s not found" msgstr "ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ %(manager)s не знайдено" msgid "Add a new user." msgstr "Додати нового кориÑтувача." #, python-format msgid "Added user \"%(value)s\"" msgstr "Додано кориÑтувача «%(value)s»" msgid "Don't create user private group" msgstr "Ðе Ñтворювати закриту групу кориÑтувача" #, python-format msgid "can be at most %(len)d characters" msgstr "не повинне перевищувати %(len)d Ñимволів у довжину" msgid "Default group for new users is not POSIX" msgstr "Типовою групою Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… кориÑтувачів не Ñ” група POSIX" msgid "Delete a user." msgstr "Вилучити кориÑтувача." #, python-format msgid "Deleted user \"%(value)s\"" msgstr "Вилучено кориÑтувача «%(value)s»" msgid "Modify a user." msgstr "Змінити параметри кориÑтувача." #, python-format msgid "Modified user \"%(value)s\"" msgstr "Змінено кориÑтувача «%(value)s»" msgid "Search for users." msgstr "Шукати кориÑтувачів." msgid "Self" msgstr "Self" msgid "Display user record for current Kerberos principal" msgstr "" "Показати Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача Ð´Ð»Ñ Ð¿Ð¾Ñ‚Ð¾Ñ‡Ð½Ð¾Ð³Ð¾ реєÑтраційного запиÑу Kerberos" #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "вÑтановлено відповідніÑть %(count)d кориÑтувача" msgstr[1] "вÑтановлено відповідніÑть %(count)d кориÑтувачів" msgstr[2] "вÑтановлено відповідніÑть %(count)d кориÑтувачів" msgid "Display information about a user." msgstr "Показати дані щодо кориÑтувача." msgid "Disable a user account." msgstr "Вимкнути обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача." #, python-format msgid "Disabled user account \"%(value)s\"" msgstr "Вимкнено обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача «%(value)s»" msgid "Enable a user account." msgstr "Увімкнути обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача." #, python-format msgid "Enabled user account \"%(value)s\"" msgstr "Увімкнено обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача «%(value)s»" msgid "" "\n" " Unlock a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator." msgstr "" "\n" " Розблокувати обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача\n" "\n" " Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¼Ð¾Ð¶Ðµ бути заблоковано, Ñкщо відповідно до правил " "безпеки\n" " кориÑтувач перевищить Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð½Ð° кількіÑть Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¾Ð²Ð¸Ñ… " "паролів\n" " протÑгом певного чаÑу. Ð—Ð°Ð¿Ð¸Ñ Ð±Ð»Ð¾ÐºÑƒÑ”Ñ‚ÑŒÑÑ Ñ‚Ð¸Ð¼Ñ‡Ð°Ñово, його може бути\n" " розблоковано адмініÑтратором." #, python-format msgid "Unlocked account \"%(value)s\"" msgstr "Розблоковано обліковий Ð·Ð°Ð¿Ð¸Ñ Â«%(value)s»" msgid "" "\n" " Lockout status of a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator.\n" "\n" " This connects to each IPA master and displays the lockout status on\n" " each one.\n" "\n" " To determine whether an account is locked on a given server you need\n" " to compare the number of failed logins and the time of the last " "failure.\n" " For an account to be locked it must exceed the maxfail failures within\n" " the failinterval duration as specified in the password policy " "associated\n" " with the user.\n" "\n" " The failed login counter is modified only when a user attempts a log in\n" " so it is possible that an account may appear locked but the last failed\n" " login attempt is older than the lockouttime of the password policy. " "This\n" " means that the user may attempt a login again. " msgstr "" "\n" " Стан Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу кориÑтувача\n" "\n" " Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð¼Ð¾Ð¶Ðµ бути заблоковано, Ñкщо введено неправильний пароль\n" " забагато разів протÑгом певного проміжку чаÑу, Ñкий визначаєтьÑÑ " "правилами\n" " роботи з паролÑми. Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу Ñ” тимчаÑовим Ñтаном, " "його\n" " може бути розблоковано адмініÑтратором.\n" "\n" " Ð¦Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð° з’єднуєтьÑÑ Ð· кожним оÑновним вузлом IPA Ñ– показує Ñтан\n" " Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð° кожному з них.\n" "\n" " Щоб визначити, чи Ñлід блокувати обліковий Ð·Ð°Ð¿Ð¸Ñ Ð½Ð° певному Ñервері, " "Ñлід\n" " виконати порівнÑÐ½Ð½Ñ ÐºÑ–Ð»ÑŒÐºÐ¾Ñті помилкових Ñпроб входу та Ñ‡Ð°Ñ Ð¾Ñтанньої\n" " невдалої Ñпроби з еталонними значеннÑми. Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ´Ðµ " "заблоковано,\n" " Ñкщо буде перевищено кількіÑть maxfail помилкових Ñпроб протÑгом " "проміжку\n" " чаÑу failinterval. Відповідні Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°ÑŽÑ‚ÑŒÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°Ð¼Ð¸ обробки " "паролів,\n" " пов’Ñзаними з обліковим запиÑом кориÑтувача.\n" "\n" " Зміни до лічильника помилкових Ñпроб входу вноÑÑтьÑÑ, лише коли " "кориÑтувач\n" " виконує Ñпробу увійти, тому може ÑтатиÑÑ Ñ‚Ð°Ðº, що обліковий Ð·Ð°Ð¿Ð¸Ñ " "заблоковано,\n" " хоча чаÑ, що минув з оÑтанньої помилкової Ñпроби, перевищує Ñ‡Ð°Ñ " "блокуваннÑ\n" " (lockouttime), заданий правилам обробки паролів. Це означає, що " "кориÑтувач\n" " може увійти до ÑиÑтеми знову. " #, python-format msgid "%(host)s failed: %(error)s" msgstr "Помилка %(host)s: %(error)s" #, python-format msgid "%(host)s failed" msgstr "Помилка %(host)s" #, python-format msgid "Account disabled: %(disabled)s" msgstr "Обліковий Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¸Ð¼ÐºÐ½ÐµÐ½Ð¾: %(disabled)s" msgid "operation not defined" msgstr "дію не визначено" msgid "not allowed to perform this command" msgstr "виконувати цю команду заборонено" msgid "No such virtual command" msgstr "Такої віртуальної команди не передбачено" msgid "any of the configured servers" msgstr "будь-Ñкий з налаштованих Ñерверів" msgid "could not allocate unique new session_id" msgstr "" "не вдалоÑÑ Ð²Ñтановити унікальне нове Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ‚Ð¾Ñ€Ð° ÑеанÑу " "(session_id)" msgid "Filename is empty" msgstr "ÐŸÐ¾Ñ€Ð¾Ð¶Ð½Ñ Ð½Ð°Ð·Ð²Ð° файла" #, python-format msgid "Permission denied: %(file)s" msgstr "ДоÑтуп заборонено: %(file)s" msgid "empty DNS label" msgstr "Ð¿Ð¾Ñ€Ð¾Ð¶Ð½Ñ Ð¼Ñ–Ñ‚ÐºÐ° DNS" msgid "DNS label cannot be longer that 63 characters" msgstr "Довжина мітки DNS не повинна перевищувати 63 Ñимволи" #, python-format msgid "" "only letters, numbers,%(underscore)s and - are allowed. DNS label may not " "start or end with -" msgstr "" "можна викориÑтовувати лише літери, цифри, %(underscore)s Ñ– Ñимвол «-». " "Символ «-» не повинен бути першим або оÑтаннім Ñимволом мітки DNS." msgid "" "mail account may only include letters, numbers, -, _ and a dot. There may " "not be consecutive -, _ and . characters. Its parts may not start or end " "with - or _" msgstr "" "назва облікового запиÑу електронної пошти може ÑкладатиÑÑ Ð»Ð¸ÑˆÐµ з літер, " "цифр, Ñимволів «-», «_» Ñ– крапок. Ðе можна викориÑтовувати у назві " "поÑлідовноÑті з Ñимволів «-», «_» та «.». Його чаÑтини не повинні починатиÑÑ " "або закінчуватиÑÑ Ð½Ð° «-» або «_»." msgid "cannot be longer that 255 characters" msgstr "не може бути довшим за 255 Ñимволів" msgid "too many '@' characters" msgstr "занадто багато Ñимволів «@»" msgid "missing address domain" msgstr "не вказано домену адреÑи" msgid "missing mail account" msgstr "не вказано поштового облікового запиÑу" msgid "hostname contains empty label (consecutive dots)" msgstr "назва вузла міÑтить лише порожню мітку (поÑлідовні крапки)" msgid "not fully qualified" msgstr "вказано не повніÑтю" msgid "invalid SSH public key" msgstr "некоректний відкритий ключ SSH" msgid "options are not allowed" msgstr "не можна викориÑтовувати параметри" msgid "improperly formatted DER-encoded certificate" msgstr "неналежне Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñертифіката у кодуванні DER" #, python-format msgid "Issuer \"%(issuer)s\" does not match the expected issuer" msgstr "Ð—Ð°Ð¿Ð¸Ñ Ð²Ð¸Ð´Ð°Ð²Ñ†Ñ Â«%(issuer)s» не відповідає очікуваному значенню видавцÑ" #, python-format msgid "Retrieving CA cert chain failed: %s" msgstr "Спроба Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð»Ð°Ð½Ñ†ÑŽÐ¶ÐºÐ° Ñертифікації CA зазнала невдачі: %s" #, python-format msgid "request failed with HTTP status %d" msgstr "помилка запиту зі Ñтаном HTTP %d" #, python-format msgid "Retrieving CA status failed: %s" msgstr "" "Спроба Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… щодо Ñтану Ñлужби Ñертифікації зазнала невдачі: %s" #, python-format msgid "objectclass %s not found" msgstr "ÐºÐ»Ð°Ñ Ð¾Ð±â€™Ñ”ÐºÑ‚Ñ–Ð² %s не знайдено" msgid "" "\n" "Classes to manage trust joins using DCE-RPC calls\n" "\n" "The code in this module relies heavily on samba4-python package\n" "and Samba4 python bindings.\n" msgstr "" "\n" "КлаÑи Ð´Ð»Ñ ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€ÐµÐ½Ð¸Ð¼Ð¸ приєднаннÑми за допомогою викликів DCE-RPC\n" "\n" "Код цього Ð¼Ð¾Ð´ÑƒÐ»Ñ Ð¶Ð¾Ñ€Ñтко залежить від вміÑту пакунка samba4-python\n" "та обгорток Ð´Ð»Ñ Ð¼Ð¾Ð²Ð¸ Python у Samba4.\n" msgid "CIFS server denied your credentials" msgstr "Ваші реєÑтраційні дані відхилено Ñервером CIFS" msgid "communication with CIFS server was unsuccessful" msgstr "Ñпроба обмінÑтиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з Ñервером CIFS зазнала невдачі" msgid "AD domain controller" msgstr "Контролер домену AD" msgid "unsupported functional level" msgstr "непідтримуваний функціональний рівень" msgid "Cannot find specified domain or server name" msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ домену або Ñервера з вказаною назвою" msgid "At least the domain or IP address should be specified" msgstr "Слід вказати принаймні домен або IP-адреÑу" #, python-format msgid "" "CIFS server communication error: code \"%(num)s\",\n" " message \"%(message)s\" (both may be \"None\")" msgstr "" "Помилка обміну даними з Ñервером CIFS: код «%(num)s»,\n" "Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Â«%(message)s» (обидва Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¼Ð¾Ð¶ÑƒÑ‚ÑŒ бути «None»)" msgid "" "communication with trusted domains is allowed for Trusts administrator group " "members only" msgstr "" "обмін даними з довіреним доменом дозволено лише учаÑникам групи " "адмініÑÑ‚Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Trusts" msgid "no trusted domain is configured" msgstr "Ðе налаштовано жодного довіреного домену" msgid "domain is not configured" msgstr "домен не налаштовано" msgid "SID is not valid" msgstr "SID не Ñ” чинним" msgid "SID does not match exactlywith any trusted domain's SID" msgstr "SID не збігаєтьÑÑ Ñ‚Ð¾Ñ‡Ð½Ð¾ з будь-Ñким з SID довірених доменів" msgid "SID does not match any trusted domain" msgstr "SID не відповідає жодному з довірених доменів" msgid "Trust setup" msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð²Ñ–Ñ€Ð¸" msgid "Our domain is not configured" msgstr "Ðаш домен не налаштовано" msgid "No trusted domain is not configured" msgstr "Ðе налаштовано жодного довіреного домену" msgid "trusted domain object" msgstr "об’єкт довіреного домену" msgid "domain is not trusted" msgstr "домен не Ñ” довіреним" msgid "no trusted domain matched the specified flat name" msgstr "вказаній проÑтій назві не відповідає жоден довірений домен" msgid "trusted domain object not found" msgstr "об’єкт довіреного домену не знайдено" msgid "Ambiguous search, user domain was not specified" msgstr "Ðеоднозначні параметри пошуку: не вказано домену кориÑтувача" msgid "Trusted domain did not return a unique object" msgstr "Довіреним доменом не повернуто унікального об’єкта" msgid "Trusted domain did not return a valid SID for the object" msgstr "Довіреним доменом не повернуто коректного SID об’єкта" msgid "trusted domain user not found" msgstr "не знайдено кориÑтувача довіреного домену" #, python-format msgid "" "KDC for %(domain)s denied trust account for IPA domain with a message " "'%(message)s'" msgstr "" "KDC Ð´Ð»Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ %(domain)s відмовлено у довіреному обліковому запиÑів Ð´Ð»Ñ " "домену IPA з повідомленнÑм «%(message)s»" msgid "Cannot retrieve trusted domain GC list" msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ ÑпиÑок GC довіреного домену" msgid "CIFS credentials object" msgstr "Об’єкт реєÑтраційних даних CIFS" #, python-format msgid "CIFS server %(host)s denied your credentials" msgstr "Ваші реєÑтраційні дані відхилено Ñервером CIFS %(host)s" #, python-format msgid "Cannot establish LSA connection to %(host)s. Is CIFS server running?" msgstr "" "Ðе вдалоÑÑ Ð²Ñтановити LSA-Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· %(host)s. Чи запущено Ñервер CIFS?" #, python-format msgid "" "the IPA server and the remote domain cannot share the same NetBIOS name: %s" msgstr "" "Ñервер IPA Ñ– віддалений домен не можуть викориÑтовувати Ñпільно ту Ñаму " "назву NetBIOS: %s" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ð¼Ñ–Ð½ÑтиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з CMS (%s)" msgid "Unable to communicate with CMS" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ð¼Ñ–Ð½ÑтиÑÑ Ð´Ð°Ð½Ð¸Ð¼Ð¸ з CMS" msgid "find not supported on CAs upgraded from 9 to 10" msgstr "знайти непідтримувані у CA піÑÐ»Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð· 9 до 10" msgid "The hostname to register as" msgstr "Ðазва вузла Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації" msgid "The IPA realm" msgstr "ОблаÑть IPA" msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "Ðпаратна платформа вузла (наприклад, «Lenovo T61»)" msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "Операційна ÑиÑтема вузла Ñ– Ñ—Ñ— верÑÑ–Ñ (наприклад, «Fedora 9»)" #, python-format msgid "" "Insufficient 'write' privilege to the 'krbLastPwdChange' attribute of entry " "'%s'." msgstr "" "ÐедоÑтатні права доÑтупу «write» до атрибута «krbLastPwdChange» запиÑу «%s»." msgid "Request must be a dict" msgstr "Запит має належати до типу Ñловника (dict)" msgid "Request is missing \"method\"" msgstr "У запиті не вказано метод (\"method\")" msgid "Request is missing \"params\"" msgstr "У запиті не вказано параметри (\"params\")" msgid "params must be a list" msgstr "params має бути ÑпиÑком (list)" msgid "params must contain [args, options]" msgstr "params має міÑтити запиÑи [аргументи, параметри]" msgid "params[0] (aka args) must be a list" msgstr "params[0] (або аргументи) має бути ÑпиÑком (list)" msgid "params[1] (aka options) must be a dict" msgstr "params[1] (або параметри) має належати до типу Ñловника (dict)" #, c-format msgid "cannot open configuration file %s\n" msgstr "не вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ файл налаштувань %s\n" #, c-format msgid "cannot stat() configuration file %s\n" msgstr "не вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ функцією stat() файл Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ %s\n" #, c-format msgid "out of memory\n" msgstr "не виÑтачає пам'Ñті\n" #, c-format msgid "read error\n" msgstr "помилка читаннÑ\n" #, c-format msgid "Kerberos context initialization failed: %1$s (%2$d)\n" msgstr "Ðевдала Ñпроба ініціалізації контекÑту Kerberos: %1$s (%2$d)\n" #, c-format msgid "Unable to parse principal: %1$s (%2$d)\n" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ реєÑтраційний запиÑ: %1$s (%2$d)\n" #, c-format msgid "No keys accepted by KDC\n" msgstr "Жоден з ключів не прийнÑто KDC\n" #, c-format msgid "Out of memory \n" msgstr "Ðе виÑтачає пам'Ñті \n" #, c-format msgid "Out of Memory!\n" msgstr "Ðе виÑтачає пам'Ñті!\n" #, c-format msgid "Failed to create control!\n" msgstr "Ðе вдалоÑÑ Ñтворити керуваннÑ!\n" #, c-format msgid "Unable to initialize ldap library!\n" msgstr "Ðе вдалоÑÑ Ñ–Ð½Ñ–Ñ†Ñ–Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ бібліотеку ldap!\n" #, c-format msgid "Unable to set LDAP_OPT_X_SASL_NOCANON\n" msgstr "Ðе вдалоÑÑ Ð²Ñтановити LDAP_OPT_X_SASL_NOCANON\n" #, c-format msgid "Unable to set ldap options!\n" msgstr "Ðе вдалоÑÑ Ð²Ñтановити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ–Ð² ldap!\n" #, c-format msgid "Simple bind failed\n" msgstr "Ðевдала Ñпроба проÑтого прив’ÑзуваннÑ\n" #, c-format msgid "Operation failed! %s\n" msgstr "Ðевдала Ñпроба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð´Ñ–Ñ—! %s\n" #, c-format msgid "Missing reply control!\n" msgstr "Ðемає ÐºÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð´ÑŽ!\n" #, c-format msgid "ber_init() failed, Invalid control ?!\n" msgstr "Спроба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ber_init() зазнала невдачі. Ðекоректне керуваннÑ?!\n" #, c-format msgid "ber_scanf() failed, unable to find kvno ?!\n" msgstr "помилка ber_scanf(), не вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ kvno?!\n" #, c-format msgid "Failed to retrieve encryption type type #%d\n" msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ дані щодо типу ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ â„–%d\n" #, c-format msgid "Failed to retrieve encryption type %1$s (#%2$d)\n" msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ дані щодо типу ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ %1$s (â„–%2$d)\n" #, c-format msgid "Failed to retrieve any keys" msgstr "Ðе вдалоÑÑ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ñ‚Ð¸ жодного ключа" msgid "New Principal Password" msgstr "Ðовий пароль реєÑтраційного запиÑу" msgid "Verify Principal Password" msgstr "Перевірка Ð¿Ð°Ñ€Ð¾Ð»Ñ Ñ€ÐµÑ”Ñтраційного запиÑу" msgid "Print as little as possible" msgstr "Виводити мінімум даних" msgid "Output only on errors" msgstr "Виводити лише Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилки" msgid "Contact this specific KDC Server" msgstr "Ð’Ñтановити зв’Ñзок з вказаним Ñервером KDC" msgid "Server Name" msgstr "Ðазва Ñервера" msgid "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)" msgstr "" "РеєÑтраційний запиÑ, Ð´Ð»Ñ Ñкого Ñлід отримати таблицю ключів (приклад: ftp/" "ftp.example.com@EXAMPLE.COM)" msgid "Kerberos Service Principal Name" msgstr "Ðазва реєÑтраційного запиÑу Ñлужби Kerberos" msgid "File were to store the keytab information" msgstr "Файл, у Ñкому зберігатимутьÑÑ Ð´Ð°Ð½Ñ– таблиці ключів" msgid "Keytab File Name" msgstr "Ðазва файла таблиці ключів" msgid "Encryption types to request" msgstr "Типи шифруваннÑ, запит щодо Ñких Ñлід надÑилати" msgid "Comma separated encryption types list" msgstr "СпиÑок типів шифруваннÑ, відокремлених комами" msgid "Show the list of permitted encryption types and exit" msgstr "Показати ÑпиÑок дозволених типів ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– завершити роботу" msgid "Permitted Encryption Types" msgstr "Дозволені типи шифруваннÑ" msgid "Asks for a non-random password to use for the principal" msgstr "" "Запитати невипадковий пароль, Ñкий Ñлід викориÑтати Ð´Ð»Ñ Ñ€ÐµÑ”Ñтраційного запиÑу" msgid "LDAP DN" msgstr "DN LDAP" msgid "DN to bind as if not using kerberos" msgstr "" "DN, до Ñкого Ñлід виконати прив’Ñзку, Ñкщо не викориÑтовуєтьÑÑ kerberos" msgid "LDAP password" msgstr "Пароль LDAP" msgid "password to use if not using kerberos" msgstr "пароль, Ñкий Ñлід викориÑтати, Ñкщо не викориÑтовуєтьÑÑ kerberos" #, c-format msgid "Kerberos context initialization failed\n" msgstr "Ðевдала Ñпроба ініціалізації контекÑту Kerberos\n" #, c-format msgid "No system preferred enctypes ?!\n" msgstr "Ðемає оÑновних ÑиÑтемних типів шифруваннÑ?!\n" #, c-format msgid "Supported encryption types:\n" msgstr "Підтримувані типи шифруваннÑ:\n" #, c-format msgid "Warning: failed to convert type (#%d)\n" msgstr "ПопередженнÑ: не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ Ð¿ÐµÑ€ÐµÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‚Ð¸Ð¿Ñƒ (â„–%d)\n" #, c-format msgid "Bind password required when using a bind DN.\n" msgstr "У разі викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð²â€™Ñзки DN Ñлід вказати пароль прив’Ñзки.\n" #, c-format msgid "" "Warning: salt types are not honored with randomized passwords (see opt. -P)\n" msgstr "" "ПопередженнÑ: Ð´Ð»Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÐ¾Ð²Ð¸Ñ… паролів типи Ñолі (salt) не мають Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ " "(див. параметр -P)\n" #, c-format msgid "Invalid Service Principal Name\n" msgstr "Ðекоректна назва реєÑтраційного запиÑу Ñлужби\n" #, c-format msgid "Kerberos Credential Cache not found. Do you have a Kerberos Ticket?\n" msgstr "" "Ðе знайдено кешу реєÑтраційних даних Kerberos. Чи Ñ” у Ð²Ð°Ñ ÐºÐ²Ð¸Ñ‚Ð¾Ðº Kerberos?\n" #, c-format msgid "" "Kerberos User Principal not found. Do you have a valid Credential Cache?\n" msgstr "" "Ðе знайдено реєÑтраційного запиÑу кориÑтувача Kerberos. Ви маєте ви " "коректний кеш реєÑтраційних даних?\n" #, c-format msgid "Failed to open Keytab\n" msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ таблицю ключів\n" #, c-format msgid "Failed to create key material\n" msgstr "Ðе вдалоÑÑ Ñтворити вихідні дані Ð´Ð»Ñ ÐºÐ»ÑŽÑ‡Ð°\n" #, c-format msgid "Failed to add key to the keytab\n" msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ ключ до таблиці ключів\n" #, c-format msgid "Failed to close the keytab\n" msgstr "Ðе вдалоÑÑ Ð·Ð°ÐºÑ€Ð¸Ñ‚Ð¸ таблицю ключів\n" #, c-format msgid "Keytab successfully retrieved and stored in: %s\n" msgstr "Таблицю ключів уÑпішно отримати Ñ– збережено до: %s\n" #, c-format msgid "No permission to join this host to the IPA domain.\n" msgstr "Ðемає дозволу на Ð´Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ вузла до домену IPA.\n" #, c-format msgid "No write permissions on keytab file '%s'\n" msgstr "Ðемає дозволу на Ð·Ð°Ð¿Ð¸Ñ Ð´Ð¾ файла таблиці ключів «%s»\n" #, c-format msgid "access() on %1$s failed: errno = %2$d\n" msgstr "Ðевдала Ñпроба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ access() Ð´Ð»Ñ %1$s: номер помилки = %2$d\n" #, c-format msgid "Out of memory!" msgstr "Ðе виÑтачає пам'Ñті!" #, c-format msgid "Unable to initialize connection to ldap server: %s" msgstr "Ðе вдалоÑÑ Ñ–Ð½Ñ–Ñ†Ñ–Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ð· Ñервером LDAP: %s" #, c-format msgid "Unable to enable SSL in LDAP\n" msgstr "Ðе вдалоÑÑ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÑƒÑ‚Ð¸ SSL у LDAP\n" #, c-format msgid "Unable to set LDAP version\n" msgstr "Ðе вдалоÑÑ Ð²Ñтановити верÑÑ–ÑŽ LDAP\n" #, c-format msgid "Bind failed: %s\n" msgstr "Ðевдала Ñпроба прив’Ñзки: %s\n" #, c-format msgid "Search for %1$s on rootdse failed with error %2$d\n" msgstr "" "Спроба пошуку %1$s у rootdse завершилаÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ з повідомленнÑм про помилку " "%2$d\n" #, c-format msgid "No values for %s" msgstr "Ðемає значень %s" #, c-format msgid "Search for IPA namingContext failed with error %d\n" msgstr "Спроба пошуку namingContext IPA завершилаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ¾ÑŽ %d\n" #, c-format msgid "IPA namingContext not found\n" msgstr "namingContext IPA не знайдено\n" #, c-format msgid "Out of memory!\n" msgstr "Ðе виÑтачає пам'Ñті!\n" #, c-format msgid "Search for ipaCertificateSubjectBase failed with error %d" msgstr "" "Спроба пошуку ipaCertificateSubjectBase завершилаÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾ з Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ " "про помилку %d" #, c-format msgid "Unable to determine root DN of %s\n" msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ кореневий DN %s\n" #, c-format msgid "Incorrect password.\n" msgstr "Ðекоректний пароль.\n" #, c-format msgid "Unable to determine certificate subject of %s\n" msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñертифіката %s\n" #, c-format msgid "Enrollment failed. %s\n" msgstr "Помилка реєÑтруваннÑ. %s\n" #, c-format msgid "principal not found in XML-RPC response\n" msgstr "реєÑтраційного запиÑу не знайдено у XML-RPC відповіді\n" #, c-format msgid "Host is already joined.\n" msgstr "Вузол вже приєднано.\n" #, c-format msgid "Unable to determine IPA server from %s\n" msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð·Ð½Ð°Ñ‡Ð¸Ñ‚Ð¸ Ñервер IPA з %s\n" #, c-format msgid "The hostname must be fully-qualified: %s\n" msgstr "Ðазву вузла Ñлід вказувати повніÑтю: %s\n" #, c-format msgid "Unable to join host: Kerberos context initialization failed\n" msgstr "" "Ðе вдалоÑÑ Ð´Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ вузол: невдала Ñпроба ініціалізації контекÑту Kerberos\n" #, c-format msgid "Error resolving keytab: %s.\n" msgstr "Помилка при визначенні Ð°Ð´Ñ€ÐµÑ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– ключів: %s.\n" #, c-format msgid "Error getting default Kerberos realm: %s.\n" msgstr "Помилка під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚Ð¸Ð¿Ð¾Ð²Ð¾Ñ— облаÑті дії Kerberos: %s.\n" #, c-format msgid "Error parsing \"%1$s\": %2$s.\n" msgstr "Помилка під Ñ‡Ð°Ñ Ð¾Ð±Ñ€Ð¾Ð±ÐºÐ¸ «%1$s»: %2$s.\n" #, c-format msgid "Error obtaining initial credentials: %s.\n" msgstr "Помилка під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… реєÑтраційних даних: %s.\n" #, c-format msgid "Unable to generate Kerberos Credential Cache\n" msgstr "Ðе вдалоÑÑ Ñтворити кеш реєÑтраційних даних Kerberos\n" #, c-format msgid "Error storing creds in credential cache: %s.\n" msgstr "Помилка під Ñ‡Ð°Ñ Ñпроби Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€ÐµÑ”Ñтраційних даних у кеші: %s.\n" #, c-format msgid "Unenrollment successful.\n" msgstr "УÑпішне ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑ”Ñтрації.\n" #, c-format msgid "Unenrollment failed.\n" msgstr "Спроба ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑ”Ñтрації зазнала невдачі.\n" #, c-format msgid "result not found in XML-RPC response\n" msgstr "у відповіді XML-RPC не знайдено результату\n" #, c-format msgid "The hostname must not be: %s\n" msgstr "Ðазва вузла не повинна бути такою: %s\n" #, c-format msgid "Unable to join host: Kerberos Credential Cache not found\n" msgstr "" "Ðе вдалоÑÑ Ð´Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ вузол: не знайдено кешу реєÑтраційних даних Kerberos\n" #, c-format msgid "" "Unable to join host: Kerberos User Principal not found and host password not " "provided.\n" msgstr "" "Ðе вдалоÑÑ Ð´Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ вузол: не знайдено реєÑтраційного запиÑу кориÑтувача " "Kerberos Ñ– не вказано Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð²ÑƒÐ·Ð»Ð°.\n" #, c-format msgid "fork() failed\n" msgstr "невдала Ñпроба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ fork()\n" #, c-format msgid "ipa-getkeytab not found\n" msgstr "Ðе знайдено ipa-getkeytab\n" #, c-format msgid "ipa-getkeytab has bad permissions?\n" msgstr "Помилкові права доÑтупу до ipa-getkeytab?\n" #, c-format msgid "executing ipa-getkeytab failed, errno %d\n" msgstr "Ñпроба Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ ipa-getkeytab зазнала невдачі, номер помилки %d\n" #, c-format msgid "child exited with %d\n" msgstr "дочірній Ð¿Ñ€Ð¾Ñ†ÐµÑ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð² роботу з повідомленнÑм %d\n" #, c-format msgid "Certificate subject base is: %s\n" msgstr "Базовий об’єкт Ñертифікації: %s\n" msgid "Print the raw XML-RPC output in GSSAPI mode" msgstr "ВивеÑти дані XML-RPC без обробки у режимі GSSAPI" msgid "Quiet mode. Only errors are displayed." msgstr "«Мовчазний» режим. Буде показано лише Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ помилки." msgid "Unenroll this host from IPA server" msgstr "СкаÑувати реєÑтрацію цього вузла на Ñервері IPA" msgid "Hostname of this server" msgstr "Ðазва вузла цього Ñервера" msgid "hostname" msgstr "назва вузла" msgid "IPA Server to use" msgstr "Сервер IPA, Ñкий Ñлід викориÑтовувати" msgid "Specifies where to store keytab information." msgstr "Визначає, де Ñлід зберігати дані таблиці ключів." msgid "filename" msgstr "назва файла" msgid "Force the host join. Rejoin even if already joined." msgstr "" "Долучити вузол у примуÑовому режимі. Повторне Ð´Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑƒÐ²Ð°Ñ‚Ð¸Ð¼ÐµÑ‚ÑŒÑÑ, " "навіть Ñкщо вузол вже долучено." msgid "LDAP password (if not using Kerberos)" msgstr "Пароль LDAP (Ñкщо не викориÑтовуєтьÑÑ Kerberos)" msgid "password" msgstr "пароль" msgid "LDAP basedn" msgstr "Базовий DN LDAP" msgid "basedn" msgstr "Базовий DN" #, c-format msgid "Unable to parse principal name\n" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ назву реєÑтраційного запиÑу\n" #, c-format msgid "krb5_parse_name %1$d: %2$s\n" msgstr "krb5_parse_name %1$d: %2$s\n" #, c-format msgid "Removing principal %s\n" msgstr "Ð’Ð¸Ð»ÑƒÑ‡ÐµÐ½Ð½Ñ Ñ€ÐµÑ”Ñтраційного запиÑу %s\n" #, c-format msgid "Failed to open keytab\n" msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ таблицю ключів\n" #, c-format msgid "principal not found\n" msgstr "реєÑтраційного запиÑу не знайдено\n" #, c-format msgid "krb5_kt_get_entry %1$d: %2$s\n" msgstr "krb5_kt_get_entry %1$d: %2$s\n" #, c-format msgid "Unable to remove entry\n" msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð»ÑƒÑ‡Ð¸Ñ‚Ð¸ запиÑ\n" #, c-format msgid "kvno %d\n" msgstr "kvno %d\n" #, c-format msgid "krb5_kt_remove_entry %1$d: %2$s\n" msgstr "krb5_kt_remove_entry %1$d: %2$s\n" #, c-format msgid "Unable to parse principal\n" msgstr "Ðе вдалоÑÑ Ð¾Ð±Ñ€Ð¾Ð±Ð¸Ñ‚Ð¸ реєÑтраційний запиÑ\n" #, c-format msgid "krb5_unparse_name %1$d: %2$s\n" msgstr "krb5_unparse_name %1$d: %2$s\n" #, c-format msgid "realm not found\n" msgstr "облаÑть не знайдено\n" msgid "Print debugging information" msgstr "ВивеÑти діагноÑтичні дані" msgid "Debugging output" msgstr "ДіагноÑтична інформаціÑ" msgid "Remove all principals in this realm" msgstr "Вилучити вÑÑ– реєÑтраційні запиÑи у цій облаÑті" #, c-format msgid "Failed to open keytab '%1$s': %2$s\n" msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ таблицю ключів «%1$s»: %2$s\n" #, c-format msgid "Closing keytab failed\n" msgstr "Спроба Ð·Ð°ÐºÑ€Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– ключів зазнала невдачі\n" #, c-format msgid "krb5_kt_close %1$d: %2$s\n" msgstr "krb5_kt_close %1$d: %2$s\n" msgid "Out of memory!?\n" msgstr "Ðе виÑтачає пам'Ñті!?\n" msgid "Out of memory\n" msgstr "Ðе виÑтачає пам'Ñті\n" msgid "Warning unrecognized encryption type.\n" msgstr "ПопередженнÑ: невідомий тип шифруваннÑ.\n" msgid "Warning unrecognized salt type.\n" msgstr "ПопередженнÑ: невідомий тип Ñолі (salt).\n" msgid "Enctype comparison failed!\n" msgstr "Спроба порівнÑÐ½Ð½Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½ÑŒ типу ÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð·Ð½Ð°Ð»Ð° невдачі!\n" msgid "Failed to create random key!\n" msgstr "Ðе вдалоÑÑ Ñтворити випадковий ключ!\n" msgid "Failed to create key!\n" msgstr "Ðе вдалоÑÑ Ñтворити ключ!\n" msgid "Bad or unsupported salt type.\n" msgstr "Помилковий або непідтримуваний тип Ñолі (salt).\n" freeipa-3.3.4/install/po/id.po0000664000175000017500000001665312271663206015542 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # jdennis , 2011 # Teguh Dwicaksana , 2010 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Indonesian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: id\n" "Plural-Forms: nplurals=1; plural=0;\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Masukkan %(label)s lagi untuk verifikasi:" #, c-format msgid "Passwords do not match!" msgstr "Kata sandi tidak cocok!" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "kesalahan %(code)d tidak dikenal dari %(server)s: %(error)s" msgid "an internal error has occurred" msgstr "terjadi kesalahan internal" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "Permintaan JSON-RPC tidak valid: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Kesalahan kerberos: %(major)s/%(minor)s" msgid "Ticket expired" msgstr "Tiket sudah kadaluarsa" #, python-format msgid "Insufficient access: %(info)s" msgstr "Hak akses tidak mencukupi: %(info)s" msgid "Passwords do not match" msgstr "Kata sandi tidak cocok" msgid "Command not implemented" msgstr "Perintah tidak diimplementasikan" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Entri ini sudah ada" msgid "You must enroll a host in order to create a host service" msgstr "Anda harus mendaftarkan sebuah host untuk membuat layanan host" msgid "This command requires root access" msgstr "Perintah ini memerlukan akses root" msgid "This is already a posix group" msgstr "Ini sudah merupakan grup posix" msgid "A group may not be a member of itself" msgstr "Sebuah grup tidak mungkin menjadi anggota grup itu sendiri" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Penguraian Base64 gagal: %(reason)s" msgid "change collided with another change" msgstr "perubahan bertabrakan dengan perubahan lain" msgid "no modifications to be performed" msgstr "tidak ada modifikasi yang harus dilakukan" msgid "limits exceeded for this query" msgstr "query ini telah melampaui batas" #, python-format msgid "%(info)s" msgstr "%(info)s" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "Operasi sertifikat tidak dapat diselesaikan: %(error)s" msgid "Results are truncated, try a more specific search" msgstr "Hasil yang terpotong, coba cari dengan lebih spesifik" msgid "incorrect type" msgstr "type salah" msgid "Only one value is allowed" msgstr "Hanya satu nilai yang diperbolehkan" msgid "must be True or False" msgstr "harus True atau False" msgid "must be an integer" msgstr "harus merupakan bilangan bulat" #, python-format msgid "must be at least %(minvalue)d" msgstr "setidaknya harus %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "nilai maksimum yang diperbolehkan %(maxvalue)d" msgid "must be a decimal number" msgstr "harus merupakan angka desimal" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "harus cocok dengan pola \"%(pattern)s\"" msgid "must be binary data" msgstr "harus merupakan data binari" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "panjang minimum yang diperbolehkan %(minlength)d byte" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "panjang maksimum yang diperbolehkan %(maxlength)d byte" #, python-format msgid "must be exactly %(length)d bytes" msgstr "harus tepat %(length)d byte" msgid "must be Unicode text" msgstr "harus teks Unicode" #, python-format msgid "must be at least %(minlength)d characters" msgstr "setidaknya minimum harus %(minlength)d karakter" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "panjang maksimum yang diperbolehkan %(maxlength)d karakter" #, python-format msgid "must be exactly %(length)d characters" msgstr "harus tepat %(length)d karakter" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "setidaknya diperlukan salah satu dari: type, filter, subtree, targetgroup, " "attrs atau memberof" #, python-format msgid "Group '%s' does not exist" msgstr "Grup '%s' tidak ada" #, python-format msgid "ACI with name \"%s\" not found" msgstr "ACI dengan nama \"%s\" tidak ditemukan" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "ACI \"%(value)s\" telah dibuat" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "ACI \"%(value)s\" telah dihapus" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "ACI \"%(value)s\" telah dimodifikasi" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "%(count)d ACI sesuai" msgid "Failure decoding Certificate Signing Request" msgstr "Gagal mengurai Permintaan Penandatanganan Sertifikat" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "Gagal mengurai Permintaan Penandatanganan Sertifikat: %s" #, python-format msgid "Added group \"%(value)s\"" msgstr "Grup \"%(value)s\" telah ditambahkan" #, python-format msgid "Deleted group \"%(value)s\"" msgstr "Grup \"%(value)s\" telah dihapus" #, python-format msgid "Modified group \"%(value)s\"" msgstr "Grup \"%(value)s\" telah dimodifikasi" #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "%(count)d grup sesuai" #, python-format msgid "Added host \"%(value)s\"" msgstr "Host \"%(value)s\" telah ditambahkan" #, python-format msgid "Deleted host \"%(value)s\"" msgstr "Host \"%(value)s\" telah dihapus" #, python-format msgid "Modified host \"%(value)s\"" msgstr "Host \"%(value)s\" telah dimodifikasi" #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "%(count)d host sesuai" #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "hostgroup \"%(value)s\" telah ditambahkan" #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "hostgroup \"%(value)s\" telah dihapus" #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "hostgroup \"%(value)s\" telah dimodifikasi" #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "%(count)d hostgroup sesuai" #, python-format msgid "%(count)d variables" msgstr "%(count)d variabel" #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "%(count)d pengaya telah dimuat" msgid "priority cannot be set on global policy" msgstr "prioritas tidak dapat ditetapkan pada kebijakan global" #, python-format msgid "Added user \"%(value)s\"" msgstr "Pengguna \"%(value)s\" telah ditambahkan" #, python-format msgid "Deleted user \"%(value)s\"" msgstr "Pengguna \"%(value)s\" telah dihapus" #, python-format msgid "Modified user \"%(value)s\"" msgstr "Pengguna \"%(value)s\" telah dimodifikasi" #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "%(count)d pengguna sesuai" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "Tidak dapat berkomunikasi dengan CMS (%s)" freeipa-3.3.4/install/po/pl.po0000664000175000017500000011657512271663206015565 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # jdennis , 2011 # mmarzantowicz , 2013 # Piotr DrÄ…g , 2010,2013 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "ProszÄ™ podać %(label)s ponownie, aby sprawdzić: " #, c-format msgid "Passwords do not match!" msgstr "HasÅ‚a siÄ™ nie zgadzajÄ…." #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "nieznany błąd %(code)d z %(server)s: %(error)s" msgid "an internal error has occurred" msgstr "wystÄ…piÅ‚ wewnÄ™trzny błąd" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "NieprawidÅ‚owe żądanie JSON-RPC: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Błąd Kerberosa: %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "nie otrzymano danych uwierzytelniajÄ…cych Kerberosa" msgid "No credentials cache found" msgstr "Nie odnaleziono pamiÄ™ci podrÄ™cznej danych uwierzytelniajÄ…cych" msgid "Ticket expired" msgstr "ZgÅ‚oszenie wygasÅ‚o" msgid "Credentials cache permissions incorrect" msgstr "" "Uprawnienia pamiÄ™ci podrÄ™cznej danych uwierzytelniajÄ…cych sÄ… niepoprawne" msgid "Bad format in credentials cache" msgstr "Błędny format w pamiÄ™ci podrÄ™cznej danych uwierzytelniajÄ…cych" msgid "Cannot resolve KDC for requested realm" msgstr "Nie można rozwiÄ…zać KDC dla żądanego obszaru" #, python-format msgid "Insufficient access: %(info)s" msgstr "NiewystarczajÄ…cy dostÄ™p: %(info)s" msgid "Passwords do not match" msgstr "HasÅ‚a siÄ™ nie zgadzajÄ…" msgid "Command not implemented" msgstr "Polecenie nie jest zaimplementowane" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Ten wpis już istnieje" msgid "You must enroll a host in order to create a host service" msgstr "Należy zapisać siÄ™ do komputera, aby utworzyć jego usÅ‚ugÄ™" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "Naczelnik usÅ‚ugi nie jest w formacie: usÅ‚uga/w peÅ‚ni kwalifikowana nazwa " "komputera: %(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "Obszar naczelnika nie zgadza siÄ™ z obszarem dla tego serwera IPA" msgid "This command requires root access" msgstr "Te polecenie wymaga dostÄ™pu roota" msgid "This is already a posix group" msgstr "To jest już grupa POSIX" msgid "A group may not be a member of itself" msgstr "Grupa nie może być wÅ‚asnym elementem" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Dekodowanie base64 nie powiodÅ‚o siÄ™: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "Nie można dodać grupy jako elementu jej samej" msgid "The default users group cannot be removed" msgstr "Nie można usunąć domyÅ›lnej grupy użytkowników" msgid "Host does not have corresponding DNS A record" msgstr "Komputer nie posiada pasujÄ…cego wpisu DNS A" msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "" "Usuwanie zarzÄ…dzanej grupy nie jest dozwolone. Musi zostać najpierw " "odłączona." #, python-format msgid "%(attr)s does not contain '%(value)s'" msgstr "%(attr)s nie zawiera \"%(value)s\"" msgid "change collided with another change" msgstr "zmiana koliduje z innÄ… zmianÄ…" msgid "no modifications to be performed" msgstr "żadne modyfikacje nie zostanÄ… wykonane" msgid "limits exceeded for this query" msgstr "przekroczono ograniczenia dla tego zapytania" #, python-format msgid "%(info)s" msgstr "%(info)s" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "Nie można ukoÅ„czyć dziaÅ‚ania na certyfikacie: %(error)s" #, python-format msgid "Certificate format error: %(error)s" msgstr "Błąd formatu certyfikatu: %(error)s" msgid "Results are truncated, try a more specific search" msgstr "" "Wyniki zostaÅ‚y obciÄ™te, proszÄ™ spróbować bardziej konkretnego wyszukiwania" msgid "Forward to server instead of running locally" msgstr "Przekazanie do serwera zamiast uruchamiania lokalnie" msgid "A dictionary representing an LDAP entry" msgstr "SÅ‚ownik reprezentujÄ…cy wpis LDAP" msgid "A list of LDAP entries" msgstr "Lista wpisów LDAP" msgid "All commands should at least have a result" msgstr "Wszystkie polecenia powinny powiadać przynajmniej wynik" msgid "incorrect type" msgstr "niepoprawny typ" msgid "Only one value is allowed" msgstr "Dozwolona jest tylko jedna wartość" msgid "must be True or False" msgstr "musi być prawdÄ… lub faÅ‚szem" msgid "must be an integer" msgstr "musi być liczba caÅ‚kowitÄ…" #, python-format msgid "must be at least %(minvalue)d" msgstr "musi wynosić co najmniej %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "może wynosić co najwyżej %(maxvalue)d" msgid "must be a decimal number" msgstr "musi być liczbÄ… dziesiÄ™tnÄ…" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "musi pasować do wzorca \"%(pattern)s\"" msgid "must be binary data" msgstr "musi być danymi binarnymi" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "musi wynosić co najmniej %(minlength)d bajtów" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "może wynosić co najwyżej %(maxlength)d bajtów" #, python-format msgid "must be exactly %(length)d bytes" msgstr "musi wynosić dokÅ‚adnie %(length)d bajtów" msgid "must be Unicode text" msgstr "musi być tekstem w unikodzie" #, python-format msgid "must be at least %(minlength)d characters" msgstr "musi wynosić co najmniej %(minlength)d znaków" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "może wynosić co najwyżej %(maxlength)d znaków" #, python-format msgid "must be exactly %(length)d characters" msgstr "musi wynosić dokÅ‚adnie %(length)d znaków" msgid "A list of ACI values" msgstr "Lista wartoÅ›ci ACI" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "" "wartoÅ›ci \"type\", \"filter\", \"subtree\" i \"targetgroup\" sÄ… wzajemnie " "wyłączne" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "co najmniej jedna z wartoÅ›ci: \"type\", \"filter\", \"subtree\", " "\"targetgroup\", \"attrs\" lub \"memberof\" jest wymagana" #, python-format msgid "Group '%s' does not exist" msgstr "Grupa \"%s\" nie istnieje" #, python-format msgid "Syntax Error: %(error)s" msgstr "Błąd skÅ‚adni: %(error)s" #, python-format msgid "ACI with name \"%s\" not found" msgstr "Nie odnaleziono ACI o nazwie \"%s\"" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "Nazwa ACI" msgid "User group" msgstr "Grupa użytkowników" msgid "User group ACI grants access to" msgstr "Grupa użytkowników, do której ACI zapewnia dostÄ™p" msgid "Permissions" msgstr "Uprawnienia" msgid "Attributes" msgstr "Atrybuty" msgid "Type" msgstr "Typ" msgid "Member of" msgstr "Element" msgid "Member of a group" msgstr "Element grupy" msgid "Filter" msgstr "Filtr" msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "Dozwolony filtr LDAP (np. ou=Inżynieria)" msgid "Subtree" msgstr "Poddrzewo" msgid "Subtree to apply ACI to" msgstr "Poddrzewo, do którego zastosować ACI" msgid "Target group" msgstr "Grupa docelowa" msgid "Group to apply ACI to" msgstr "Grupa, do której zastosować ACI" msgid "Target your own entry (self)" msgstr "Cel wÅ‚asnego wpisu (\"self\")" msgid "Apply ACI to your own entry (self)" msgstr "Zastosowanie ACI do wÅ‚asnego wpisu (\"self\")" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "Utworzono ACI \"%(value)s\"" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "UsuniÄ™to ACI \"%(value)s\"" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "Zmodyfikowano ACI \"%(value)s\"" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "Pasuje %(count)d ACI" msgstr[1] "PasujÄ… %(count)d ACI" msgstr[2] "Pasuje %(count)d ACI" msgid "Description" msgstr "Opis" #, python-format msgid "Group: %s not found!" msgstr "Grupa: nie odnaleziono %s." msgid "Location" msgstr "PoÅ‚ożenie" #, python-format msgid "File %(file)s not found" msgstr "Nie odnaleziono pliku %(file)s" msgid "Map" msgstr "Mapa" msgid "Automount Maps" msgstr "Automatyczne montowanie map" msgid "Key" msgstr "Klucz" msgid "Mount information" msgstr "Informacje o montowaniu" msgid "description" msgstr "opis" msgid "Automount Keys" msgstr "Automatyczne montowanie kluczy" msgid "Mount point" msgstr "Punkt montowania" msgid "Parent map" msgstr "Mapa nadrzÄ™dna" msgid "Password" msgstr "HasÅ‚o" msgid "Failed members" msgstr "Elementy, które siÄ™ nie powiodÅ‚y" msgid "Member users" msgstr "Elementy użytkowników" msgid "Member groups" msgstr "Elementy grupy" msgid "Member of groups" msgstr "CzÅ‚onek grup" msgid "Member hosts" msgstr "Element komputerów" msgid "Member host-groups" msgstr "Element grupy komputerów" msgid "Member of host-groups" msgstr "Element grupy komputerów" msgid "Roles" msgstr "Role" msgid "Sudo Command Groups" msgstr "Grupy polecenia sudo" msgid "Member services" msgstr "UsÅ‚ugi elementów" msgid "Member service groups" msgstr "Grupy usÅ‚ugi elementów" msgid "External host" msgstr "ZewnÄ™trzny komputer" #, python-format msgid "container entry (%(container)s) not found" msgstr "nie odnaleziono wpisu kontenera (%(container)s)" #, python-format msgid "%(parent)s: %(oname)s not found" msgstr "%(parent)s: nie odnaleziono %(oname)s" #, python-format msgid "%(pkey)s: %(oname)s not found" msgstr "%(pkey)s: nie odnaleziono %(oname)s" msgid "Continuous mode: Don't stop on errors." msgstr "Tryb ciÄ…gÅ‚y: bez zatrzymywania po błędach." msgid "Rights" msgstr "Uprawnienia" msgid "the entry was deleted while being modified" msgstr "wpis zostaÅ‚ usuniÄ™ty podczas modyfikowania" #, python-format msgid "member %s" msgstr "czÅ‚onek %s" msgid "Members that could not be added" msgstr "Elementy, które nie mogÅ‚y zostać dodane" msgid "Number of members added" msgstr "Liczba dodanych elementów" msgid "Members that could not be removed" msgstr "Liczba elementów, które nie mogÅ‚y zostać usuniÄ™te" msgid "Number of members removed" msgstr "Liczba usuniÄ™tych elementów" msgid "Time Limit" msgstr "Ograniczenie czasu" msgid "Time limit of search in seconds" msgstr "Ograniczenie czasu wyszukiwania w sekundach" msgid "Size Limit" msgstr "Ograniczenie rozmiaru" msgid "Maximum number of entries returned" msgstr "Maksymalna liczba zwróconych wpisów" msgid "Failure decoding Certificate Signing Request:" msgstr "Dekodowanie żądania podpisywania certyfikatu nie powiodÅ‚o siÄ™:" msgid "Failure decoding Certificate Signing Request" msgstr "Dekodowanie żądania podpisywania certyfikatu nie powiodÅ‚o siÄ™" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "Dekodowanie żądania podpisywania certyfikatu nie powiodÅ‚o siÄ™: %s" msgid "Principal" msgstr "Naczelnik" msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "Naczelnik usÅ‚ugi dla tego certyfikatu (np. HTTP/test.przykÅ‚ad.pl)" msgid "automatically add the principal if it doesn't exist" msgstr "automatycznie dodaj naczelnika, jeÅ›li nie istnieje" msgid "Certificate" msgstr "Certyfikat" msgid "Subject" msgstr "Temat" msgid "Issuer" msgstr "Wydawca" msgid "Not Before" msgstr "Nie wczeÅ›niej" msgid "Not After" msgstr "Nie po" msgid "Fingerprint (MD5)" msgstr "Odcisk (MD5)" msgid "Fingerprint (SHA1)" msgstr "Odcisk (SHA1)" msgid "Serial number" msgstr "Numer seryjny" msgid "Dictionary mapping variable name to value" msgstr "Nazwa zmiennej mapowania sÅ‚ownika do ustawienia jako wartość" msgid "Request id" msgstr "Identyfikator żądania" msgid "Request status" msgstr "Stan żądania" msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "" "Numer seryjny w formie dziesiÄ™tnej lub szesnastkowej, jeÅ›li poprzedzone 0x" msgid "Revocation reason" msgstr "Przyczyna unieważnienia" msgid "Revoke a certificate." msgstr "Odrzuć certyfikat." msgid "Revoked" msgstr "Unieważniono" msgid "Reason" msgstr "Przyczyna" msgid "Reason for revoking the certificate (0-10)" msgstr "Przyczyna unieważnienia certyfikatu (0-10)" msgid "Unrevoked" msgstr "CofniÄ™to unieważnienie" msgid "Error" msgstr "Błąd" msgid "Status" msgstr "Stan" msgid "Configuration" msgstr "Konfiguracja" msgid "Home directory base" msgstr "Podstawa katalogu domowego" msgid "Default shell" msgstr "DomyÅ›lna powÅ‚oka" msgid "Default shell for new users" msgstr "DomyÅ›lna powÅ‚oka dla nowych użytkowników" msgid "Default users group" msgstr "DomyÅ›lna grupa użytkowników" msgid "Default group for new users" msgstr "DomyÅ›lna grupa dla nowych użytkowników" msgid "Search time limit" msgstr "Ograniczenie czasu wyszukiwania" msgid "Search size limit" msgstr "Ograniczenie rozmiaru wyszukiwania" msgid "User search fields" msgstr "Pola wyszukiwania użytkowników" msgid "Certificate Subject base" msgstr "Podstawa tematu certyfikatu" msgid "Hostname" msgstr "Nazwa komputera" msgid "Target" msgstr "Cel" msgid "Priority" msgstr "Priorytet" msgid "Zone name" msgstr "Nazwa strefy" msgid "Zone name (FQDN)" msgstr "Nazwa strefy (FQDN)" msgid "Administrator e-mail address" msgstr "Adres e-mail administratora" msgid "SOA serial" msgstr "Numer seryjny SOA" msgid "SOA refresh" msgstr "OdÅ›wieżenie SOA" msgid "SOA retry" msgstr "Ponowienie SOA" msgid "SOA expire" msgstr "Wygaszenie SOA" msgid "SOA minimum" msgstr "Minimalne SOA" msgid "SOA time to live" msgstr "Czas życia SOA" msgid "SOA class" msgstr "Klasa SOA" msgid "BIND update policy" msgstr "Polityka aktualizacji BIND" msgid "Active zone" msgstr "Aktywna strefa" msgid "DNS is not configured" msgstr "DNS nie jest skonfigurowany" msgid "Time to live" msgstr "Czas życia" msgid "Class" msgstr "Klasa" msgid "Delete all associated records" msgstr "UsuÅ„ wszystkie powiÄ…zane wpisy" msgid "Delete all?" msgstr "Usunąć wszystko?" #, python-format msgid "Found '%(value)s'" msgstr "Odnaleziono \"%(value)s\"" #, python-format msgid "Host '%(host)s' not found" msgstr "Nie odnaleziono komputera \"%(host)s\"" msgid "User Groups" msgstr "Grupy użytkowników" msgid "Group name" msgstr "Nazwa grupy" msgid "Group description" msgstr "Opis grupy" msgid "GID" msgstr "GID" msgid "GID (use this option to set it manually)" msgstr "GID (ta opcja umożliwia jego rÄ™czne ustawienie)" #, python-format msgid "Added group \"%(value)s\"" msgstr "Dodano grupÄ™ \"%(value)s\"" #, python-format msgid "Deleted group \"%(value)s\"" msgstr "UsuniÄ™to grupÄ™ \"%(value)s\"" #, python-format msgid "Modified group \"%(value)s\"" msgstr "Zmodyfikowano grupÄ™ \"%(value)s\"" msgid "change to a POSIX group" msgstr "zmiana na grupÄ™ POSIX" #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "Pasuje %(count)d grupa" msgstr[1] "PasujÄ… %(count)d grupy" msgstr[2] "Pasuje %(count)d grup" #, python-format msgid "Detached group \"%(value)s\" from user \"%(value)s\"" msgstr "Odłączono grupÄ™ \"%(value)s\" od użytkownika \"%(value)s\"" msgid "not allowed to modify user entries" msgstr "modyfikowanie wpisów użytkowników nie jest dozwolone" msgid "not allowed to modify group entries" msgstr "modyfikowanie wpisów grup nie jest dozwolone" msgid "Not a managed group" msgstr "Nie jest zarzÄ…dzanÄ… grupÄ…" msgid "Rule name" msgstr "Nazwa reguÅ‚y" msgid "Rule type" msgstr "Typ reguÅ‚y" msgid "User category" msgstr "Kategoria użytkowników" msgid "User category the rule applies to" msgstr "Kategoria użytkowników, do których zastosowywana jest reguÅ‚a" msgid "Host category" msgstr "Kategoria komputerów" msgid "Host category the rule applies to" msgstr "Kategoria komputerów, do których zastosowywana jest reguÅ‚a" msgid "Service category" msgstr "Kategoria usÅ‚ug" msgid "Service category the rule applies to" msgstr "Kategoria usÅ‚ug, do których zastosowywana jest reguÅ‚a" msgid "Enabled" msgstr "Włączone" msgid "Users" msgstr "Użytkownicy" msgid "Hosts" msgstr "Komputery" msgid "Host Groups" msgstr "Grupy komputerów" msgid "Services" msgstr "UsÅ‚ugi" msgid "Service Groups" msgstr "Grupy usÅ‚ug" msgid "Access time" msgstr "Czas dostÄ™pu" msgid "Service name" msgstr "Nazwa usÅ‚ugi" msgid "Service group name" msgstr "Nazwa grupy usÅ‚ugi" msgid "HBAC service group description" msgstr "Opis grupy usÅ‚ugi HBAC" msgid "User name" msgstr "Nazwa użytkownika" msgid "Keytab" msgstr "Tabela kluczy" msgid "Host name" msgstr "Nazwa komputera" msgid "A description of this host" msgstr "Opis tego komputera" msgid "Locality" msgstr "Lokalizacja" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "Lokalizacja komputera (np. \"Baltimore, MD\")" msgid "Host location (e.g. \"Lab 2\")" msgstr "PoÅ‚ożenie komputera (np. \"Laboratorium nr 2\")" msgid "Platform" msgstr "Platforma" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "Platforma sprzÄ™towa komputera (np. \"Lenovo T61\")" msgid "Operating system" msgstr "System operacyjny" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "System operacyjny komputera i jego wersja (np. \"Fedora 9\")" msgid "User password" msgstr "HasÅ‚o użytkownika" msgid "Password used in bulk enrollment" msgstr "HasÅ‚o używane w zapisywaniu wiÄ™kszej części" msgid "Base-64 encoded server certificate" msgstr "Certyfikat serwera zakodowany za pomocÄ… Base-64" msgid "Principal name" msgstr "Nazwa naczelnika" #, python-format msgid "Added host \"%(value)s\"" msgstr "Dodano komputer \"%(value)s\"" msgid "force host name even if not in DNS" msgstr "wymuszenie nazwy komputera nawet, jeÅ›li nie w DNS" #, python-format msgid "Deleted host \"%(value)s\"" msgstr "UsuniÄ™to komputer \"%(value)s\"" #, python-format msgid "Modified host \"%(value)s\"" msgstr "Zmodyfikowano komputer \"%(value)s\"" msgid "Kerberos principal name for this host" msgstr "Nazwa naczelnika Kerberosa dla tego komputera" #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "Pasuje %(count)d komputer" msgstr[1] "Pasuje %(count)d komputery" msgstr[2] "Pasuje %(count)d komputerów" msgid "Host-group" msgstr "Grupa komputerów" msgid "Name of host-group" msgstr "Nazwa grupy komputerów" msgid "A description of this host-group" msgstr "Opis tej grupy komputerów" #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "Dodano grupÄ™ komputerów \"%(value)s\"" #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "UsuniÄ™to grupÄ™ komputerów \"%(value)s\"" #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "Zmodyfikowano grupÄ™ komputerów \"%(value)s\"" #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "Pasuje %(count)d grupa komputerów" msgstr[1] "PasujÄ… %(count)d grupy komputerów" msgstr[2] "Pasuje %(count)d grup komputerów" msgid "Name of object to export" msgstr "Nazwa obiektu do wyeksportowania" msgid "Dict of JSON encoded IPA Objects" msgstr "SÅ‚ownik obiektów IPA zakodowanych w formacie JSON" msgid "Add" msgstr "Dodaj" msgid "Add and Close" msgstr "Dodaj i zamknij" msgid "Add and Edit" msgstr "Dodaj i edytuj" msgid "Cancel" msgstr "Anuluj" msgid "Close" msgstr "Zamknij" msgid "Find" msgstr "Znajdź" msgid "Delete" msgstr "UsuÅ„" msgid "Reset" msgstr "Przywróć" msgid "Restore" msgstr "Przywróć" msgid "Retry" msgstr "Ponów" msgid "Update" msgstr "Zaktualizuj" msgid "Back to Top" msgstr "Wróć na górÄ™" msgid "Settings" msgstr "Ustawienia" msgid "Search" msgstr "Wyszukaj" msgid "Logged In As" msgstr "Zalogowano jako" msgid "Attribute" msgstr "Atrybut" msgid "New Certificate" msgstr "Nowy certyfikat" msgid "Certificate Revoked" msgstr "Odrzucono certyfikat" msgid "Data" msgstr "Dane" msgid "DNS Zone Settings" msgstr "Ustawienia strefy DNS" msgid "Host Name" msgstr "Nazwa komputera" msgid "Set OTP" msgstr "Ustaw OTP" msgid "Kerberos Ticket Policy" msgstr "Polityka zgÅ‚oszeÅ„ Kerberosa" msgid "User" msgstr "Użytkownik" msgid "Password Policy" msgstr "Polityka haseÅ‚" msgid "Groups" msgstr "Grupy" msgid "Commands" msgstr "Polecenia" msgid "Account Settings" msgstr "Ustawienia konta" msgid "Mailing Address" msgstr "Adres pocztowy" msgid "Misc. Information" msgstr "Różne informacje" msgid "New Password" msgstr "Nowe hasÅ‚o" msgid "Password change complete" msgstr "UkoÅ„czono zmianÄ™ hasÅ‚a" msgid "Passwords must match" msgstr "HasÅ‚a muszÄ… siÄ™ zgadzać" msgid "Quick Links" msgstr "Szybkie odnoÅ›niki" msgid "Select All" msgstr "Zaznacz wszystko" msgid "Unselect All" msgstr "Odznacz wszystko" msgid "Automount" msgstr "Automatyczne montowanie" msgid "DNS" msgstr "DNS" msgid "Role Based Access Control" msgstr "Kontrola dostÄ™pu oparta na rolach" msgid "Dict of I18N messages" msgstr "SÅ‚ownik komunikatów umiÄ™dzynaradawiania" msgid "Manage ticket policy for specific user" msgstr "ZarzÄ…dzanie politykÄ… zgÅ‚oszeÅ„ dla podanego użytkownika" msgid "Max life" msgstr "Maksymalny czas życia" msgid "Maximum ticket life (seconds)" msgstr "Minimalny czas życia zgÅ‚oszenia (sekundy)" msgid "Max renew" msgstr "Maksymalne odnowienie" msgid "Maximum renewable age (seconds)" msgstr "Maksymalny czas, w którym możliwe jest odnowienie (sekundy)" #, python-format msgid "" "Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually." msgstr "" "Naczelnik Kerberosa %s już istnieje. Należy użyć polecenia \"ipa user-mod\", " "aby ustawić go rÄ™cznie." msgid "" "Failed to add user to the default group. Use 'ipa group-add-member' to add " "manually." msgstr "" "Dodanie użytkownika do domyÅ›lnej grupy nie powiodÅ‚o siÄ™. Należy użyć " "polecenia \"ipa group-add-member\", aby dodać go rÄ™cznie." msgid "LDAP URI" msgstr "Adres URI LDAP" msgid "LDAP URI of DS server to migrate from" msgstr "Adres URI LDAP serwera DS, z którego migrować" msgid "bind password" msgstr "hasÅ‚o Bind" msgid "Bind DN" msgstr "DN dowiÄ…zania" msgid "User container" msgstr "Kontener użytkownika" msgid "Group container" msgstr "Kontener grupy" msgid "LDAP schema" msgstr "Schemat LDAP" msgid "Lists of objects migrated; categorized by type." msgstr "Lista migrowanych obiektów, uÅ‚ożonych w kategorie wedÅ‚ug typu." msgid "Lists of objects that could not be migrated; categorized by type." msgstr "" "Lista obiektów, które nie mogÅ‚y zostać migrowane, uÅ‚ożonych w kategorie " "wedÅ‚ug typu." msgid "False if migration mode was disabled." msgstr "FaÅ‚sz, jeÅ›li wyłączono tryb migracji" msgid "Migration mode is disabled. Use 'ipa config-mod' to enable it." msgstr "" "Tryb migracji jest wyłączony. Należy użyć polecenia \"ipa config-mod\", aby " "go włączyć." msgid "" "Passwords have been migrated in pre-hashed format.\n" "IPA is unable to generate Kerberos keys unless provided\n" "with clear text passwords. All migrated users need to\n" "login at https://your.domain/ipa/migration/ before they\n" "can use their Kerberos accounts." msgstr "" "HasÅ‚a zostaÅ‚y migrowane w formacie sprzed mieszania.\n" "Program IPA nie może utworzyć kluczy Kerberosa, chyba\n" "że zostaÅ‚y podane z hasÅ‚ami w zwykÅ‚ym tekÅ›cie. Wszyscy\n" "migrowani użytkownicy muszÄ… zalogować siÄ™ na stronie\n" "https://twoja.domena/ipa/migration/, zanim bÄ™dÄ… mogli\n" "używać swoich kont Kerberosa." #, python-format msgid "%(count)d variables" msgstr "%(count)d zmiennych" msgid "Total number of variables env (>= count)" msgstr "CaÅ‚kowita liczba zmiennych Å›rodowiskowych (>= licznik)" msgid "Number of variables returned (<= total)" msgstr "Liczba zwróconych zmiennych (<= razem)" #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "Wczytano %(count)d wtyczkÄ™" msgstr[1] "Wczytano %(count)d wtyczki" msgstr[2] "Wczytano %(count)d wtyczek" msgid "Number of plugins loaded" msgstr "Liczba wczytanych wtyczek" msgid "Member Host" msgstr "Komputer elementu" msgid "Netgroups" msgstr "Grupy sieciowe" msgid "Netgroup name" msgstr "Nazwa grupy sieciowej" msgid "Netgroup description" msgstr "Opis grupy sieciowej" msgid "NIS domain name" msgstr "Nazwa domeny NIS" msgid "IPA unique ID" msgstr "Unikalny identyfikator IPA" #, python-format msgid "Changed password for \"%(value)s\"" msgstr "Zmieniono hasÅ‚o dla \"%(value)s\"" msgid "Member of group" msgstr "CzÅ‚onek grupy" #, python-format msgid "priority must be a unique value (%(prio)d already used by %(gname)s)" msgstr "" "priorytet musi być unikalnÄ… wartoÅ›ciÄ… (%(prio)d jest już używane przez " "%(gname)s)" msgid "Group" msgstr "Grupa" msgid "Manage password policy for specific group" msgstr "ZarzÄ…dzanie politykÄ… haseÅ‚ dla podanej grupy" msgid "Max lifetime (days)" msgstr "Maksymalny czas życia (w dniach)" msgid "Maximum password lifetime (in days)" msgstr "Maksymalny czas życia hasÅ‚a (w dniach)" msgid "Min lifetime (hours)" msgstr "Minimalny czas życia (w godzinach)" msgid "Minimum password lifetime (in hours)" msgstr "Minimalny czas życia hasÅ‚a (w godzinach)" msgid "History size" msgstr "Rozmiar historii" msgid "Password history size" msgstr "Rozmiar historii haseÅ‚" msgid "Character classes" msgstr "Klasy znaków" msgid "Minimum number of character classes" msgstr "Minimalna liczba klas znaków" msgid "Min length" msgstr "Minimalna dÅ‚ugość" msgid "Minimum length of password" msgstr "Minimalna dÅ‚ugość hasÅ‚a" msgid "Priority of the policy (higher number means lower priority" msgstr "Priorytet polityki (wyższy numer równa siÄ™ niższemu priorytetowi" msgid "Maximum password life must be greater than minimum." msgstr "Maksymalny czas życia hasÅ‚a musi być wyższy niż minimalny." msgid "priority cannot be set on global policy" msgstr "nie można ustawiać priorytetu dla globalnej polityki" msgid "Display effective policy for a specific user" msgstr "WyÅ›wietlanie aktywnej polityki dla podanego użytkownika" msgid "A description of this role-group" msgstr "Opis tej grupy rol" msgid "Service principal" msgstr "Naczelnik usÅ‚ugi" #, python-format msgid "Added service \"%(value)s\"" msgstr "Dodano usÅ‚ugÄ™ \"%(value)s\"" msgid "force principal name even if not in DNS" msgstr "wymuszenie nazwy naczelnika nawet, jeÅ›li nie w DNS" #, python-format msgid "Deleted service \"%(value)s\"" msgstr "UsuniÄ™to usÅ‚ugÄ™ \"%(value)s\"" #, python-format msgid "Modified service \"%(value)s\"" msgstr "Zmodyfikowano usÅ‚ugÄ™ \"%(value)s\"" #, python-format msgid "%(count)d service matched" msgid_plural "%(count)d services matched" msgstr[0] "Pasuje %(count)d usÅ‚uga" msgstr[1] "Pasuje %(count)d usÅ‚ugi" msgstr[2] "Pasuje %(count)d usÅ‚ug" msgid "Sudo Command" msgstr "Polecenie sudo" msgid "A description of this command" msgstr "Opis tego polecenia" msgid "Sudo Allow Commands" msgstr "Polecenia zezwolone sudo" msgid "Sudo Deny Commands" msgstr "Polecenia zabronione sudo" msgid "Realm name" msgstr "Nazwa obszaru" msgid "User login" msgstr "Login użytkownika" msgid "First name" msgstr "ImiÄ™" msgid "Last name" msgstr "Nazwisko" msgid "Full name" msgstr "PeÅ‚na nazwa" msgid "Home directory" msgstr "Katalog domowy" msgid "Login shell" msgstr "PowÅ‚oka logowania" msgid "Kerberos principal" msgstr "Naczelnik Kerberosa" msgid "Email address" msgstr "Adres e-mail" msgid "UID" msgstr "UID" msgid "User ID Number (system will assign one if not provided)" msgstr "" "Numer identyfikacyjny użytkownika (system go przydzieli, jeÅ›li nie zostanie " "podany)" msgid "Street address" msgstr "Adres zamieszkania" msgid "City" msgstr "Miasto" msgid "Telephone Number" msgstr "Numer telefonu" msgid "Mobile Telephone Number" msgstr "Numer telefonu komórkowego" msgid "Pager Number" msgstr "Numer pagera" msgid "Fax Number" msgstr "Numer faksu" #, python-format msgid "Added user \"%(value)s\"" msgstr "Dodano użytkownika \"%(value)s\"" #, python-format msgid "Deleted user \"%(value)s\"" msgstr "UsuniÄ™to użytkownika \"%(value)s\"" #, python-format msgid "Modified user \"%(value)s\"" msgstr "Zmodyfikowano użytkownika \"%(value)s\"" msgid "Self" msgstr "WÅ‚asny" msgid "Display user record for current Kerberos principal" msgstr "WyÅ›wietlenie wpisu użytkownika dla bieżącego naczelnika Kerberosa" #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "Pasuje %(count)d użytkownik" msgstr[1] "Pasuje %(count)d użytkowników" msgstr[2] "Pasuje %(count)d użytkowników" #, python-format msgid "Disabled user account \"%(value)s\"" msgstr "Wyłączono konto użytkownika \"%(value)s\"" #, python-format msgid "Enabled user account \"%(value)s\"" msgstr "Włączono konto użytkownika \"%(value)s\"" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "Nie można komunikować siÄ™ z CMS (%s)" msgid "The hostname to register as" msgstr "Nazwa komputera, pod jakÄ… zarejestrować" msgid "The IPA realm" msgstr "Obszar IPA" msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "Platforma sprzÄ™towa komputera (np. Lenovo T61)" msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "System operacyjny komputera i jego wersja (np. Fedora 9)" #, c-format msgid "cannot open configuration file %s\n" msgstr "nie można otworzyć pliku konfiguracji %s\n" #, c-format msgid "cannot stat() configuration file %s\n" msgstr "nie można wykonać stat() na pliku konfiguracji %s\n" #, c-format msgid "read error\n" msgstr "błąd odczytu\n" #, c-format msgid "No keys accepted by KDC\n" msgstr "Å»adne klucze nie zostaÅ‚y zaakceptowane przez KDC\n" #, c-format msgid "Out of memory \n" msgstr "Brak pamiÄ™ci \n" #, c-format msgid "Out of Memory!\n" msgstr "Brak pamiÄ™ci.\n" #, c-format msgid "Failed to create control!\n" msgstr "Utworzenie kontroli nie powiodÅ‚o siÄ™.\n" #, c-format msgid "Unable to initialize ldap library!\n" msgstr "Nie można zainicjować biblioteki LDAP.\n" #, c-format msgid "Unable to set ldap options!\n" msgstr "Nie można ustawić opcji LDAP.\n" #, c-format msgid "Simple bind failed\n" msgstr "Proste dowiÄ…zanie nie powiodÅ‚o siÄ™\n" #, c-format msgid "Operation failed! %s\n" msgstr "DziaÅ‚anie nie powiodÅ‚o siÄ™. %s\n" #, c-format msgid "Missing reply control!\n" msgstr "Brak kontroli odpowiedzi.\n" #, c-format msgid "ber_init() failed, Invalid control ?!\n" msgstr "ber_init() nie powiodÅ‚o siÄ™, nieprawidÅ‚owa kontrola?\n" msgid "New Principal Password" msgstr "Nowe hasÅ‚o naczelnika" msgid "Verify Principal Password" msgstr "Sprawdzenie hasÅ‚a naczelnika" msgid "Print as little as possible" msgstr "WyÅ›wietla tak maÅ‚o, jak to możliwe" msgid "Output only on errors" msgstr "WyÅ›wietla tylko błędy" msgid "Contact this specific KDC Server" msgstr "Kontaktuje siÄ™ z konkretnym serwerem KDC" msgid "Server Name" msgstr "Nazwa serwera" msgid "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)" msgstr "" "Naczelnik, dla którego uzyskać tablicÄ™ kluczy (np.: ftp/ftp.przykÅ‚ad." "pl@PRZYKÅAD.PL)" msgid "Kerberos Service Principal Name" msgstr "Nazwa naczelnika usÅ‚ugi Kerberos" msgid "File were to store the keytab information" msgstr "Plik, w którym przechowywać informacjÄ™ o tablicy kluczy" msgid "Keytab File Name" msgstr "Nazwa pliku tablicy kluczy" msgid "Encryption types to request" msgstr "Typy szyfrowania do zażądania" msgid "Comma separated encryption types list" msgstr "Lista typów szyfrowania oddzielonych przecinkami" msgid "Show the list of permitted encryption types and exit" msgstr "WyÅ›wietla listÄ™ dozwolonych typów szyfrowania i koÅ„czy dziaÅ‚anie" msgid "Permitted Encryption Types" msgstr "Dozwolone typy szyfrowania" msgid "Asks for a non-random password to use for the principal" msgstr "Pyta o nielosowe hasÅ‚o do użycia z naczelnikiem" msgid "LDAP DN" msgstr "DN LDAP" msgid "DN to bind as if not using kerberos" msgstr "DN do dowiÄ…zania, jeÅ›li nie jest używany Kerberos" msgid "LDAP password" msgstr "HasÅ‚o LDAP" msgid "password to use if not using kerberos" msgstr "hasÅ‚o do użycia, jeÅ›li nie jest używany Kerberos" #, c-format msgid "Kerberos context initialization failed\n" msgstr "Zainicjowanie kontekstu Kerberosa nie powiodÅ‚o siÄ™\n" #, c-format msgid "No system preferred enctypes ?!\n" msgstr "Brak typów szyfrowania preferowanych przez system?\n" #, c-format msgid "Supported encryption types:\n" msgstr "ObsÅ‚ugiwane typy szyfrowania:\n" #, c-format msgid "Warning: failed to convert type (#%d)\n" msgstr "Ostrzeżenie: przekonwertowanie typu (#%d) nie powiodÅ‚o siÄ™\n" #, c-format msgid "Bind password required when using a bind DN.\n" msgstr "HasÅ‚o dowiÄ…zania jest wymagane podczas używania dowiÄ…zania DN.\n" #, c-format msgid "" "Warning: salt types are not honored with randomized passwords (see opt. -P)\n" msgstr "" "Ostrzeżenie: typy salt nie sÄ… uwzglÄ™dniane z losowymi hasÅ‚ami (proszÄ™ " "zobaczyć opcjÄ™ -P)\n" #, c-format msgid "Invalid Service Principal Name\n" msgstr "NieprawidÅ‚owa nazwa naczelnika usÅ‚ugi\n" #, c-format msgid "Kerberos Credential Cache not found. Do you have a Kerberos Ticket?\n" msgstr "" "Nie odnaleziono pamiÄ™ci podrÄ™cznej danych uwierzytelniajÄ…cych. Istnieje " "zgÅ‚oszenie Kerberosa?\n" #, c-format msgid "" "Kerberos User Principal not found. Do you have a valid Credential Cache?\n" msgstr "" "Nie odnaleziono naczelnika użytkownika Kerberosa. Istnieje prawidÅ‚owa pamięć " "podrÄ™czna danych uwierzytelniajÄ…cych?\n" #, c-format msgid "Failed to open Keytab\n" msgstr "Otwarcie tablicy kluczy nie powiodÅ‚o siÄ™\n" #, c-format msgid "Failed to create key material\n" msgstr "Utworzenie materiaÅ‚u klucza nie powiodÅ‚o siÄ™\n" #, c-format msgid "Failed to add key to the keytab\n" msgstr "Dodanie klucza do tablicy kluczy nie powiodÅ‚o siÄ™\n" #, c-format msgid "Failed to close the keytab\n" msgstr "ZamkniÄ™cie tablicy kluczy nie powiodÅ‚o siÄ™\n" #, c-format msgid "Keytab successfully retrieved and stored in: %s\n" msgstr "PomyÅ›lnie pobrano tablicÄ™ kluczy i przechowano jÄ… w: %s\n" #, c-format msgid "No permission to join this host to the IPA domain.\n" msgstr "Brak uprawnienia do dołączenia do tego komputera w domenie IPA.\n" #, c-format msgid "No write permissions on keytab file '%s'\n" msgstr "Brak uprawnieÅ„ do zapisu pliku tablicy kluczy \"%s\"\n" #, c-format msgid "Unable to enable SSL in LDAP\n" msgstr "Nie można włączyć SSL w LDAP\n" #, c-format msgid "Unable to set LDAP version\n" msgstr "Nie można ustawić wersji LDAP\n" #, c-format msgid "Bind failed: %s\n" msgstr "DowiÄ…zanie nie powiodÅ‚o siÄ™: %s\n" #, c-format msgid "No values for %s" msgstr "Brak wartoÅ›ci dla %s" #, c-format msgid "Out of memory!\n" msgstr "Brak pamiÄ™ci.\n" #, c-format msgid "Search for ipaCertificateSubjectBase failed with error %d" msgstr "Wyszukiwanie ipaCertificateSubjectBase nie powiodÅ‚o siÄ™ z błędem %d" #, c-format msgid "Unable to determine root DN of %s\n" msgstr "Nie można ustalić głównego DN %s\n" #, c-format msgid "Incorrect password.\n" msgstr "Niepoprawne hasÅ‚o.\n" #, c-format msgid "Unable to determine certificate subject of %s\n" msgstr "Nie można ustalić tematu certyfikatu %s\n" #, c-format msgid "principal not found in XML-RPC response\n" msgstr "nie odnaleziono naczelnika w odpowiedzi XML-RPC\n" #, c-format msgid "Host is already joined.\n" msgstr "Komputer jest już dołączony.\n" #, c-format msgid "Unable to determine IPA server from %s\n" msgstr "Nie można ustalić serwera IPA z %s\n" #, c-format msgid "The hostname must be fully-qualified: %s\n" msgstr "Nazwa komputera musi być w peÅ‚ni kwalifikowana: %s\n" #, c-format msgid "Unable to join host: Kerberos context initialization failed\n" msgstr "" "Nie można dołączyć do komputera: zainicjowanie kontekstu Kerberosa nie " "powiodÅ‚o siÄ™\n" #, c-format msgid "Error resolving keytab: %s.\n" msgstr "Błąd podczas rozwiÄ…zywania tablicy kluczy: %s.\n" #, c-format msgid "Error obtaining initial credentials: %s.\n" msgstr "" "Błąd podczas uzyskiwania poczÄ…tkowych danych uwierzytelniajÄ…cych: %s.\n" #, c-format msgid "Unable to generate Kerberos Credential Cache\n" msgstr "" "Nie można utworzyć pamiÄ™ci podrÄ™cznej danych uwierzytelniajÄ…cych Kerberosa\n" #, c-format msgid "Error storing creds in credential cache: %s.\n" msgstr "" "Błąd podczas przechowywania danych uwierzytelniajÄ…cych w pamiÄ™ci podrÄ™cznej: " "%s.\n" #, c-format msgid "Unenrollment successful.\n" msgstr "PomyÅ›lnie wypisano.\n" #, c-format msgid "Unenrollment failed.\n" msgstr "Wypisanie nie powiodÅ‚o siÄ™.\n" #, c-format msgid "result not found in XML-RPC response\n" msgstr "nie odnaleziono wyniku w odpowiedzi XML-RPC\n" #, c-format msgid "Unable to join host: Kerberos Credential Cache not found\n" msgstr "" "Nie można dołączyć do komputera: nie odnaleziono pamiÄ™ci podrÄ™cznej danych " "uwierzytelniajÄ…cych Kerberosa\n" #, c-format msgid "" "Unable to join host: Kerberos User Principal not found and host password not " "provided.\n" msgstr "" "Nie można dołączyć do komputera: nie odnaleziono naczelnika użytkownika " "Kerberosa oraz nie podano hasÅ‚a komputera.\n" #, c-format msgid "fork() failed\n" msgstr "fork() nie powiodÅ‚o siÄ™\n" #, c-format msgid "ipa-getkeytab not found\n" msgstr "nie odnaleziono ipa-getkeytab\n" #, c-format msgid "ipa-getkeytab has bad permissions?\n" msgstr "ipa-getkeytab posiada błędne uprawnienia?\n" #, c-format msgid "executing ipa-getkeytab failed, errno %d\n" msgstr "wykonanie ipa-getkeytab nie powiodÅ‚o siÄ™, errno %d\n" #, c-format msgid "child exited with %d\n" msgstr "potomek zostaÅ‚ zakoÅ„czony z %d\n" #, c-format msgid "Certificate subject base is: %s\n" msgstr "Podstawa tematu certyfikatu: %s\n" msgid "Unenroll this host from IPA server" msgstr "Wypisuje ten komputer z serwera IPA" msgid "IPA Server to use" msgstr "Serwer IPA do użycia" msgid "password" msgstr "hasÅ‚o" #, c-format msgid "Unable to parse principal name\n" msgstr "Nie można przetworzyć nazwy naczelnika\n" #, c-format msgid "Removing principal %s\n" msgstr "Usuwanie naczelnika %s\n" #, c-format msgid "Failed to open keytab\n" msgstr "Otwarcie tablicy kluczy nie powiodÅ‚o siÄ™\n" #, c-format msgid "principal not found\n" msgstr "nie odnaleziono naczelnika\n" #, c-format msgid "Unable to remove entry\n" msgstr "Nie można usunąć wpisu\n" #, c-format msgid "kvno %d\n" msgstr "kvno %d\n" #, c-format msgid "Unable to parse principal\n" msgstr "Nie można przetworzyć naczelnika\n" msgid "Print debugging information" msgstr "WyÅ›wietlanie informacji o debugowaniu" msgid "Debugging output" msgstr "WyjÅ›cie debugowania" msgid "Remove all principals in this realm" msgstr "Usuwa wszystkich naczelników w tym obszarze" #, c-format msgid "Closing keytab failed\n" msgstr "ZamkniÄ™cie tablicy kluczy nie powiodÅ‚o siÄ™\n" msgid "Out of memory!?\n" msgstr "Brak pamiÄ™ci?\n" msgid "Out of memory\n" msgstr "Brak pamiÄ™ci\n" msgid "Enctype comparison failed!\n" msgstr "Porównanie typów szyfrowania nie powiodÅ‚o siÄ™.\n" msgid "Failed to create random key!\n" msgstr "Utworzenie losowego klucza nie powiodÅ‚o siÄ™.\n" msgid "Failed to create key!\n" msgstr "Utworzenie klucza nie powiodÅ‚o siÄ™.\n" freeipa-3.3.4/install/po/fr.po0000664000175000017500000126225612271663206015560 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Automatically generated, 2010 # Dralyab , 2013 # Dralyab , 2013 # Gé Baylard <>, 2013 # Jérôme Fenal , 2011-2013 # Jérôme Fenal , 2011 # Petr Viktorin , 2013 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-16 17:26+0000\n" "Last-Translator: Dralyab \n" "Language-Team: French \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fr\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Entrer à nouveau %(label)s pour validation :" #, c-format msgid "Passwords do not match!" msgstr "Les mots de passe ne correspondent pas !" msgid "No matching entries found" msgstr "Aucune entrée correspondante trouvée" msgid "Topic or Command" msgstr "Thème ou commande" msgid "The topic or command name." msgstr "Le nom du thème ou de la commande." msgid "Topic commands:" msgstr "Commandes du thème :" msgid "To get command help, use:" msgstr "Pour obtenir de l'aide, utiliser :" msgid " ipa --help" msgstr " ipa --help" msgid "Command name" msgstr "Nom de commande" msgid "Positional arguments" msgstr "Arguments positionnels" msgid "No file to read" msgstr "Pas de fichier à lire" #, python-format msgid "%(cver)s client incompatible with %(sver)s server at '%(server)s'" msgstr "Client %(cver)s incompatible avec un serveur %(sver)s à « %(server)s »" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "Code erreur inconnu %(code)d renvoyé par %(server)s: %(error)s" msgid "an internal error has occurred" msgstr "une erreur interne est survenue" #, python-format msgid "an internal error has occurred on server at '%(server)s'" msgstr "une erreur interne est survenue sur le serveur à « %(server)s »" #, python-format msgid "unknown command '%(name)s'" msgstr "commande « %(name)s » inconnue" #, python-format msgid "error on server '%(server)s': %(error)s" msgstr "erreur sur le serveur « %(server)s » : %(error)s" #, python-format msgid "cannot connect to '%(uri)s': %(error)s" msgstr "impossible de se connecter à « %(uri)s » : %(error)s" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "Requête JSON-RPC invalide : %(error)s" #, python-format msgid "error marshalling data for XML-RPC transport: %(error)s" msgstr "erreur au triage des données du transport XML-RPC : %(error)s" #, python-format msgid "Missing or invalid HTTP Referer, %(referer)s" msgstr "Referer HTTP manquant ou invalide, %(referer)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Erreur Kerberos : %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "n'ai pas reçu les crédits Kerberos" #, python-format msgid "Service '%(service)s' not found in Kerberos database" msgstr "Service « %(service)s » introuvable dans la base de données Kerberos" msgid "No credentials cache found" msgstr "Cache de crédits introuvable" msgid "Ticket expired" msgstr "Ticket expiré" msgid "Credentials cache permissions incorrect" msgstr "Permissions du cache de crédit incorrectes" msgid "Bad format in credentials cache" msgstr "Mauvais format de cache de crédit" msgid "Cannot resolve KDC for requested realm" msgstr "Impossible de trouver le KDC pour le domaine demandé" msgid "Session error" msgstr "Erreur de session" #, python-format msgid "Principal %(principal)s cannot be authenticated: %(message)s" msgstr "Le principal %(principal)s n'a pû être authentifié : %(message)s" #, python-format msgid "Insufficient access: %(info)s" msgstr "Accès insuffisant : %(info)s" #, python-format msgid "command '%(name)s' takes no arguments" msgstr "la commande « %(name)s » ne prend pas d'argument" #, python-format msgid "command '%(name)s' takes at most %(count)d argument" msgid_plural "command '%(name)s' takes at most %(count)d arguments" msgstr[0] "la commande « %(name)s » prend au plus %(count)d argument" msgstr[1] "la commande « %(name)s » prend au plus %(count)d arguments" #, python-format msgid "overlapping arguments and options: %(names)s" msgstr "les arguments et options se chevauchent : %(names)s" #, python-format msgid "'%(name)s' is required" msgstr "« %(name)s » est requis" #, python-format msgid "invalid '%(name)s': %(error)s" msgstr "« %(name)s » invalide : %(error)s" #, python-format msgid "api has no such namespace: '%(name)s'" msgstr "l'API ne possède pas cet espace de nom : « %(name)s »" msgid "Passwords do not match" msgstr "Les mots de passe ne correspondent pas" msgid "Command not implemented" msgstr "Commande non développée" msgid "Client is not configured. Run ipa-client-install." msgstr "Le client n'est pas configuré. Lancer la commande ipa-client-install." #, python-format msgid "Could not get %(name)s interactively" msgstr "Impossible d'obtenir %(name)s de façon interactive" #, python-format msgid "Command '%(name)s' has been deprecated" msgstr "La commande « %(name)s » est maintenant obsolète." #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Cette entrée existe déjà" msgid "You must enroll a host in order to create a host service" msgstr "Vous devez enregistrer un système afin de créer un service" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "Le principal de service n'est pas de la forme : service/fully-qualified host " "name: %(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "Le domaine du principal ne correspond pas au domaine de ce serveur IPA" msgid "This command requires root access" msgstr "Cette commande requiert des droits root" msgid "This is already a posix group" msgstr "Ce groupe est déjà de type POSIX" #, python-format msgid "Principal is not of the form user@REALM: '%(principal)s'" msgstr "Le principal n'est pas de la forme user@REALM : « %(principal)s »" msgid "This entry is already enabled" msgstr "Cette entrée est déjà activée" msgid "This entry is already disabled" msgstr "Cette entrée est déjà désactivée" msgid "This entry cannot be enabled or disabled" msgstr "Cette entrée ne peut être activée ou désactivée" msgid "This entry is not a member" msgstr "Cette entrée n'est pas un membre" msgid "A group may not be a member of itself" msgstr "Un groupe ne peut être membre de lui-même" msgid "This entry is already a member" msgstr "Cette entrée est déjà membre" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Échec de décodage base64 : %(reason)s" msgid "A group may not be added as a member of itself" msgstr "Un groupe ne peut être ajouté comme membre de lui-même" msgid "The default users group cannot be removed" msgstr "Le groupe par défaut ne peut être supprimé" msgid "Host does not have corresponding DNS A record" msgstr "Un système doit avoir un enregistrement DNS A correspondant" msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "" "La suppression d'un groupe géré est interdite. Il doit d'abord être détaché." msgid "A managed group cannot have a password policy." msgstr "Un groupe géré ne peut avoir de politique de mot de passe." #, python-format msgid "'%(entry)s' doesn't have a certificate." msgstr "'%(entry)s' ne possède pas de certificat." #, python-format msgid "Unable to create private group. A group '%(group)s' already exists." msgstr "" "Impossible de créer un groupe privé. Un groupe '%(group)s' existe déjà." #, python-format msgid "" "A problem was encountered when verifying that all members were %(verb)s: " "%(exc)s" msgstr "" "Un problème est survenu lors de la vérification que tous les membres étaient " "des %(verb)s: %(exc)s" #, python-format msgid "%(attr)s does not contain '%(value)s'" msgstr "%(attr)s ne contient pas '%(value)s'" #, python-format msgid "" "The search criteria was not specific enough. Expected 1 and found %(found)d." msgstr "" "Le critère de recherche n'est pas suffisamment spécifique. Une valeur " "attendue, mais %(found)d trouvées." msgid "This group already allows external members" msgstr "Ce groupe autorise déjà des membres externes" msgid "This group cannot be posix because it is external" msgstr "Ce groupe ne peut être de type posix car il est externe" msgid "This is already a posix group and cannot be converted to external one" msgstr "" "Ce groupe est déjà de type posix et ne peut être converti en groupe externe" #, python-format msgid "no command nor help topic '%(topic)s'" msgstr "pas de commande ou de sujet d'aide pour « %(topic)s »" msgid "change collided with another change" msgstr "la modification a subit un collision avec une autre" msgid "no modifications to be performed" msgstr "pas de modification à effectuer" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s : %(info)s" msgid "limits exceeded for this query" msgstr "limites dépassées pour cette requête" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "modifying primary key is not allowed" msgstr "la modification de clé primaire n'est pas autorisée" #, python-format msgid "%(attr)s: Only one value allowed." msgstr "%(attr)s : une seule valeur autorisée." #, python-format msgid "%(attr)s: Invalid syntax." msgstr "%(attr)s : syntaxe invalide." #, python-format msgid "Bad search filter %(info)s" msgstr "Filtre de recherche invalide %(info)s" msgid "Not allowed on non-leaf entry" msgstr "Interdit sur une entrée de type nÅ“ud" msgid "LDAP timeout" msgstr "expiration de délai LDAP" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "L'opération sur le certification ne peut être effectuée : %(error)s" #, python-format msgid "Certificate format error: %(error)s" msgstr "Erreur de format de certificate : %(error)s" msgid "Already registered" msgstr "Déjà enregistré" msgid "Not registered yet" msgstr "Pas encore enregistré" #, python-format msgid "%(key)s cannot be deleted because %(label)s %(dependent)s requires it" msgstr "" "%(key)s ne peut être supprimé car %(label)s %(dependent)s en dépendent" #, python-format msgid "" "%(key)s cannot be deleted or disabled because it is the last member of " "%(label)s %(container)s" msgstr "" "%(key)s ne peut être supprimé ou désactivé étant le dernier membre de " "l'objet %(container)s %(label)s" #, python-format msgid "%(label)s %(key)s cannot be deleted/modified: %(reason)s" msgstr "%(label)s %(key)s ne peut être supprimé ou modifié : %(reason)s" #, python-format msgid "%(name)s certificate is not valid" msgstr "le certificat %(name)s est invalide" msgid "Results are truncated, try a more specific search" msgstr "Résultats tronqués, essayer un recherche plus spécifique" #, python-format msgid "Unknown option: %(option)s" msgstr "Option inconnue : %(option)s" msgid "" "Retrieve and print all attributes from the server. Affects command output." msgstr "" "Récupérer et imprimer tous les attributs du serveur. Affecte la sortie " "standard de la commande." msgid "Print entries as stored on the server. Only affects output format." msgstr "" "Imprimer les entrées telles que stockées sur le serveur. Affecte uniquement " "le format de sortie." msgid "Client version. Used to determine if server will accept request." msgstr "" "Version du client. Utilisée pour déterminer si le serveur acceptera la " "requête." msgid "Forward to server instead of running locally" msgstr "Transférer au serveur au lieu d'exécuter localement" msgid "Additional instructions:" msgstr "Instructions complémentaires :" #, python-format msgid "" "API Version number was not sent, forward compatibility not guaranteed. " "Assuming server's API version, %(server_version)s" msgstr "" "Le serveur n'a pas envoyé de version d'API, la compatibilité ascendante " "n'est pas garantie. On part du principe que la version de l'API est " "%(server_version)s" msgid "A dictionary representing an LDAP entry" msgstr "Un dictionnaire représente une entrée LDAP" msgid "A list of LDAP entries" msgstr "Une liste d'entrées LDAP" msgid "All commands should at least have a result" msgstr "Toutes les commandes doivent avoir au moins un résultat" msgid "User-friendly description of action performed" msgstr "Description intelligible de l'action effectuée" msgid "The primary_key value of the entry, e.g. 'jdoe' for a user" msgstr "La clé primaire de l'entrée, par ex. 'jdoe' pour un utilisateur" msgid "Number of entries returned" msgstr "Nombre d'entrées renvoyées" msgid "True if not all results were returned" msgstr "Vrai si tous les résultats n'ont pas été renvoyés" msgid "List of deletions that failed" msgstr "Liste des suppressions en échec" msgid "True means the operation was successful" msgstr "Vrai signifie que l'opération a réussi" msgid "incorrect type" msgstr "type incorrect" msgid "Only one value is allowed" msgstr "Une seule valeur est autorisée" msgid "must be True or False" msgstr "doit être True ou False" msgid "must be an integer" msgstr "doit être un nombre entier" #, python-format msgid "must be at least %(minvalue)d" msgstr "doit être supérieur ou égal à %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "doit être inférieur ou égal à %(maxvalue)d" msgid "must be a decimal number" msgstr "doit être un nombre décimal" #, python-format msgid "must be at least %(minvalue)s" msgstr "doit valoir a minima %(minvalue)s" #, python-format msgid "can be at most %(maxvalue)s" msgstr "doit valoir au plus %(maxvalue)s" #, python-format msgid "" "number class '%(cls)s' is not included in a list of allowed number classes: " "%(allowed)s" msgstr "" "La classe de nombres '%(cls)s' ne fait pas partie d'une classe autorisée : " "%(allowed)s" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "doit correspondre au motif \"%(pattern)s\"" msgid "must be binary data" msgstr "doit être des données binaires" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "doit être d'au moins %(minlength)d octets" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "peut être d'au plus %(maxlength)d octets" #, python-format msgid "must be exactly %(length)d bytes" msgstr "doit être d'exactement %(length)d octets" msgid "must be Unicode text" msgstr "doit être du texte Unicode" msgid "Leading and trailing spaces are not allowed" msgstr "Les espaces de début et de fin ne sont pas autorisés" #, python-format msgid "must be at least %(minlength)d characters" msgstr "doit être d'au moins %(minlength)d caractères" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "peut être d'au plus %(maxlength)d caractères" #, python-format msgid "must be exactly %(length)d characters" msgstr "doit être d'exactement %(length)d caractères" #, python-format msgid "The character %(char)r is not allowed." msgstr "Le caractère « %(char)r » n'est pas autorisé." #, python-format msgid "must be '%(value)s'" msgstr "doit être « %(value)s »" #, python-format msgid "must be one of %(values)s" msgstr "doit être une valeur parmi %(values)s" msgid "incomplete time value" msgstr "valeur de temps incomplète" msgid "this option is deprecated" msgstr "cette option est obsolète" msgid "A list of ACI values" msgstr "Une liste de valeurs d'ACI" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "type, filter, subtree et targetgroup sont mutuellement exclusifs" msgid "ACI prefix is required" msgstr "Un préfixe ACI est requis" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "au moins un parmi type, filter, subtree, targetgroup, attrs ou memberof est " "requis" msgid "filter and memberof are mutually exclusive" msgstr "filter et memberof sont mutuellement exclusifs" msgid "group, permission and self are mutually exclusive" msgstr "group, permission et self sont mutuellement exclusifs" msgid "One of group, permission or self is required" msgstr "Un parmi group, permission ou self est requis" #, python-format msgid "Group '%s' does not exist" msgstr "Le groupe '%s' n'existe pas" msgid "empty filter" msgstr "filtre vide" #, python-format msgid "Syntax Error: %(error)s" msgstr "Erreur de syntaxe : %(error)s" #, python-format msgid "invalid DN (%s)" msgstr "DN invalide (%s)" #, python-format msgid "ACI with name \"%s\" not found" msgstr "ACI nommée \"%s\" introuvable" msgid "ACI prefix" msgstr "Préfixe ACI" msgid "" "Prefix used to distinguish ACI types (permission, delegation, selfservice, " "none)" msgstr "" "Préfixe utilisé pour distinguer les types d'ACI (permission, delegation, " "selfservice, none)" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "Nom d'ACI" msgid "Permission" msgstr "Permission" msgid "Permission ACI grants access to" msgstr "L'ACI Permission donne accès à" msgid "User group" msgstr "Groupe d'utilisateurs" msgid "User group ACI grants access to" msgstr "L'ACI groupe utilisateur donne accès à" msgid "Permissions" msgstr "Permissions" msgid "Permissions to grant(read, write, add, delete, all)" msgstr "Permissions à accorder (read, write, add, delete, all)" msgid "Attributes to which the permission applies" msgstr "Attributs auxquels les permissions s'appliquent" msgid "Attributes" msgstr "Attributs" msgid "Type" msgstr "Type" msgid "type of IPA object (user, group, host, hostgroup, service, netgroup)" msgstr "type d'objet IPA (user, group, host, hostgroup, service, netgroup)" msgid "Member of" msgstr "Membre de" msgid "Member of a group" msgstr "Membre d'un groupe" msgid "Filter" msgstr "Filtre" msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "Filtre LDAP valide (i.e. ou=Engineering)" msgid "Subtree" msgstr "Sous-arbre" msgid "Subtree to apply ACI to" msgstr "Sous-arbre sur lequel appliquer l'ACI" msgid "Target group" msgstr "Groupe cible" msgid "Group to apply ACI to" msgstr "Groupe sur lequel appliquer l'ACI" msgid "Target your own entry (self)" msgstr "Cibler votre propre entrée (self)" msgid "Apply ACI to your own entry (self)" msgstr "Appliquer l'ACI à votre propre entrée (self)" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "ACI créée \"%(value)s\"" msgid "Test the ACI syntax but don't write anything" msgstr "Tester la syntaxe de l'ACI, sans rien écrire" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "Deleted ACI \"%(value)s\"" msgid "ACI" msgstr "ACI" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "ACI modifiée \"%(value)s\"" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "%(count)d ACI correspondantes" msgstr[1] "%(count)d ACI correspondantes" msgid "New ACI name" msgstr "Nouveau nom de l'ACI" #, python-format msgid "Renamed ACI to \"%(value)s\"" msgstr "ACI renommée en \"%(value)s\"" msgid "" "\n" "Auto Membership Rule.\n" "\n" "Bring clarity to the membership of hosts and users by configuring inclusive\n" "or exclusive regex patterns, you can automatically assign a new entries " "into\n" "a group or hostgroup based upon attribute information.\n" "\n" "A rule is directly associated with a group by name, so you cannot create\n" "a rule without an accompanying group or hostgroup.\n" "\n" "A condition is a regular expression used by 389-ds to match a new incoming\n" "entry with an automember rule. If it matches an inclusive rule then the\n" "entry is added to the appropriate group or hostgroup.\n" "\n" "A default group or hostgroup could be specified for entries that do not\n" "match any rule. In case of user entries this group will be a fallback group\n" "because all users are by default members of group specified in IPA config.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add the initial group or hostgroup:\n" " ipa hostgroup-add --desc=\"Web Servers\" webservers\n" " ipa group-add --desc=\"Developers\" devel\n" "\n" " Add the initial rule:\n" " ipa automember-add --type=hostgroup webservers\n" " ipa automember-add --type=group devel\n" "\n" " Add a condition to the rule:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" " ipa automember-add-condition --key=manager --type=group --inclusive-" "regex=^uid=mscott devel\n" "\n" " Add an exclusive condition to the rule to prevent auto assignment:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-" "regex=^web5\\.example\\.com webservers\n" "\n" " Add a host:\n" " ipa host-add web1.example.com\n" "\n" " Add a user:\n" " ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott\n" "\n" " Verify automembership:\n" " ipa hostgroup-show webservers\n" " Host-group: webservers\n" " Description: Web Servers\n" " Member hosts: web1.example.com\n" "\n" " ipa group-show devel\n" " Group name: devel\n" " Description: Developers\n" " GID: 1004200000\n" " Member users: tuser\n" "\n" " Remove a condition from the rule:\n" " ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" "\n" " Modify the automember rule:\n" " ipa automember-mod\n" "\n" " Set the default (fallback) target group:\n" " ipa automember-default-group-set --default-group=webservers --" "type=hostgroup\n" " ipa automember-default-group-set --default-group=ipausers --type=group\n" "\n" " Remove the default (fallback) target group:\n" " ipa automember-default-group-remove --type=hostgroup\n" " ipa automember-default-group-remove --type=group\n" "\n" " Show the default (fallback) target group:\n" " ipa automember-default-group-show --type=hostgroup\n" " ipa automember-default-group-show --type=group\n" "\n" " Find all of the automember rules:\n" " ipa automember-find\n" "\n" " Display a automember rule:\n" " ipa automember-show --type=hostgroup webservers\n" " ipa automember-show --type=group devel\n" "\n" " Delete an automember rule:\n" " ipa automember-del --type=hostgroup webservers\n" " ipa automember-del --type=group devel\n" msgstr "" "\n" "Règle d'auto adhésion.\n" "\n" "Il est possible d'apporter de la clarté dans l'adhésion de systèmes ou\n" "d'utilisateurs en configurant des motifs d'expressions rationnelles " "inclusives\n" "ou exclusives, ce qui permet d'assigner de nouvelles entrées dans un groupe\n" "d'utilisateurs ou de systèmes sur la base d'informations dans les " "attributs.\n" "\n" "Une règle est directement associée avec un groupe par son nom, il est donc\n" "impossible de créer une règle sans le nom du groupe auquel elle est " "associée.\n" "\n" "Une condition est une expression rationnelle utilisée par 389-ds pour\n" "identifier les nouvelles entrées à utiliser dans la règle d'auto-adhésion.\n" "S'il y a correspondance avec une règle d'auto-adhésion, alors l'entrée\n" "est automatiquement ajoutée au groupe d'utilisateurs ou de systèmes.\n" "\n" "Un groupe ou un groupe de systèmes par défaut peut être spécifié pour les\n" "entrées qui ne correspondent à aucune règle. Dans le cas des entrées\n" "utilisateurs, ce groupe sera le groupe de repli car tous les utilisateurs\n" "sont par défaut membres d'un groupe spécifié dans la configuration IPA.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter le groupe d'utilisateurs ou de systèmes initial :\n" " ipa hostgroup-add --desc=\"Web Servers\" webservers\n" " ipa group-add --desc=\"Developers\" devel\n" "\n" " Créer la règle initiale :\n" " ipa automember-add --type=hostgroup webservers\n" " ipa automember-add --type=group devel\n" "\n" " Ajouter une condition à la règle :\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\\\.example\\\\.com webservers\n" " ipa automember-add-condition --key=manager --type=group --inclusive-" "regex=^uid=mscott devel\n" "\n" " Ajouter une condition exclusive à la règle empêchant l'auto-adhésion :\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-" "regex=^web5\\\\.example\\\\.com webservers\n" "\n" " Ajouter un système :\n" " ipa host-add web1.example.com\n" "\n" " Ajouter un utilisateur :\n" " ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott\n" "\n" " Vérifier l'auto-adhésion :\n" " ipa hostgroup-show webservers\n" " Host-group: webservers\n" " Description: Web Servers\n" " Member hosts: web1.example.com\n" "\n" " ipa group-show devel\n" " Group name: devel\n" " Description: Developers\n" " GID: 1004200000\n" " Member users: tuser\n" "\n" " Supprimer une conditition de la règle :\n" " ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" "\n" " Modifier la règle d'auto-adhésion:\n" " ipa automember-mod\n" "\n" " Définir le groupe cible (de repli) par défaut :\n" " ipa automember-default-group-set --default-group=webservers --" "type=hostgroup\n" " ipa automember-default-group-set --default-group=ipausers --type=group\n" "\n" " Supprimer le groupe cible (de repli) par défaut :\n" " ipa automember-default-group-remove --type=hostgroup\n" " ipa automember-default-group-remove --type=group\n" "\n" " Afficher le groupe cible (de repli) par défaut :\n" " ipa automember-default-group-show --type=hostgroup\n" " ipa automember-default-group-show --type=group\n" "\n" " Rechercher toutes les règles d'auto-adhésion :\n" " ipa automember-find\n" "\n" " Afficher une règle d'auto-adhésion :\n" " ipa automember-show --type=hostgroup webservers\n" " ipa automember-show --type=group devel\n" "\n" " Supprimer une règle d'auto-adhésion :\n" " ipa automember-del --type=hostgroup webservers\n" " ipa automember-del --type=group devel\n" msgid "Inclusive Regex" msgstr "Regex inclusive" msgid "Exclusive Regex" msgstr "Regex exclusive" msgid "Attribute Key" msgstr "Clé d'attribut" msgid "" "Attribute to filter via regex. For example fqdn for a host, or manager for a " "user" msgstr "" "Attribut à filtrer via l'expression rationnelle. Par exemple fqdn pour un " "système, ou manager pour un utilisateur" msgid "Grouping Type" msgstr "Type de groupe" msgid "Grouping to which the rule applies" msgstr "Type de groupe auquel la règle s'applique" msgid "Automember Rule" msgstr "Règle d'auto-adhésion" msgid "Auto Membership Rule" msgstr "Règle d'auto-adhésion" msgid "Description" msgstr "Description" msgid "A description of this auto member rule" msgstr "Une description de cette règle d'auto-adhésion" msgid "Default (fallback) Group" msgstr "Groupe par défaut (de repli)" msgid "Default group for entries to land" msgstr "Groupe par défaut pour les nouvelles entrées" #, python-format msgid "Group: %s not found!" msgstr "Groupe : %s introuvable !" #, python-format msgid "%s is not a valid attribute." msgstr "%s n'est pas un attribut valide." msgid "" "\n" " Add an automember rule.\n" " " msgstr "" "\n" " Ajouter une règle d'auto-adhésion.\n" " " #, python-format msgid "Added automember rule \"%(value)s\"" msgstr "Règle d'auto-adhésion \"%(value)s\" ajoutée" msgid "Auto Membership is not configured" msgstr "L'auto-adhésion n'est pas configurée" msgid "" "\n" " Add conditions to an automember rule.\n" " " msgstr "" "\n" " Ajouter des conditions à une règle d'auto-adhésion.\n" " " msgid "Failed to add" msgstr "Échec lors de l'ajout" #, python-format msgid "Added condition(s) to \"%(value)s\"" msgstr "Condition(s) ajoutées à \"%(value)s\"" msgid "Conditions that could not be added" msgstr "Conditions n'ayant pu être ajoutées" msgid "Number of conditions added" msgstr "Nombre de conditions ajoutées" #, python-format msgid "Auto member rule: %s not found!" msgstr "Règle d'auto-adhésion : %s introuvable !" msgid "" "\n" " Override this so we can add completed and failed to the return " "result.\n" " " msgstr "" "\n" " Outrepasser ceci afin de pouvoir préciser les ajouts et échecs aux\n" " résultats renvoyés.\n" " " msgid "" "\n" " Remove conditions from an automember rule.\n" " " msgstr "" "\n" " Supprimer les conditions d'une règle d'auto-adhésion.\n" " " #, python-format msgid "Removed condition(s) from \"%(value)s\"" msgstr "Conditions supprimées de \"%(value)s\"" msgid "Conditions that could not be removed" msgstr "Conditions n'ayant pu être supprimées" msgid "Number of conditions removed" msgstr "Nombre de conditions supprimées" msgid "" "\n" " Override this so we can set completed and failed.\n" " " msgstr "" "\n" " Outrepasser ceci afin de pouvoir préciser les ajouts et échecs.\n" " " msgid "" "\n" " Modify an automember rule.\n" " " msgstr "" "\n" " Modifier une règle d'auto-adhésion.\n" " " #, python-format msgid "Modified automember rule \"%(value)s\"" msgstr "Règle d'auto-adhésion \"%(value)s\" modifiée" msgid "" "\n" " Delete an automember rule.\n" " " msgstr "" "\n" " Supprimer une règle d'auto-adhésion.\n" " " #, python-format msgid "Deleted automember rule \"%(value)s\"" msgstr "Règle d'auto-adhésion \"%(value)s\" supprimée" msgid "" "\n" " Search for automember rules.\n" " " msgstr "" "\n" " Rechercher des règles d'auto-adhésion.\n" " " #, python-format msgid "%(count)d rules matched" msgid_plural "%(count)d rules matched" msgstr[0] "%(count)d règle correspondante" msgstr[1] "%(count)d règles correspondantes" msgid "" "\n" " Display information about an automember rule.\n" " " msgstr "" "\n" " Afficher les informations sur une règle d'auto-adhésion.\n" " " msgid "" "\n" " Set default (fallback) group for all unmatched entries.\n" " " msgstr "" "\n" " Défini le groupe par défaut (de repli) pour toutes les entrées sans " "correspondance.\n" " " msgid "Default (fallback) group for entries to land" msgstr "Groupe par défaut (de repli) où les entrées seront visibles" #, python-format msgid "Set default (fallback) group for automember \"%(value)s\"" msgstr "" "Groupe par défaut (de repli) défini pour l'appartenance automatique " "« %(value)s »" msgid "" "\n" " Remove default (fallback) group for all unmatched entries.\n" " " msgstr "" "\n" " Supprimer le groupe par défaut (de repli) pour toutes les entrées sans " "correspondance.\n" " " #, python-format msgid "Removed default (fallback) group for automember \"%(value)s\"" msgstr "" "Groupe par défaut (de repli) supprimé pour l'appartenance automatique « " "%(value)s »" msgid "No default (fallback) group set" msgstr "Pas de groupe par défaut (de repli) défini" msgid "" "\n" " Display information about the default (fallback) automember groups.\n" " " msgstr "" "\n" " Afficher les informations par défaut (repli) pour les groupes " "d'appartenance automatique.\n" " " msgid "" "\n" "Automount\n" "\n" "Stores automount(8) configuration for autofs(8) in IPA.\n" "\n" "The base of an automount configuration is the configuration file auto." "master.\n" "This is also the base location in IPA. Multiple auto.master configurations\n" "can be stored in separate locations. A location is implementation-specific\n" "with the default being a location named 'default'. For example, you can " "have\n" "locations by geographic region, by floor, by type, etc.\n" "\n" "Automount has three basic object types: locations, maps and keys.\n" "\n" "A location defines a set of maps anchored in auto.master. This allows you\n" "to store multiple automount configurations. A location in itself isn't\n" "very interesting, it is just a point to start a new automount map.\n" "\n" "A map is roughly equivalent to a discrete automount file and provides\n" "storage for keys.\n" "\n" "A key is a mount point associated with a map.\n" "\n" "When a new location is created, two maps are automatically created for\n" "it: auto.master and auto.direct. auto.master is the root map for all\n" "automount maps for the location. auto.direct is the default map for\n" "direct mounts and is mounted on /-.\n" "\n" "An automount map may contain a submount key. This key defines a mount\n" "location within the map that references another map. This can be done\n" "either using automountmap-add-indirect --parentmap or manually\n" "with automountkey-add and setting info to \"-type=autofs :\".\n" "\n" "EXAMPLES:\n" "\n" "Locations:\n" "\n" " Create a named location, \"Baltimore\":\n" " ipa automountlocation-add baltimore\n" "\n" " Display the new location:\n" " ipa automountlocation-show baltimore\n" "\n" " Find available locations:\n" " ipa automountlocation-find\n" "\n" " Remove a named automount location:\n" " ipa automountlocation-del baltimore\n" "\n" " Show what the automount maps would look like if they were in the " "filesystem:\n" " ipa automountlocation-tofiles baltimore\n" "\n" " Import an existing configuration into a location:\n" " ipa automountlocation-import baltimore /etc/auto.master\n" "\n" " The import will fail if any duplicate entries are found. For\n" " continuous operation where errors are ignored, use the --continue\n" " option.\n" "\n" "Maps:\n" "\n" " Create a new map, \"auto.share\":\n" " ipa automountmap-add baltimore auto.share\n" "\n" " Display the new map:\n" " ipa automountmap-show baltimore auto.share\n" "\n" " Find maps in the location baltimore:\n" " ipa automountmap-find baltimore\n" "\n" " Create an indirect map with auto.share as a submount:\n" " ipa automountmap-add-indirect baltimore --parentmap=auto.share --" "mount=sub auto.man\n" "\n" " This is equivalent to:\n" "\n" " ipa automountmap-add-indirect baltimore --mount=/man auto.man\n" " ipa automountkey-add baltimore auto.man --key=sub --info=\"-" "fstype=autofs ldap:auto.share\"\n" "\n" " Remove the auto.share map:\n" " ipa automountmap-del baltimore auto.share\n" "\n" "Keys:\n" "\n" " Create a new key for the auto.share map in location baltimore. This ties\n" " the map we previously created to auto.master:\n" " ipa automountkey-add baltimore auto.master --key=/share --info=auto." "share\n" "\n" " Create a new key for our auto.share map, an NFS mount for man pages:\n" " ipa automountkey-add baltimore auto.share --key=man --info=\"-ro,soft," "rsize=8192,wsize=8192 ipa.example.com:/shared/man\"\n" "\n" " Find all keys for the auto.share map:\n" " ipa automountkey-find baltimore auto.share\n" "\n" " Find all direct automount keys:\n" " ipa automountkey-find baltimore --key=/-\n" "\n" " Remove the man key from the auto.share map:\n" " ipa automountkey-del baltimore auto.share --key=man\n" msgstr "" "\n" "Automount\n" "\n" "Stocke la configuration automount(8) pour autofs(8) dans IPA.\n" "\n" "tLa base d'une configuration automount est le fichier de configuration auto." "master.\n" "C'est aussi le lieu de base dans IPA. Plusieurs configurations auto.master\n" "peuvent être stockées dans plusieurs lieux différents. Un lieu est " "spécifique\n" "à chaque mise en Å“uvre, le lieu par défaut étant 'default'. Par exemple, " "vous\n" "pouvez avoir un lieu par région géographique, par étage, par type, etc.\n" "\n" "Automount a trois types d'objets : les lieux, les cartes et les clés.\n" "\n" "Un lieu définit un jeu de cartes ancrées dans auto.master. Cela permet\n" "de stocker de multiples configurations automount. Un lieu en soi n'est pas\n" "très intéressant, mais est le point de départ d'une nouvelle carte " "automount.\n" "\n" "Une carte est en gros équivalente à un fichier individuel automount et " "fournit\n" "le stockage pour les clés.\n" "\n" "Une clé est un point de montage associé à une carte.\n" "A key is a mount point associated with a map.\n" "\n" "Quand un nouveau lieu est créé, deux cartes sont automatiquement\n" "créées pour lui: auto.master et auto.direct. auto.master est la carte " "racine\n" "pour toutes les cartes automount pour le lieu en question. auto.direct est\n" "la carte par défaut pour les montages directs et est monté sur /-.\n" "\n" "Une carte d'automontage peut contenir une clé de sous-montage. Cette clé\n" "définit un lieu de montage dans la carte qui référence une autre carte.\n" "Cela peut être réalisé par l'utilisation de automountmap-add-indirect --" "parentmap\n" "ou manuellement avec automountkey-add et l'information de configuration\n" "\"-type=autofs :\".\n" "\n" "EXEMPLES:\n" "\n" "Lieux:\n" "\n" " Créer un nouveau lieu nommé \"Baltimore\" :\n" " ipa automountlocation-add baltimore\n" "\n" " Afficher le nouveau lieu :\n" " ipa automountlocation-show baltimore\n" "\n" " Trouver les lieux disponibles :\n" " ipa automountlocation-find\n" "\n" " Supprimer un lieu automount nommé :\n" " ipa automountlocation-del baltimore\n" "\n" " Afficher à quoi ressembleraient les cartes automount si elles étaient dans " "le système de fichiers :\n" " ipa automountlocation-tofiles baltimore\n" "\n" " Importer une configuration existante dans un lieu:\n" " ipa automountlocation-import baltimore /etc/auto.master\n" "\n" " L'import échoera si une entrée dupliquée est trouvée. Pour une\n" " utilisation continue où les erreurs sont ignorées, utiliser l'option\n" " --continue.\n" "\n" "Cartes :\n" "\n" " Créer une nouvelle carte, \"auto.share\" :\n" " ipa automountmap-add baltimore auto.share\n" "\n" " Afficher la nouvelle carte :\n" " ipa automountmap-show baltimore auto.share\n" "\n" " Trouver les cartes du lieu baltimore :\n" " ipa automountmap-find baltimore\n" "\n" " Créer la carte indirecte avec auto.share comme sous-montage :\n" " ipa automountmap-add-indirect baltimore --parentmap=auto.share --" "mount=sub auto.man\n" "\n" " Ce qui est équivalent à :\n" "\n" " ipa automountmap-add-indirect baltimore --mount=/man auto.man\n" " ipa automountkey-add baltimore auto.man --key=sub --info=\"-" "fstype=autofs ldap:auto.share\"\n" "\n" " Supprimer la carte auto.share :\n" " ipa automountmap-del baltimore auto.share\n" "\n" "Clés :\n" "\n" " Créer une nouvelle clé pour la carte auto.share du lieu baltimore. Cela " "associe\n" " la carte précédemment créée à auto.master auto.master:\n" " ipa automountkey-add baltimore auto.master --key=/share --info=auto." "share\n" "\n" " Créer une nouvelle clé dans notre carte auto.share, un montage NFS pour " "les pages de manuel :\n" " ipa automountkey-add baltimore auto.share --key=man --info=\"-ro,soft," "rsize=8192,wsize=8192 ipa.example.com:/shared/man\"\n" "\n" " Trouver toutes les clés de la carte auto.share :\n" " ipa automountkey-find baltimore auto.share\n" "\n" " Trouver toutes les clés automount directes :\n" " ipa automountkey-find baltimore --key=/-\n" "\n" " Supprimer la clé man de la carte auto.share :\n" " ipa automountkey-del baltimore auto.share --key=man\n" msgid "automount location" msgstr "lieu d'automontage" msgid "automount locations" msgstr "lieux d'automontage" msgid "Automount Locations" msgstr "Lieux d'automontage" msgid "Automount Location" msgstr "Lieu d'automontage" msgid "Location" msgstr "Lieu" msgid "Automount location name." msgstr "Nom de lieu automount." msgid "Create a new automount location." msgstr "Créer un nouveau lieu d'automontage" #, python-format msgid "Added automount location \"%(value)s\"" msgstr "Lieu d'automontage \"%(value)s\" ajouté" msgid "Delete an automount location." msgstr "Supprimer un lieu d'automontage." #, python-format msgid "Deleted automount location \"%(value)s\"" msgstr "Lieu d'automontage \"%(value)s\" supprimé" msgid "Display an automount location." msgstr "Afficher un lieu d'automontage." msgid "Search for an automount location." msgstr "Rechercher un lieu d'automontage." #, python-format msgid "%(count)d automount location matched" msgid_plural "%(count)d automount locations matched" msgstr[0] "%(count)d lieu d'automontage correspondants" msgstr[1] "%(count)d lieux d'automontage correspondant" msgid "Generate automount files for a specific location." msgstr "Créer les fichiers d'automontage pour un lieu spécifique." msgid "maps not connected to /etc/auto.master:" msgstr "cartes non connectées à /etc/auto.master :" msgid "Import automount files for a specific location." msgstr "Importer les fichiers d'automontage pour un lieu spécifique." msgid "Master file" msgstr "Fichier maître" msgid "Automount master file." msgstr "Fichier maître automount" msgid "" "Continuous operation mode. Errors are reported but the process continues." msgstr "" "Mode opération continue. Les erreurs seront rapportées mais le processus " "continuera." #, python-format msgid "File %(file)s not found" msgstr "Fichiers %(file)s introuvable" #, python-format msgid "key %(key)s already exists" msgstr "La clé %(key)s existe déjà" #, python-format msgid "map %(map)s already exists" msgstr "La carte %(map)s existe déjà" msgid "automount map" msgstr "carte d'automontage" msgid "automount maps" msgstr "cartes d'automontage" msgid "Map" msgstr "Carte" msgid "Automount map name." msgstr "Nom de carte d'automontage." msgid "Automount Maps" msgstr "Cartes d'automontage" msgid "Automount Map" msgstr "Carte d'automontage" msgid "Create a new automount map." msgstr "Créer une nouvelle carte d'automontage." #, python-format msgid "Added automount map \"%(value)s\"" msgstr "Carte d'automontage \"%(value)s\" ajoutée" msgid "Delete an automount map." msgstr "Supprimer une carte d'automontage." #, python-format msgid "Deleted automount map \"%(value)s\"" msgstr "Carte d'automontage \"%(value)s\" supprimée" msgid "Modify an automount map." msgstr "Modifier une carte d'automontage." #, python-format msgid "Modified automount map \"%(value)s\"" msgstr "Carte d'automontage \"%(value)s\" modifiée" msgid "Search for an automount map." msgstr "Rechercher des cartes d'automontage." #, python-format msgid "%(count)d automount map matched" msgid_plural "%(count)d automount maps matched" msgstr[0] "%(count)d carte d'automontage correspondante" msgstr[1] "%(count)d cartes d'automontage correspondantes" msgid "Display an automount map." msgstr "Afficher une carte d'automontage." msgid "Automount key object." msgstr "Objet clé d'automontage." msgid "automount key" msgstr "clé d'automontage" msgid "automount keys" msgstr "clés d'automontage" msgid "Key" msgstr "Clé" msgid "Automount key name." msgstr "Nom de clé d'automontage." msgid "Mount information" msgstr "Information du montage" msgid "description" msgstr "description" msgid "Automount Keys" msgstr "Clés d'automontage" msgid "Automount Key" msgstr "Clé d'automontage" #, python-format msgid "" "The key,info pair must be unique. A key named %(key)s with info %(info)s " "already exists" msgstr "" "La paire key,info doit être unique. Une clé nommée %(key)s avec " "l'information %(info)s existe déjà." #, python-format msgid "key named %(key)s already exists" msgstr "la clé nommée %(key)s existe déjà" #, python-format msgid "The automount key %(key)s with info %(info)s does not exist" msgstr "La clé automount %(key)s avec l'information %(info)s n'existe pas" #, python-format msgid "" "More than one entry with key %(key)s found, use --info to select specific " "entry." msgstr "" "Plus d'une entrée avec la clé %(key)s trouvée, utilisez --info pour " "sélectionner l'entrée spécifique." msgid "Create a new automount key." msgstr "Créer une nouvelle clé d'automontage." #, python-format msgid "Added automount key \"%(value)s\"" msgstr "Clé d'automontage \"%(value)s\" créée" msgid "Create a new indirect mount point." msgstr "Créer un nouveau point de montage indirect." #, python-format msgid "Added automount indirect map \"%(value)s\"" msgstr "Carte d'automontage indirect \"%(value)s\" créée" msgid "Mount point" msgstr "Point de montage" msgid "Parent map" msgstr "Carte parente" msgid "Name of parent automount map (default: auto.master)." msgstr "Nom de la carte parente (par défaut : auto.master)." msgid "mount point is relative to parent map, cannot begin with /" msgstr "point de montage relatif à la carte parente, ne peut commencer par /" msgid "Delete an automount key." msgstr "Supprimer une clé d'automontage." #, python-format msgid "Deleted automount key \"%(value)s\"" msgstr "Clé d'automontage \"%(value)s\" supprimée" msgid "Modify an automount key." msgstr "Modifier une clé d'automontage." #, python-format msgid "Modified automount key \"%(value)s\"" msgstr "Clé d'automontage \"%(value)s\" modifiée" msgid "New mount information" msgstr "Nouvelle information de montage" msgid "Search for an automount key." msgstr "Rechercher une clé d'automontage." #, python-format msgid "%(count)d automount key matched" msgid_plural "%(count)d automount keys matched" msgstr[0] "%(count)d clé d'automontage correspondante" msgstr[1] "%(count)d clés d'automontage correspondantes" msgid "Display an automount key." msgstr "Afficher une clé d'automontage." msgid "Password" msgstr "Mot de passe" msgid "Failed members" msgstr "Membres en échec" msgid "Member users" msgstr "Utilisateurs membres" msgid "Member groups" msgstr "Groupes membres" msgid "Member of groups" msgstr "Membre des groupes" msgid "Member hosts" msgstr "Systèmes membres" msgid "Member host-groups" msgstr "Groupes de systèmes membres" msgid "Member of host-groups" msgstr "Membre du groupe de systèmes" msgid "Roles" msgstr "Rôles" msgid "Sudo Command Groups" msgstr "Groupes de commandes sudo" msgid "Granting privilege to roles" msgstr "Accord en cours des privilègues aux rôles" msgid "Member netgroups" msgstr "Netgroups membres" msgid "Member of netgroups" msgstr "Membre des netgroups" msgid "Member services" msgstr "Services membres" msgid "Member service groups" msgstr "Groupes de services membres" msgid "Member HBAC service" msgstr "Services HBAC membres" msgid "Member HBAC service groups" msgstr "Groupes de services HBAC membres" msgid "Indirect Member users" msgstr "Utilisateurs membres indirects" msgid "Indirect Member groups" msgstr "Groupes membres indirects" msgid "Indirect Member hosts" msgstr "Systèmes membres indirects" msgid "Indirect Member host-groups" msgstr "Groupes de systèmes membres indirect" msgid "Indirect Member of roles" msgstr "Membres indirect des rôles" msgid "Indirect Member permissions" msgstr "Permission membre indirect" msgid "Indirect Member HBAC service" msgstr "Service HBAC membre indirect" msgid "Indirect Member HBAC service group" msgstr "Groupe de services membre indirect" msgid "Indirect Member netgroups" msgstr "Netgroups membres indirects" msgid "Failed source hosts/hostgroups" msgstr "Systèmes/groupes de systèmes sources en échec" msgid "Failed hosts/hostgroups" msgstr "Systèmes et groupes de système en échec" msgid "Failed users/groups" msgstr "Utilisateurs et groupes en échec" msgid "Failed service/service groups" msgstr "Services et groupes de service en échec" msgid "Failed to remove" msgstr "Échec à la suppression" msgid "Failed RunAs" msgstr "Échec de RunAs" msgid "Failed RunAsGroup" msgstr "Échec de RunAsGroup" msgid "Invalid format. Should be name=value" msgstr "Format invalide. Doit être nom=valeur" msgid "External host" msgstr "Système externe" msgid "An IPA master host cannot be deleted or disabled" msgstr "Un serveur maître IPA ne peut être supprimé ni désactivé" msgid "entry" msgstr "entrée" msgid "entries" msgstr "entrées" msgid "Entry" msgstr "Entrée" #, python-format msgid "container entry (%(container)s) not found" msgstr "entrée conteneur (%(container)s) introuvable" #, python-format msgid "%(parent)s: %(oname)s not found" msgstr "%(parent)s: %(oname)s introuvable" #, python-format msgid "%(pkey)s: %(oname)s not found" msgstr "%(pkey)s: %(oname)s introuvable" #, python-format msgid "%(oname)s with name \"%(pkey)s\" already exists" msgstr "%(oname)s avec le nom \"%(pkey)s\" existe déjà" #, python-format msgid "attribute \"%(attribute)s\" not allowed" msgstr "l'attribut « %(attribute)s » n'est pas autorisé" msgid "" "Set an attribute to a name/value pair. Format is attr=value.\n" "For multi-valued attributes, the command replaces the values already present." msgstr "" "Modifie un attribut avec une paire nom/valeur. Le format est attr=valeur.\n" "Pour les attributs multi-valués, la commande remplace toutes les valeurs " "déjà présentes." msgid "" "Add an attribute/value pair. Format is attr=value. The attribute\n" "must be part of the schema." msgstr "" "Ajouter une paire attribut/valeur. Format : attr=valeur. Les\n" "attributs doivent faire partie du schéma." msgid "" "Delete an attribute/value pair. The option will be evaluated\n" "last, after all sets and adds." msgstr "" "Supprimer une paire attribut/valeur. L'option sera évaluée\n" "en dernier, après les modifications et ajouts." msgid "attribute is not configurable" msgstr "l'attribut n'est pas configurable" msgid "No such attribute on this entry" msgstr "Aucun attribut pour cette entrée" msgid "Suppress processing of membership attributes." msgstr "Arrêt du traitement des attributs d'appartenance." msgid "Continuous mode: Don't stop on errors." msgstr "Mode continu : pas d'arrêt sur erreurs." msgid "Rights" msgstr "Droits" msgid "" "Display the access rights of this entry (requires --all). See ipa man page " "for details." msgstr "" "Affiche les droits d'accès sur cette entrée (requiert --all). Cf. la page de " "manuel de ipa pour plus d'informations." msgid "Rename" msgstr "Renommer" #, python-format msgid "Rename the %(ldap_obj_name)s object" msgstr "Renomme l'objet %(ldap_obj_name)s" msgid "the entry was deleted while being modified" msgstr "cette entrée a été supprimée pendant sa modification" #, python-format msgid "%s" msgstr "%s" #, python-format msgid "member %s" msgstr "%s membre" #, python-format msgid "%s to add" msgstr "%s à ajouter" msgid "Members that could not be added" msgstr "Membres n'ayant pu être ajoutés" msgid "Number of members added" msgstr "Nombre de membres ajoutés" #, python-format msgid "%s to remove" msgstr "%s à supprimer" msgid "Members that could not be removed" msgstr "Membres n'ayant pu être supprimé" msgid "Number of members removed" msgstr "Nombre de membres supprimés" msgid "Primary key only" msgstr "Clé primaire uniquement" #, python-format msgid "Results should contain primary key attribute only (\"%s\")" msgstr "" "Les résultats devraient contenir uniquement des attributs clé primaire " "uniquement (\"%s\")" #, python-format msgid "" "Search for %(searched_object)s with these %(relationship)s %(ldap_object)s." msgstr "" "Recherche de %(searched_object)s avec %(relationship)s %(ldap_object)s." #, python-format msgid "" "Search for %(searched_object)s without these %(relationship)s " "%(ldap_object)s." msgstr "" "Recherche de %(searched_object)s sans %(relationship)s %(ldap_object)s." msgid "Time Limit" msgstr "Limite de durée" msgid "Time limit of search in seconds" msgstr "Limite de durée de la recherche en secondes" msgid "Size Limit" msgstr "Limite de taille" msgid "Maximum number of entries returned" msgstr "Nombre maximal d'entrées renvoyées" msgid "A string searched in all relevant object attributes" msgstr "" "Une chaîne de caractère recherchées dans tous les attributs d'objets " "pertinents" msgid "Nested Methods to execute" msgstr "Commandes imbriquées à exécuter" msgid "" "\n" "IPA certificate operations\n" "\n" "Implements a set of commands for managing server SSL certificates.\n" "\n" "Certificate requests exist in the form of a Certificate Signing Request " "(CSR)\n" "in PEM format.\n" "\n" "The dogtag CA uses just the CN value of the CSR and forces the rest of the\n" "subject to values configured in the server.\n" "\n" "A certificate is stored with a service principal and a service principal\n" "needs a host.\n" "\n" "In order to request a certificate:\n" "\n" "* The host must exist\n" "* The service must exist (or you use the --add option to automatically add " "it)\n" "\n" "SEARCHING:\n" "\n" "Certificates may be searched on by certificate subject, serial number,\n" "revocation reason, validity dates and the issued date.\n" "\n" "When searching on dates the _from date does a >= search and the _to date\n" "does a <= search. When combined these are done as an AND.\n" "\n" "Dates are treated as GMT to match the dates in the certificates.\n" "\n" "The date format is YYYY-mm-dd.\n" "\n" "EXAMPLES:\n" "\n" " Request a new certificate and add the principal:\n" " ipa cert-request --add --principal=HTTP/lion.example.com example.csr\n" "\n" " Retrieve an existing certificate:\n" " ipa cert-show 1032\n" "\n" " Revoke a certificate (see RFC 5280 for reason details):\n" " ipa cert-revoke --revocation-reason=6 1032\n" "\n" " Remove a certificate from revocation hold status:\n" " ipa cert-remove-hold 1032\n" "\n" " Check the status of a signing request:\n" " ipa cert-status 10\n" "\n" " Search for certificates by hostname:\n" " ipa cert-find --subject=ipaserver.example.com\n" "\n" " Search for revoked certificates by reason:\n" " ipa cert-find --revocation-reason=5\n" "\n" " Search for certificates based on issuance date\n" " ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07\n" "\n" "IPA currently immediately issues (or declines) all certificate requests so\n" "the status of a request is not normally useful. This is for future use\n" "or the case where a CA does not immediately issue a certificate.\n" "\n" "The following revocation reasons are supported:\n" "\n" " * 0 - unspecified\n" " * 1 - keyCompromise\n" " * 2 - cACompromise\n" " * 3 - affiliationChanged\n" " * 4 - superseded\n" " * 5 - cessationOfOperation\n" " * 6 - certificateHold\n" " * 8 - removeFromCRL\n" " * 9 - privilegeWithdrawn\n" " * 10 - aACompromise\n" "\n" "Note that reason code 7 is not used. See RFC 5280 for more details:\n" "\n" "http://www.ietf.org/rfc/rfc5280.txt\n" "\n" msgstr "" "\n" "Opérations de certification IPA\n" "\n" "Sont implémentées un ensemble de commandes pour gérer les certificats SSL du " "serveur.\n" "\n" "Les demandes de certification existent sous la forme de « Certificate " "Signing Request (CSR) »\n" "au format PEM.\n" "\n" "La plaque d'identité CA n'utilise que la valeur CN du CSR et force le reste " "du sujet aux\n" "valeurs configurées dans le serveur.\n" "\n" "Un certificat est enregistré avec un principal de service et un principal de " "service\n" "a besoin d'un hôte.\n" "\n" "Donc, pour demander un certificat :\n" "\n" "* l'hôte doit exister\n" "* le service doit exister (ou bien utilisez l'option --add pour l'ajouter " "automatiquement)\n" "\n" "RECHERCHE :\n" "\n" "Les certificats peuvent être recherchés par sujet, numéro de série,\n" "motif de révocation, dates de validité et date d'émission.\n" "\n" "En recherchant par dates, _from effectue une recherche >= à la date et _to\n" "une recherche <= à la date. Si elles sont combinées, elles sont équivalentes " "à un AND.\n" "\n" "Les dates sont traitées comme étant GMT pour correspondre aux dates des " "certificats.\n" "\n" "La date est au format YYYY-mm-dd.\n" "\n" "EXEMPLES :\n" "\n" " Demander un nouveau certificat et ajouter le principal :\n" " ipa cert-request --add --principal=HTTP/lion.example.com example.csr\n" "\n" " Retrouver un certificat existant :\n" " ipa cert-show 1032\n" "\n" " Révoquer un certificat (voir RFC 5280 pour le détail des raisons) :\n" " ipa cert-revoke --revocation-reason=6 1032\n" "\n" " Lever l'état de maintien de révocation d'un certificat :\n" " ipa cert-remove-hold 1032\n" "\n" " Vérifier l'état d'une demande de signature :\n" " ipa cert-status 10\n" "\n" " Rechercher des certificats par nom d'hôte :\n" " ipa cert-find --subject=ipaserver.example.com\n" "\n" " Rechercher les certificats révoqués par motif :\n" " ipa cert-find --revocation-reason=5\n" "\n" " Rechercher les certificats selon la date d'émission :\n" " ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07\n" "\n" "Actuellement IPA émet (ou décline) immédiatement toute demande de " "certificat ;\n" "l'état de la requête n'est donc normalement pas utile. La demande est en " "prévision d'une\n" "utilisation future ou au cas où un CA n'émet pas immédiatement un " "certificat.\n" "\n" "Les motifs de révocation suivants sont pris en charge :\n" "\n" " * 0 - unspecified\n" " * 1 - keyCompromise\n" " * 2 - cACompromise\n" " * 3 - affiliationChanged\n" " * 4 - superseded\n" " * 5 - cessationOfOperation\n" " * 6 - certificateHold\n" " * 8 - removeFromCRL\n" " * 9 - privilegeWithdrawn\n" " * 10 - aACompromise\n" "\n" "Notez que le motif de code 7 n'est pas utilisé. Voir RFC 5280 pour plus de " "détails :\n" "\n" "http://www.ietf.org/rfc/rfc5280.txt\n" "\n" msgid "Failure decoding Certificate Signing Request:" msgstr "Échec dans le décodage du Certificate Signing Request :" msgid "Failure decoding Certificate Signing Request" msgstr "Échec dans le décodage du Certificate Signing Request" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "Échec dans le décodage du Certificate Signing Request : %s" msgid "Submit a certificate signing request." msgstr "Soumettre une demande de signature de certificat." msgid "CSR" msgstr "CSR" msgid "Principal" msgstr "Principal" msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "" "Principal de service pour ce certificat (par ex.: HTTP/test.example.com)" msgid "automatically add the principal if it doesn't exist" msgstr "ajoute automatiquement le principal s'il n'existe pas" msgid "Certificate" msgstr "Certificat" msgid "Subject" msgstr "Subjet" msgid "Issuer" msgstr "Émetteur" msgid "Not Before" msgstr "Pas Avant" msgid "Not After" msgstr "Pas Après" msgid "Fingerprint (MD5)" msgstr "Empreinte (MD5)" msgid "Fingerprint (SHA1)" msgstr "Empreinte (SHA1)" msgid "Serial number" msgstr "Numéro de série" msgid "Serial number (hex)" msgstr "Numéro de série (hex)" msgid "Dictionary mapping variable name to value" msgstr "Nom de variable de correspondance de la valeur" msgid "No hostname was found in subject of request." msgstr "Aucun nom de système n'a été trouvé dans le sujet de la demande." #, python-format msgid "" "hostname in subject of request '%(subject_host)s' does not match principal " "hostname '%(hostname)s'" msgstr "" "Le nom de système sujet de la requête « %(subject_host)s » ne correspond " "pas au nom de système du principal « %(hostname)s »" msgid "The service principal for this request doesn't exist." msgstr "Le principal de service pour cette requête est inexistant" msgid "You need to be a member of the serviceadmin role to add services" msgstr "Vous devez être membre du rôle serviceadmin pour ajouter des services" #, python-format msgid "" "Insufficient 'write' privilege to the 'userCertificate' attribute of entry " "'%s'." msgstr "" "Privilèges en écriture insuffisants sur l'attribut « userCertificate » de " "l'entrée « %s »." #, python-format msgid "no host record for subject alt name %s in certificate request" msgstr "" "pas d'enregistrement de système pour le nom alternatif de système %s sujet " "de la demande de certificat" #, python-format msgid "" "Insufficient privilege to create a certificate with subject alt name '%s'." msgstr "" "Privilèges insuffisants pour créer un certificat avec le nom de sujet " "alternatif « %s »." msgid "Check the status of a certificate signing request." msgstr "Vérifier l'état d'une demande de signature de certificat." msgid "Request id" msgstr "Identifiant de la demande" msgid "Request status" msgstr "État de la demande" msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "Numéro de série en décimal (ou en hexadécimal avec le préfixe 0x)" msgid "Retrieve an existing certificate." msgstr "Récupérer un certificat existant." msgid "Revocation reason" msgstr "Raison de la révocation" msgid "Output filename" msgstr "Nom de fichier de sortie" msgid "File to store the certificate in." msgstr "Fichier dans lequel stocker le certificat." msgid "Revoke a certificate." msgstr "Révoquer un certificat." msgid "Revoked" msgstr "Révoqué" msgid "Reason" msgstr "Raison" msgid "Reason for revoking the certificate (0-10)" msgstr "Raison de révocation du certificat (0-10)" msgid "7 is not a valid revocation reason" msgstr "7 n'est pas une raison de révocation valide" msgid "Take a revoked certificate off hold." msgstr "Prendre un certificat révoqué en attente." msgid "Unrevoked" msgstr "Réintégré" msgid "Error" msgstr "Erreur" msgid "Search for existing certificates." msgstr "Recherche de certificat existant." msgid "minimum serial number" msgstr "plancher des numéros de série" msgid "maximum serial number" msgstr "plafond des numéros de série" msgid "match the common name exactly" msgstr "doit correspondre exactement au nom commun" msgid "Valid not after from this date (YYYY-mm-dd)" msgstr "Valide à partir de cette date (AAAA-mm-jj)" msgid "Valid not after to this date (YYYY-mm-dd)" msgstr "Valide jusque cette date (AAAA-mm-jj)" msgid "Valid not before from this date (YYYY-mm-dd)" msgstr "Invalide avant, à partir de cette date (AAAA-mm-jj)" msgid "Valid not before to this date (YYYY-mm-dd)" msgstr "Invalide avant, jusque cette date (AAAA-mm-jj)" msgid "Issued on from this date (YYYY-mm-dd)" msgstr "Émis le, à partir de cette date (AAAA-mm-jj)" msgid "Issued on to this date (YYYY-mm-dd)" msgstr "Émis le, jusque cette date (AAAA-mm-jj)" msgid "Revoked on from this date (YYYY-mm-dd)" msgstr "Révoqué le, à partir de cette date (AAAA-mm-jj)" msgid "Revoked on to this date (YYYY-mm-dd)" msgstr "Révoqué le, jusque cette date (AAAA-mm-jj)" msgid "Maximum number of certs returned" msgstr "Nombre maximum de certificats renvoyés" msgid "Status" msgstr "État" #, python-format msgid "%(count)d certificate matched" msgid_plural "%(count)d certificates matched" msgstr[0] "%(count)d certificat correspondant" msgstr[1] "%(count)d certificats correspondants" msgid "" "\n" "Server configuration\n" "\n" "Manage the default values that IPA uses and some of its tuning parameters.\n" "\n" "NOTES:\n" "\n" "The password notification value (--pwdexpnotify) is stored here so it will\n" "be replicated. It is not currently used to notify users in advance of an\n" "expiring password.\n" "\n" "Some attributes are read-only, provided only for information purposes. " "These\n" "include:\n" "\n" "Certificate Subject base: the configured certificate subject base,\n" " e.g. O=EXAMPLE.COM. This is configurable only at install time.\n" "Password plug-in features: currently defines additional hashes that the\n" " password will generate (there may be other conditions).\n" "\n" "When setting the order list for mapping SELinux users you may need to\n" "quote the value so it isn't interpreted by the shell.\n" "\n" "EXAMPLES:\n" "\n" " Show basic server configuration:\n" " ipa config-show\n" "\n" " Show all configuration options:\n" " ipa config-show --all\n" "\n" " Change maximum username length to 99 characters:\n" " ipa config-mod --maxusername=99\n" "\n" " Increase default time and size limits for maximum IPA server search:\n" " ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000\n" "\n" " Set default user e-mail domain:\n" " ipa config-mod --emaildomain=example.com\n" "\n" " Enable migration mode to make \"ipa migrate-ds\" command operational:\n" " ipa config-mod --enable-migration=TRUE\n" "\n" " Define SELinux user map order:\n" " ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-" "s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'\n" msgstr "" "\n" "Configuration serveur\n" "\n" "Administrer les valeurs de configuration par défaut qu'utilise IPA ainsi\n" "que certains paramètres.\n" "\n" "NOTES :\n" "\n" "La valeur pour le préavis d'expiration des mots de passe (--pwdexpnotify)\n" "est stockée ici afin de pouvoir être répliquée. Elle n'est pas encore\n" "utilisée pour la notification des utilisateurs avant l'expiration de leur\n" "mot de passe.\n" "\n" "Certains attributs sont en lecture seule, fournis à titre d'information,\n" "incluant :\n" "\n" "Base de sujet de certificat : la base configurée pour les sujets de\n" " certificat, par exemple O=EXAMPLE.COM, configurable uniquement lors\n" " de l'installation.\n" "Fonctionnalités du greffon de gestion des mots de passe : défini\n" " actuellement les types de condensés additionnels qu'un mot de\n" " passe va générer (d'autres conditions peuvent s'appliquer).\n" "\n" "EXEMPLES :\n" "\n" " Afficher la configuration de base du serveur :\n" " ipa config-show\n" "\n" " Afficher toutes les options de configuration :\n" " ipa config-show --all\n" "\n" " Modifier la longueur maximale d'un nom d'utilisateur\n" " à 99 caractères :\n" " ipa config-mod --maxusername=99\n" "\n" " Augmenter les limites de temps et de taille pour les recherches\n" " sur le serveur IPA :\n" " ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000\n" "\n" " Définir le domaine par défaut pour les adresses courriel des " "utilisateurs :\n" " ipa config-mod --emaildomain=example.com\n" "\n" " Activer le mode migration pour rendre la commande \"ipa migrate-ds\" " "opérationelle :\n" " ipa config-mod --enable-migration=TRUE\n" "\n" " Définir l'ordre des utilisateurs SELinux pour les cartes :\n" " ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-" "s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'\n" msgid "searchtimelimit must be -1 or > 1." msgstr "searchtimelimit doit être égal à -1 ou > 1." msgid "configuration options" msgstr "options de configuration" msgid "Configuration" msgstr "Configuration" msgid "Maximum username length" msgstr "Longueur maximale de nom d'utilisateur" msgid "Home directory base" msgstr "Base de répertoire utilisateur" msgid "Default location of home directories" msgstr "Emplacement par défaut des répertoires utilisateur" msgid "Default shell" msgstr "Shell par défaut" msgid "Default shell for new users" msgstr "Interpréteur de commande par défaut pour les nouveaux utilisateurs" msgid "Default users group" msgstr "Groupe utilisateur par défaut" msgid "Default group for new users" msgstr "Groupe utilisateur par défaut pour les nouveaux utilisateurs" msgid "Default e-mail domain" msgstr "Domaine par défaut pour les adresses courriel" msgid "Search time limit" msgstr "Durée de recherche limite" msgid "" "Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)" msgstr "Durée maximale (secondes) pour une recherche (> 0, -1 pour illimité)" msgid "Search size limit" msgstr "Taille limite de recherche" msgid "Maximum number of records to search (-1 is unlimited)" msgstr "Nombre maximal d'entrées à rechercher (-1 pour illimité)" msgid "User search fields" msgstr "Champs de recherche utilisateur" msgid "A comma-separated list of fields to search in when searching for users" msgstr "" "Une liste séparée par des virgules des champs à fouiller lors d'une " "recherche d'utilisateurs" msgid "A comma-separated list of fields to search in when searching for groups" msgstr "" "Une liste séparée par des virgules des champs à fouiller lors d'une " "recherche de groupes" msgid "Enable migration mode" msgstr "Activer le mode migration" msgid "Certificate Subject base" msgstr "Base du sujet de certificat" msgid "Base for certificate subjects (OU=Test,O=Example)" msgstr "Base pour les sujets de certificat (OU=Test,O=Example)" msgid "Default group objectclasses" msgstr "Classes d'objets par défaut pour les groupes" msgid "Default group objectclasses (comma-separated list)" msgstr "" "Classes d'objets par défaut pour les groupes (liste séparée par des virgules)" msgid "Default user objectclasses" msgstr "Classes d'objets par défaut pour les utilisateurs" msgid "Default user objectclasses (comma-separated list)" msgstr "" "Classes d'objets par défaut pour les utilisateurs (liste séparée par des " "virgules)" msgid "Password Expiration Notification (days)" msgstr "Notification avant expiration de mot de passe (jours)" msgid "Number of days's notice of impending password expiration" msgstr "Nombre de jours de préavis d'expiration de mot de passe" msgid "Password plugin features" msgstr "Fonctionnalités du greffon de gestion des mots de passe" msgid "Extra hashes to generate in password plug-in" msgstr "" "Hachages supplémentaires à générer dans le greffon de gestion des mots de " "passe" msgid "SELinux user map order" msgstr "Ordre des utilisateurs SELinux pour les cartes" msgid "Order in increasing priority of SELinux users, delimited by $" msgstr "" "Ordre des utilisateurs SELinux pour les cartes, par priorité croissante, " "délimités par $" msgid "Default SELinux user" msgstr "Utilisateur SELinux par défaut" msgid "Default SELinux user when no match is found in SELinux map rule" msgstr "" "Utilisateur SELinux par défaut quand il n'y a aucune correspondance dans la " "règle de carte SELinux" msgid "Default PAC types" msgstr "Types de PAC par défaut" msgid "Default types of PAC supported for services" msgstr "Types de PAC par défaut pris en charge pour les services" msgid "Modify configuration options." msgstr "Modifier les options de configuration." msgid "The group doesn't exist" msgstr "Le groupe n'existe pas" #, python-format msgid "attribute \"%s\" not allowed" msgstr "attribut \"%s\" interdit" msgid "May not be empty" msgstr "Ne peut être vide" #, python-format msgid "%(obj)s default attribute %(attr)s would not be allowed!" msgstr "L'attribut par défaut %(attr)s de %(obj)s ne serait pas autorisé !" msgid "A list of SELinux users delimited by $ expected" msgstr "Une liste des utilisateurs SELinux délimitée par $ est attendue" #, python-format msgid "SELinux user '%(user)s' is not valid: %(error)s" msgstr "L'utilisateur SELinux « %(user)s » n'est pas valide : %(error)s" msgid "SELinux user map default user not in order list" msgstr "La carte des utilisateurs par défaut n'est pas une liste ordonnée" msgid "Show the current configuration." msgstr "Afficher la configuration actuelle." msgid "" "\n" "Group to Group Delegation\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "Group to Group Delegations grants the members of one group to update a set\n" "of attributes of members of another group.\n" "\n" "EXAMPLES:\n" "\n" " Add a delegation rule to allow managers to edit employee's addresses:\n" " ipa delegation-add --attrs=street --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones. Add postalCode to the list:\n" " ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " Display our updated rule:\n" " ipa delegation-show \"managers edit employees' street\"\n" "\n" " Delete a rule:\n" " ipa delegation-del \"managers edit employees' street\"\n" msgstr "" "\n" "Délégation de groupe à groupe\n" "\n" "Une permission permet une délégation fine des autorisations. Les règles de\n" "contrôle d'accès, ou les instructions (ACI), accordent la possibilité aux\n" "permissions de réaliser certaines tâches comme l'ajout d'utilisateur, la\n" "modification d'un groupe, etc.\n" "\n" "La délégation de groupe à groupe permet aux membres d'un groupe de modifier\n" "un jeu d'attributs de membres d'un autre groupe.\n" "\n" "EXEMPLES:\n" "\n" " Ajouter une règle de délégation permettant aux managers de modifier\n" " les adresses des employés :\n" " ipa delegation-add --attrs=street --group=managers --" "membergroup=employees 'les managers modifient les adresses des employés'\n" "\n" "\n" " Lors de la gestion d'une liste d'attributs, vous devez toujours spécifier\n" " la liste complète des attributs, y compris les attributs existants.\n" " Ajouter postalCode à la liste :\n" " ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --" "membergroup=employees 'les managers modifient les adresses des employés'\n" "\n" "\n" " Afficher la règle modifiée :\n" " ipa delegation-show 'les managers modifient les adresses des employés'\n" "\n" " Supprimer une règle :\n" " ipa delegation-del 'les managers modifient les adresses des employés'\n" msgid "delegation" msgstr "délégation" msgid "delegations" msgstr "délégations" msgid "Delegations" msgstr "Délégations" msgid "Delegation" msgstr "Délégation" msgid "Delegation name" msgstr "Nom de la délégation" msgid "Permissions to grant (read, write). Default is write." msgstr "Permissions à accorder (read, write). La valeur par défaut est write." msgid "Attributes to which the delegation applies" msgstr "Attributs auxquels la délégation s'applique" msgid "Member user group" msgstr "Membre du groupe d'utilisateurs" msgid "User group to apply delegation to" msgstr "Groupe d'utilisateur auquel appliquer la délégation" msgid "Add a new delegation." msgstr "Ajouter une nouvelle délégation." #, python-format msgid "Added delegation \"%(value)s\"" msgstr "Délégation \"%(value)s\" ajoutée" msgid "Delete a delegation." msgstr "Supprimer une délégation." #, python-format msgid "Deleted delegation \"%(value)s\"" msgstr "Délégation \"%(value)s\" supprimée" msgid "Modify a delegation." msgstr "Modifier une délégation." #, python-format msgid "Modified delegation \"%(value)s\"" msgstr "Délégation \"%(value)s\" modifiée" msgid "Search for delegations." msgstr "Rechercher des délégations." #, python-format msgid "%(count)d delegation matched" msgid_plural "%(count)d delegations matched" msgstr[0] "%(count)d délégation correspondante" msgstr[1] "%(count)d délégations correspondantes" msgid "Display information about a delegation." msgstr "Afficher les informations sur une délégation." msgid "" "\n" "Domain Name System (DNS)\n" "\n" "Manage DNS zone and resource records.\n" "\n" "\n" "USING STRUCTURED PER-TYPE OPTIONS\n" "\n" "There are many structured DNS RR types where DNS data stored in LDAP server\n" "is not just a scalar value, for example an IP address or a domain name, but\n" "a data structure which may be often complex. A good example is a LOC record\n" "[RFC1876] which consists of many mandatory and optional parts (degrees,\n" "minutes, seconds of latitude and longitude, altitude or precision).\n" "\n" "It may be difficult to manipulate such DNS records without making a mistake\n" "and entering an invalid value. DNS module provides an abstraction over " "these\n" "raw records and allows to manipulate each RR type with specific options. " "For\n" "each supported RR type, DNS module provides a standard option to manipulate\n" "a raw records with format ---rec, e.g. --mx-rec, and special " "options\n" "for every part of the RR structure with format ---, e.g.\n" "--mx-preference and --mx-exchanger.\n" "\n" "When adding a record, either RR specific options or standard option for a " "raw\n" "value can be used, they just should not be combined in one add operation. " "When\n" "modifying an existing entry, new RR specific options can be used to change\n" "one part of a DNS record, where the standard option for raw value is used\n" "to specify the modified value. The following example demonstrates\n" "a modification of MX record preference from 0 to 1 in a record without\n" "modifying the exchanger:\n" "ipa dnsrecord-mod --mx-rec=\"0 mx.example.com.\" --mx-preference=1\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add new zone:\n" " ipa dnszone-add example.com --name-server=ns \\\n" " --admin-email=admin@example.com \\\n" " --ip-address=10.0.0.1\n" "\n" " Add system permission that can be used for per-zone privilege delegation:\n" " ipa dnszone-add-permission example.com\n" "\n" " Modify the zone to allow dynamic updates for hosts own records in realm " "EXAMPLE.COM:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE\n" "\n" " This is the equivalent of:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " --update-policy=\"grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM " "krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;\"\n" "\n" " Modify the zone to allow zone transfers for local network only:\n" " ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8\n" "\n" " Add new reverse zone specified by network IP address:\n" " ipa dnszone-add --name-from-ip=80.142.15.0/24 \\\n" " --name-server=ns.example.com.\n" "\n" " Add second nameserver for example.com:\n" " ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com\n" "\n" " Add a mail server for example.com:\n" " ipa dnsrecord-add example.com @ --mx-rec=\"10 mail1\"\n" "\n" " Add another record using MX record specific options:\n" " ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2\n" "\n" " Add another record using interactive mode (started when dnsrecord-add, " "dnsrecord-mod,\n" " or dnsrecord-del are executed with no options):\n" " ipa dnsrecord-add example.com @\n" " Please choose a type of DNS resource record to be added\n" " The most common types for this type of zone are: NS, MX, LOC\n" "\n" " DNS resource record type: MX\n" " MX Preference: 30\n" " MX Exchanger: mail3\n" " Record name: example.com\n" " MX record: 10 mail1, 20 mail2, 30 mail3\n" " NS record: nameserver.example.com., nameserver2.example.com.\n" "\n" " Delete previously added nameserver from example.com:\n" " ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com.\n" "\n" " Add LOC record for example.com:\n" " ipa dnsrecord-add example.com @ --loc-rec=\"49 11 42.4 N 16 36 29.6 E " "227.64m\"\n" "\n" " Add new A record for www.example.com. Create a reverse record in " "appropriate\n" " reverse zone as well. In this case a PTR record \"2\" pointing to www." "example.com\n" " will be created in zone 15.142.80.in-addr.arpa.\n" " ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse\n" "\n" " Add new PTR record for www.example.com\n" " ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com.\n" "\n" " Add new SRV records for LDAP servers. Three quarters of the requests\n" " should go to fast.example.com, one quarter to slow.example.com. If neither\n" " is available, switch to backup.example.com.\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 3 389 fast.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 1 389 slow.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"1 1 389 backup." "example.com\"\n" "\n" " The interactive mode can be used for easy modification:\n" " ipa dnsrecord-mod example.com _ldap._tcp\n" " No option to modify specific record provided.\n" " Current DNS record contents:\n" "\n" " SRV record: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 " "backup.example.com\n" "\n" " Modify SRV record '0 3 389 fast.example.com'? Yes/No (default No):\n" " Modify SRV record '0 1 389 slow.example.com'? Yes/No (default No): y\n" " SRV Priority [0]: (keep the default value)\n" " SRV Weight [1]: 2 (modified value)\n" " SRV Port [389]: (keep the default value)\n" " SRV Target [slow.example.com]: (keep the default value)\n" " 1 SRV record skipped. Only one value per DNS record type can be modified " "at one time.\n" " Record name: _ldap._tcp\n" " SRV record: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 " "389 slow.example.com\n" "\n" " After this modification, three fifths of the requests should go to\n" " fast.example.com and two fifths to slow.example.com.\n" "\n" " An example of the interactive mode for dnsrecord-del command:\n" " ipa dnsrecord-del example.com www\n" " No option to delete specific record provided.\n" " Delete all? Yes/No (default No): (do not delete all records)\n" " Current DNS record contents:\n" "\n" " A record: 1.2.3.4, 11.22.33.44\n" "\n" " Delete A record '1.2.3.4'? Yes/No (default No):\n" " Delete A record '11.22.33.44'? Yes/No (default No): y\n" " Record name: www\n" " A record: 1.2.3.4 (A record 11.22.33.44 has been " "deleted)\n" "\n" " Show zone example.com:\n" " ipa dnszone-show example.com\n" "\n" " Find zone with \"example\" in its domain name:\n" " ipa dnszone-find example\n" "\n" " Find records for resources with \"www\" in their name in zone example.com:\n" " ipa dnsrecord-find example.com www\n" "\n" " Find A records with value 10.10.0.1 in zone example.com\n" " ipa dnsrecord-find example.com --a-rec=10.10.0.1\n" "\n" " Show records for resource www in zone example.com\n" " ipa dnsrecord-show example.com www\n" "\n" " Delegate zone sub.example to another nameserver:\n" " ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5\n" " ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com.\n" "\n" " If global forwarder is configured, all requests to sub.example.com will be\n" " routed through the global forwarder. To change the behavior for example." "com\n" " zone only and forward the request directly to ns.sub.example.com., global\n" " forwarding may be disabled per-zone:\n" " ipa dnszone-mod example.com --forward-policy=none\n" "\n" " Forward all requests for the zone external.com to another nameserver using\n" " a \"first\" policy (it will send the queries to the selected forwarder and " "if\n" " not answered it will use global resolvers):\n" " ipa dnszone-add external.com\n" " ipa dnszone-mod external.com --forwarder=10.20.0.1 \\\n" " --forward-policy=first\n" "\n" " Delete zone example.com with all resource records:\n" " ipa dnszone-del example.com\n" "\n" " Resolve a host name to see if it exists (will add default IPA domain\n" " if one is not included):\n" " ipa dns-resolve www.example.com\n" " ipa dns-resolve www\n" "\n" "\n" "GLOBAL DNS CONFIGURATION\n" "\n" "DNS configuration passed to command line install script is stored in a " "local\n" "configuration file on each IPA server where DNS service is configured. " "These\n" "local settings can be overridden with a common configuration stored in LDAP\n" "server:\n" "\n" " Show global DNS configuration:\n" " ipa dnsconfig-show\n" "\n" " Modify global DNS configuration and set a list of global forwarders:\n" " ipa dnsconfig-mod --forwarder=10.0.0.1\n" msgstr "" "\n" "Domain Name System (DNS)\n" "\n" "Gestion des zones DNS et des enregistrements de ressource.\n" "\n" "UTILISATION D'OPTIONS STRUCTURÉES PAR TYPE\n" "\n" "Il existe de nombreux types structurés de RR DNS où les données DNS " "stockées\n" "dans le serveur LDAP ne sont pas seulement des valeurs scalaires, par " "exemple\n" "une adresse IP ou un nom de domaine, mais une structure de données qui " "peut \n" "être souvent complexe. Un bon exemple est un enregistrement LOC [RFC1876] " "qui \n" "se compose de plusieurs parties obligatoires et facultatives (degrés, " "minutes,\n" "secondes de latitude et de longitude, altitude ou précision).\n" "\n" "Il peut être difficile de manipuler ces enregistrements DNS sans se tromper\n" "et entrer une valeur invalide. Le module DNS fournit une abstraction sur " "ces\n" "enregistrements bruts et permet de manipuler chaque type RR avec des " "options \n" "spécifiques. Pour chaque type RR pris en charge, le module DNS fournit une \n" "option standard pour manipuler les enregistrements bruts avec un format\n" "---rec, par exemple --mx-rec, ainsi que des options spéciales\n" "pour chaque partie de la structure RR avec le format ---,\n" "par exemple, --mx-preference and --mx-exchanger.\n" "\n" "Lors de l'ajout d'un enregistrement, les options standards ou les options\n" "spécifiques peuvent au choix être utilisées, mais ne peuvent être combinées\n" "au sein de la même commande. Lors de la modification d'une entrée " "existante,\n" "de nouvelles options spécifiques RR peuvent être utilisés pour changer une \n" "partie d'un enregistrement DNS, où l'option standard pour la valeur brute " "est\n" "utilisée pour spécifier la valeur modifiée. L'exemple suivant montre une \n" "modification de la préférence du MX de 0 à 1 dans un enregistrement\n" "existant, sans modifier le MX lui-même :\n" "ipa dnsrecord-mod --mx-rec=\"0 mx.example.com.\" --mx-preference=1\n" "\n" "\n" "EXEMPLES :\n" "\n" " Ajouter une nouvelle zone :\n" " ipa dnszone-add example.com --name-server=ns \\\n" " --admin-email=admin@example.com \\\n" " --ip-address=10.0.0.1\n" " Ajouter une permission ssytème afin de pouvoir utiliser la délégation\n" " de privilège par zone :\n" " ipa dnszone-add-permission example.com\n" "\n" " Modifier la zone pour permettre les mises à jour dynamiques des\n" " enregistrements des systèmes du domaine EXAMPLE.COM :\n" " ipa dnszone-mod example.com --dynamic-update=TRUE\n" "\n" " Ceci est l'équivalent de :\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " --update-policy=\"grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM " "krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;\"\n" "\n" " Modifier la zone afin de permettre les transferts de zone pour les réseaux\n" " locaux uniquement :\n" " ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8\n" "\n" " Ajouter une nouvelle zone inverse spécifiée par son adresse de réseau :\n" " ipa dnszone-add --name-from-ip=80.142.15.0/24 \\\n" " --name-server=ns.example.com.\n" "\n" " Ajouter un second serveur de nom pour example.com:\n" " ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com\n" "\n" " Ajouter un serveur de messagerie pour example.com:\n" " ipa dnsrecord-add example.com @ --mx-rec=\"10 mail1\"\n" "\n" " Ajouter un nouvel enregistrement avec les options spécifiques MX :\n" " ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2\n" "\n" " Ajouter un nouvel enregistrement grâce au mode interactif (lancé lorsque " "dnsrecord-add,\n" " dnsrecord-mod ou dnsrecord-del sont exécutés sans options) :\n" " ipa dnsrecord-add example.com @\n" " Merci de choisir un type de ressource DNS pour l'enregistrement à " "ajouter.\n" " Les types les plus courants pour ce type de zone sont : NS, MX, LOC\n" "\n" " Type de ressource d'enregistrement DNS : MX\n" " Préférence MX : 30\n" " Échangeur MX : mail3\n" " Nom d'enregistrement : example.com\n" " Enregistrement MX : 10 mail1, 20 mail2, 30 mail3\n" " Enregistrement NS : nameserver.example.com., nameserver2.example.com.\n" "\n" " Supprimer un serveur de nom précédemment défini pour example.com:\n" " ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com.\n" "\n" " Ajouter un enregistrement LOC pour example.com:\n" " ipa dnsrecord-add example.com @ --loc-rec=\"49 11 42.4 N 16 36 29.6 E " "227.64m\"\n" "\n" " Ajouter un nouvel enregistrement A pour www.example.com. Créer aussi un\n" " enregistrement inverse. Dans ce cas, un enregistrement PTR « 2 » pointant\n" " vers www.example.com sera créé dans la zone 15.142.80.in-addr.arpa.\n" " ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse\n" "\n" " Ajouter un nouvel enregistrement PTR pour www.example.com\n" " ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com.\n" "\n" " Ajouter de nouveaux enregistrement SRV pour les serveurs LDAP. Les trois " "quarts\n" " des requêtes doivent aller sur fast.example.com, un quart sur slow.example." "com.\n" " Si aucune n'est disponible, basculer sur backup.example.com.\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 3 389 fast.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 1 389 slow.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"1 1 389 backup." "example.com\"\n" "\n" " Le mode interactif peut être utilisé pour faciliter les modifications :\n" " ipa dnsrecord-mod example.com _ldap._tcp\n" " Aucune option spécifiées pour modifier l'enregistrement demandé.\n" " Contenu actuel de l'enregistrement DNS :\n" "\n" " Enregistrement SRV : 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 " "1 389 backup.example.com\n" "\n" " Modifier l'enregistrement SRV '0 3 389 fast.example.com'? Oui/Non (par " "défaut Non): \n" " Modifier l'enregistrement SRV '0 1 389 slow.example.com'? Oui/Non (Par " "défaut Non): o\n" " Priorité SRV [0]: (garder la valeur par défaut)\n" " Poids SRV [1]: 2 (modifier la valeur)\n" " Port SRV [389]: (garder la valeur par défaut)\n" " Cible SRV [slow.example.com]: (garder la valeur par défaut)\n" " 1 enregistrement SRV sauté. Seule une valeur par enregistrement DNS peut " "être modifié un instant donné.\n" " Nom d'enregistrement : _ldap._tcp\n" " Enregistrement SRV : 0 3 389 fast.example.com, 1 1 389 backup.example." "com, 0 2 389 slow.example.com\n" "\n" " Après cette modification, trois cinquièmes des requêtes devraient aller " "sur\n" " fast.example.com et deux cinquièmes sur slow.example.com.\n" "\n" " Un exemple d'utilisation du mode interactif pour la commande dnsrecord-" "del :\n" " ipa dnsrecord-del example.com www\n" " Pas d'option fournie pour supprimer un enregistrement spécifique.\n" " Tout supprimer ? Oui/Non (Défault: Non): (ne pas détruire tous les " "enregistrements)\n" " Contenu actuel de l'enregistrement DNS :\n" "\n" " Enregistrement A : 1.2.3.4, 11.22.33.44\n" "\n" " Supprimer l'enregistrement A '1.2.3.4'? Oui/Non (par défaut: Non): \n" " Supprimer l'enregistrement A '11.22.33.44'? Oui/Non (par défaut: Non): o\n" " Nom de l'enregistrement : www\n" " Enregistrement A : 1.2.3.4 (Enregistrement A " "11.22.33.44 a été supprimé)\n" "\n" " Afficher la zone example.com :\n" " ipa dnszone-show example.com\n" "\n" " Chercher les zones contenant \"example\" dans le nom de domaine :\n" " ipa dnszone-find example\n" "\n" " Chercher les enregistrements pour les ressources dont le nom contient \"www" "\" dans la zone example.com :\n" " ipa dnsrecord-find example.com www\n" "\n" " Chercher les enregistrements A de valeur 10.10.0.1 dans la zone example." "com\n" " ipa dnsrecord-find example.com --a-rec=10.10.0.1\n" "\n" " Afficher les enregistrements pour la ressource www dans la zone example." "com\n" " ipa dnsrecord-show example.com www\n" "\n" " Déléguer la zone sub.example à un autre serveur de noms :\n" " ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5\n" " ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com.\n" "\n" " Si un fournisseur global est configuré, toutes les requêtes à sub.example." "com\n" " seront routées vers le fournisseur global. Pour modifier le comportement " "pour\n" " la zone example.com uniquement et transférer les requêtes directement à\n" " ns.sub.example.com., la transmission globale peut être désactivée zone par " "zone :\n" " ipa dnszone-mod example.com --forward-policy=none\n" "\n" " Transmet toutes les requêtes pour la zone external.com vers un autre " "serveur de\n" " noms primant (first) sur le global (il envoie les requêtes au fournisseur \n" " sélectionné, et s'il n'a pas de réponse, utilise le transmetteur global) :\n" " ipa dnszone-add external.com\n" " ipa dnszone-mod external.com --forwarder=10.20.0.1 \\\n" " --forward-policy=first\n" "\n" " Supprimer la zone example.com avec toutes ses ressources :\n" " ipa dnszone-del example.com\n" "\n" " Résoudre un nom de système afin de vérifier son existence (ajout " "automatique du nom de domaine IPA\n" " si non spécifié) :\n" " ipa dns-resolve www.example.com\n" " ipa dns-resolve www\n" "\n" "\n" "CONFIGURATION DNS GLOBALE\n" "\n" "La configuration DNS passée au script d'installation en ligne de commande " "est \n" "stockée dans un fichier de configuration local sur chaque serveur IPA lors " "de \n" "la configuration du service DNS. Cette configuration locale peut être " "surchargée\n" "par une configuration stockée dans l'annuaire LDAP :\n" "\n" " Afficher la configuration DNS globale :\n" " ipa dnsconfig-show\n" "\n" " Modifier la configuration DNS globale et définit une liste de transmetteurs " "globaux :\n" " ipa dnsconfig-mod --forwarder=10.0.0.1\n" #, python-format msgid "invalid IP address version (is %(value)d, must be %(required_value)d)!" msgstr "" "version d'adresse IP invalide (est %(value)d, doit être %(required_value)d) !" msgid "invalid IP address format" msgstr "format d'adresse IP invalide" msgid "invalid IP network format" msgstr "format de réseau IP invalide" msgid "each ACL element must be terminated with a semicolon" msgstr "chaque élément d'ACL doit se terminer par un point-virgule" msgid "invalid address format" msgstr "format d'adresse invalide" #, python-format msgid "invalid domain-name: %s" msgstr "nom de domaine invalide : %s" #, python-format msgid "%(port)s is not a valid port" msgstr "%(port)s n'est pas un port valide" #, python-format msgid "DNS reverse zone for IP address %(addr)s not found" msgstr "Zone DNS inverse introuvable pour l'adresse IP %(addr)s" #, python-format msgid "DNS zone %(zone)s not found" msgstr "Zone DNS %(zone)s introuvable" #, python-format msgid "IP address %(ip)s is already assigned in domain %(domain)s." msgstr "L'adresse IP %(ip)s est déjà assignée au domaine %(domain)s." #, python-format msgid "" "Reverse record for IP address %(ip)s already exists in reverse zone %(zone)s." msgstr "" "L'enregistrement inverse pour l'adresse IP %(ip)s existe déjà dans la zone " "inverse %(zone)s." #, python-format msgid "%s record" msgstr "enregistrement %s" #, python-format msgid "Raw %s records" msgstr "Enregistrements %s bruts" #, python-format msgid "%s Record" msgstr "Enregistrement %s" #, python-format msgid "(see RFC %s for details)" msgstr "(cf. RFC %s pour plus de détails)" #, python-format msgid "'%s' is a required part of DNS record" msgstr "'%s' est une partie requise d'un enregistrement DNS" msgid "Invalid number of parts!" msgstr "Nombre de parties invalide !" #, python-format msgid "DNS RR type \"%s\" is not supported by bind-dyndb-ldap plugin" msgstr "" "Le type DNS RR \"%s\" n'est pas pris en compte par le greffon bind-dyndb-ldap" #, python-format msgid "format must be specified as \"%(format)s\" %(rfcs)s" msgstr "le format doit être spécificié comme \"%(format)s\" %(rfcs)s" msgid "Create reverse" msgstr "Créer enregistrement inverse" msgid "Create reverse record for this IP Address" msgstr "Créer l'enregistrement inverse pour cette adresse IP" #, python-format msgid "Cannot create reverse record for \"%(value)s\": %(exc)s" msgstr "" "Impossible de créer l'enregistrement inverse pour « %(value)s » : %(exc)s" msgid "IP Address" msgstr "Adresse IP" msgid "Record data" msgstr "Données d'enregistrement" msgid "Subtype" msgstr "Sous-type" msgid "Hostname" msgstr "Nom de système" msgid "Certificate Type" msgstr "Type de certificat" msgid "Key Tag" msgstr "Étiquette de clé" msgid "Algorithm" msgstr "Algorithme" msgid "Certificate/CRL" msgstr "Certificat/CRL" msgid "A hostname which this alias hostname points to" msgstr "Un nom de système vers lequel cet alias pointe" msgid "Target" msgstr "Cible" msgid "Digest Type" msgstr "Type de condensé" msgid "Digest" msgstr "Condensé" msgid "Flags" msgstr "Drapeaux" msgid "Protocol" msgstr "Protocole" msgid "Public Key" msgstr "Clé publique" msgid "Preference" msgstr "Préférence" msgid "Preference given to this exchanger. Lower values are more preferred" msgstr "" "Préférence donnée à cet échangeur. Les valeurs inférieures sont les " "préférées." msgid "Exchanger" msgstr "Échangeur" msgid "A host willing to act as a key exchanger" msgstr "Un système prêt à jouer le rôle d'échangeur de clé" msgid "Degrees Latitude" msgstr "Degrés latitude" msgid "Minutes Latitude" msgstr "Minutes latitude" msgid "Seconds Latitude" msgstr "Secondes latitude" msgid "Direction Latitude" msgstr "Direction latitude" msgid "Degrees Longitude" msgstr "Degrés de Longitude" msgid "Minutes Longitude" msgstr "Minutes de Longitude" msgid "Seconds Longitude" msgstr "Secondes de Longitude" msgid "Direction Longitude" msgstr "Direction de Longitude" msgid "Altitude" msgstr "Altitude" msgid "Size" msgstr "Taille" msgid "Horizontal Precision" msgstr "Précision horizontale" msgid "Vertical Precision" msgstr "Précision verticale" msgid "" "format must be specified as\n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (degrees latitude)\n" " d2: [0 .. 180] (degrees longitude)\n" " m1, m2: [0 .. 59] (minutes latitude/longitude)\n" " s1, s2: [0 .. 59.999] (seconds latitude/longitude)\n" " alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters)\n" " siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)\n" " See RFC 1876 for details" msgstr "" "le format doit être spécifié comme \n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (degrés latitude)\n" " d2: [0 .. 180] (degrés longitude)\n" " m1, m2: [0 .. 59] (minutes latitude/longitude)\n" " s1, s2: [0 .. 59.999] (secondes latitude/longitude)\n" " alt: [-100000.00 .. 42849672.95] par .01 (altitude en mètres)\n" " siz, hp, vp: [0 .. 90000000.00] (taille/précision en mètres)\n" " Cf. RFC 1876 plus les détails" #, python-format msgid "'%(required)s' must not be empty when '%(name)s' is set" msgstr "'%(required)s' ne doit pas être vide lorsque '%(name)s' est défini" msgid "A host willing to act as a mail exchanger" msgstr "Un système désirant agir comme échangeur de messagerie" msgid "" "format must be specified as \"NEXT TYPE1 [TYPE2 [TYPE3 [...]]]\" (see RFC " "4034 for details)" msgstr "" "le format doit être spécifié comme \"NEXT TYPE1 [TYPE2 [TYPE3 [...]]]\" (cf. " "RFC 4034 pour les détails)" msgid "Next Domain Name" msgstr "Nom de domaine suivant" msgid "Type Map" msgstr "Type de carte" msgid "flags must be one of \"S\", \"A\", \"U\", or \"P\"" msgstr "" "les drapeaux doivent avoir une valeur parmi \"S\", \"A\", \"U\", ou \"P\"" msgid "Order" msgstr "Ordre" msgid "Service" msgstr "Service" msgid "Regular Expression" msgstr "Expression rationnelle" msgid "Replacement" msgstr "Remplacement" msgid "The hostname this reverse record points to" msgstr "Le nom de système vers lequel cet enregistrement inverse pointe" msgid "Priority" msgstr "Priorité" msgid "Weight" msgstr "Poids" msgid "Port" msgstr "Port" msgid "" "The domain name of the target host or '.' if the service is decidedly not " "available at this domain" msgstr "" "Le nom de domaine du système cible ou '.' si le service n'est décidément pas " "disponible dans ce domaine" msgid "the value does not follow \"YYYYMMDDHHMMSS\" time format" msgstr "la valeur n'est pas au format temporel \"YYYYMMDDHHMMSS\"" msgid "Type Covered" msgstr "Type couvert" msgid "Labels" msgstr "Étiquettes" msgid "Original TTL" msgstr "TTL originel" msgid "Signature Expiration" msgstr "Expiration de signature" msgid "Signature Inception" msgstr "Création de signature" msgid "Signer's Name" msgstr "Signataire" msgid "Signature" msgstr "Signature" msgid "Fingerprint Type" msgstr "Type d'empreinte" msgid "Fingerprint" msgstr "Empreinte" msgid "Text Data" msgstr "Donnée texte" msgid "Records" msgstr "Enregistrements" msgid "Record type" msgstr "Type d'enregistrement" #, python-format msgid "Nameserver '%(host)s' does not have a corresponding A/AAAA record" msgstr "" "Le serveur de noms '%(host)s' n'a pas d'enregistrement A/AAAA correspondant" msgid "Managedby permission" msgstr "Permission managedby" msgid "DNS zone" msgstr "Zone DNS" msgid "DNS zones" msgstr "Zones DNS" msgid "DNS Zones" msgstr "Zones DNS" msgid "DNS Zone" msgstr "Zone DNS" msgid "Zone name" msgstr "Nom de zone" msgid "Zone name (FQDN)" msgstr "Nom de zone (FQDN)" msgid "Reverse zone IP network" msgstr "Zone inverse de réseau IP" msgid "IP network to create reverse zone name from" msgstr "Réseau IP à partir duquel créer une zone inverse" msgid "Authoritative nameserver" msgstr "Serveur de nom faisant autorité" msgid "Authoritative nameserver domain name" msgstr "Nom de domaine du serveur de nom faisant autorité" msgid "Administrator e-mail address" msgstr "Adresse courriel de l'administrateur" msgid "SOA serial" msgstr "Numéro de série SOA" msgid "SOA record serial number" msgstr "Numéro de série de l'enregistrement SOA" msgid "SOA refresh" msgstr "Actualisation SOA" msgid "SOA record refresh time" msgstr "Durée d'actualisation de l'enregistrement SOA" msgid "SOA retry" msgstr "ré-essai SOA" msgid "SOA record retry time" msgstr "Durée avant nouvelle tentative de l'enregistrement SOA" msgid "SOA expire" msgstr "Expiration SOA" msgid "SOA record expire time" msgstr "Durée d'expiration de l'enregistrement SOA" msgid "SOA minimum" msgstr "Minimum SOA" msgid "How long should negative responses be cached" msgstr "Durée de maintien en cache des réponses négatives" msgid "SOA time to live" msgstr "Durée de vie SOA" msgid "SOA record time to live" msgstr "Durée de vie de l'enregistrement SOA" msgid "SOA class" msgstr "Classe SOA" msgid "SOA record class" msgstr "Classe de l'enregistrement SOA " msgid "BIND update policy" msgstr "Politique de mise à jour BIND" msgid "Active zone" msgstr "Zone active" msgid "Is zone active?" msgstr "La zone est-elle active ?" msgid "Dynamic update" msgstr "Mise à jour dynamique" msgid "Allow dynamic updates." msgstr "Autorise les mises à jour dynamiques." msgid "Allow query" msgstr "Autoriser requête" msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "issue queries" msgstr "" "Liste séparée par des points-virgules d'adresses IP de systèmes ou de " "réseaux autorisés à effectuer des requêtes" msgid "Allow transfer" msgstr "Autoriser le transfert" msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "transfer the zone" msgstr "" "Liste séparée par des points-virgules d'adresses IP de systèmes ou de " "réseaux autorisés à effectuer des transferts" msgid "Zone forwarders" msgstr "Transmetteurs de zone" msgid "" "Per-zone forwarders. A custom port can be specified for each forwarder using " "a standard format \"IP_ADDRESS port PORT\"" msgstr "" "Transmetteur par zone. Un port personnalisé peut être spécifié pour chaque " "transmetteur en utilisant le format standard « adresse_IP port PORT »" msgid "Forward policy" msgstr "Politique de transmission" msgid "" "Per-zone conditional forwarding policy. Set to \"none\" to disable " "forwarding to global forwarder for this zone. In that case, conditional zone " "forwarders are disregarded." msgstr "" "Politique de tranmission conditionnelle par zone. Mettre à « none » pour " "désactiver la transmission à un transmetteur global pour cette zone. Dans ce " "cas, les transmetteurs de zone conditionnels sont ignorés." msgid "Allow PTR sync" msgstr "Autoriser la synchronisation PTR" msgid "" "Allow synchronization of forward (A, AAAA) and reverse (PTR) records in the " "zone" msgstr "" "Autoriser la synchronisation des enregistrements directs (A, AAAA) et " "inverses (PTR) dans la zone" msgid "Create new DNS zone (SOA record)." msgstr "Créer une nouvelle zone DNS (enregistrement SOA)." msgid "Force" msgstr "Forcer" msgid "Force DNS zone creation even if nameserver is not resolvable." msgstr "" "Forcer la création de la zone DNS zone même si le serveur de nom n'est pas " "résolvable." msgid "Add forward record for nameserver located in the created zone" msgstr "" "Ajouter un enregistrement direct pour les serveurs de noms situés dans la " "zone créée" msgid "Nameserver IP address" msgstr "Adresse IP du serveur de noms" msgid "DNS is not configured" msgstr "Le DNS n'est pas configuré" msgid "Nameserver address is not a domain name" msgstr "L'adresse du serveur de nom n'est pas un nom de domaine" msgid "Nameserver for reverse zone cannot be a relative DNS name" msgstr "Le serveur de nom pour la zone inverse ne peut être un nom DNS relatif" msgid "Nameserver DNS record is created for for forward zones only" msgstr "" "L'enregistrement DNS du serveur de nom est créé pour les zones directes " "uniquement" msgid "Nameserver DNS record is created only for nameservers in current zone" msgstr "" "L'enregistrement DNS du serveur de nom est créé pour les serveurs de noms " "uniquement" msgid "Delete DNS zone (SOA record)." msgstr "Supprimer la zone DNS (enregistrement SOA)." #, python-format msgid "Deleted DNS zone \"%(value)s\"" msgstr "Zone DNS « %(value)s » supprimée" msgid "Modify DNS zone (SOA record)." msgstr "Modifier la zone DNS (enregistrement SOA)." msgid "Force nameserver change even if nameserver not in DNS" msgstr "" "Forcer un changement de serveur de nom même si le serveur de nom n'est pas " "dans le DNS" msgid "Search for DNS zones (SOA records)." msgstr "Rechercher des zones DNS (enregistrements SOA)." msgid "Forward zones only" msgstr "Zones forward uniquement" msgid "Search for forward zones only" msgstr "Rechercher des zones forward uniquement" msgid "Display information about a DNS zone (SOA record)." msgstr "" "Afficher les informations au sujet d'une zone DNS (enregistrement SOA)." msgid "Disable DNS Zone." msgstr "Désactiver la zone DNS." #, python-format msgid "Disabled DNS zone \"%(value)s\"" msgstr "Zone DNS \"%(value)s\" désactivée" msgid "Enable DNS Zone." msgstr "Activer la zone DNS." #, python-format msgid "Enabled DNS zone \"%(value)s\"" msgstr "Zone DNS \"%(value)s\" activée" msgid "Add a permission for per-zone access delegation." msgstr "Ajouter une permission pour la délégation par zone." #, python-format msgid "Added system permission \"%(value)s\"" msgstr "Permission système « %(value)s » ajoutée" msgid "Remove a permission for per-zone access delegation." msgstr "Supprimer une permission pour la délégation par zone." #, python-format msgid "Removed system permission \"%(value)s\"" msgstr "Permission système « %(value)s » supprimée" msgid "DNS resource record" msgstr "Enregistrement de ressource DNS" msgid "DNS resource records" msgstr "Enregistrements de ressources DNS" msgid "DNS Resource Records" msgstr "Enregistrements de ressources DNS" msgid "DNS Resource Record" msgstr "Enregistrement de ressources DNS" msgid "Record name" msgstr "Nom d'enregistrement" msgid "Time to live" msgstr "Durée de vie" msgid "Class" msgstr "Classe" msgid "DNS class" msgstr "Classe DNS" msgid "Structured" msgstr "Structuré" msgid "Parse all raw DNS records and return them in a structured way" msgstr "" "Analyser tous les enregistrements DNS et les renvoyer sous forme structurée" #, python-format msgid "" "Reverse zone for PTR record should be a sub-zone of one the following fully " "qualified domains: %s" msgstr "" "La zone inverse pour l'enregistrement PTR doit être une sous-zone de l'un " "des domaines suivants pleinement qualifiés : %s" #, python-format msgid "" "Reverse zone %(name)s requires exactly %(count)d IP address components, " "%(user_count)d given" msgstr "" "La zone inverse %(name)s requiert exactement %(count)d composants d'adresses " "IP, %(user_count)d donnés" msgid "only one CNAME record is allowed per name (RFC 2136, section 1.1.5)" msgstr "" "seul un unique enregistrement CNAME est autorisé par nom (RFC 2136, section " "1.1.5)" msgid "" "CNAME record is not allowed to coexist with any other record (RFC 1034, " "section 3.6.2)" msgstr "" "Un enregistrement CNAME ne peut coexister avec aucun autre enregistrement " "(RFC 1034, section 3.6.2)" msgid "only one DNAME record is allowed per name (RFC 6672, section 2.4)" msgstr "" "seuil un unique enregistrement DNAME est autorisé par nom (RFC 6672, section " "2.4)" msgid "" "DNAME record is not allowed to coexist with an NS record except when located " "in a zone root record (RFC 6672, section 2.3)" msgstr "" "Un enregistrement DNAME ne peut coexister avec un enregistrement NS, sauf " "lorsqu'il se trouve dans l'enregistrement racine de la zone (RFC 6672, " "section 2.3)" msgid "Add new DNS resource record." msgstr "Ajouter un nouvel enregistrement de ressources DNS." msgid "force NS record creation even if its hostname is not in DNS" msgstr "" "forcer la création d'un enregistrement NS même si le nom du système n'est " "pas dans le DNS" msgid "Please choose a type of DNS resource record to be added" msgstr "Merci de choisir un type de ressource d'enregistrement DNS à ajouter" #, python-format msgid "The most common types for this type of zone are: %s\n" msgstr "Les types les plus courants pour ce type de zone sont : %s\n" msgid "DNS resource record type" msgstr "Type de ressource d'enregistrement DNS" #, python-format msgid "Invalid or unsupported type. Allowed values are: %s" msgstr "Type invalide ou non pris en compte. Les valeurs autorisées sont : %s" #, python-format msgid "Raw value of a DNS record was already set by \"%(name)s\" option" msgstr "" "La valeur brute d'un enregistrement DNS a déjà été configurée par l'option « " "%(name)s »" msgid "Modify a DNS resource record." msgstr "Modifier un enregistrement de ressources DNS." msgid "DNS zone root record cannot be renamed" msgstr "L'enregistrement racine de la zone DNS ne peut être renommé" msgid "DNS records can be only updated one at a time" msgstr "Les enregistrements DNS ne peuvent être modifiés qu'un seul à la fois" msgid "No option to modify specific record provided." msgstr "Aucune option fournie pour modifier un enregistrement spécifique." msgid "Current DNS record contents:\n" msgstr "Contenu actuel de l'enregistrement DNS :\n" #, python-format msgid "Modify %(name)s '%(value)s'?" msgstr "Modifier '%(value)s' pour %(name)s ?" #, python-format msgid "" "%(count)d %(type)s record skipped. Only one value per DNS record type can be " "modified at one time." msgid_plural "" "%(count)d %(type)s records skipped. Only one value per DNS record type can " "be modified at one time." msgstr[0] "" "%(count)d enregistrement %(type)s sauté. Une seule valeur par enregistrement " "DNS peut être modifiée à la fois." msgstr[1] "" "%(count)d enregistrements %(type)s sautés. Une seule valeur par " "enregistrement DNS peut être modifiée à la fois." #, python-format msgid "Deleted record \"%(value)s\"" msgstr "Enregistrement \"%(value)s\" supprimé" msgid "Delete DNS resource record." msgstr "Supprimer un enregistrement de ressources DNS." msgid "" "Neither --del-all nor options to delete a specific record provided.\n" "Command help may be consulted for all supported record types." msgstr "" "Aucune option de suppression d'un enregistrement spécifique ni --del-all " "n'ont été indiqués.\n" "Merci de consulter l'aide pour connaître tous les types d'enregistrements " "supportés." msgid "Delete all associated records" msgstr "Supprimer les enregistrements associés" #, python-format msgid "Zone record '%s' cannot be deleted" msgstr "L'enregistrement '%s' de zone ne peut être supprimé" msgid "No option to delete specific record provided." msgstr "Pas d'option fournie pour supprimer un enregistrement spécifique." msgid "Delete all?" msgstr "Tout supprimer ?" #, python-format msgid "Delete %(name)s '%(value)s'?" msgstr "Supprimer '%(value)s' pour %(name)s ?" msgid "Display DNS resource." msgstr "Afficher un enregistrement de ressources DNS." msgid "Search for DNS resources." msgstr "Rechercher des enregistrements de ressources DNS." msgid "Resolve a host name in DNS." msgstr "Résoudre un nom de système DNS." #, python-format msgid "Found '%(value)s'" msgstr "'%(value)s' trouvé." #, python-format msgid "Host '%(host)s' not found" msgstr "Système '%(host)s' introuvable" msgid "DNS configuration options" msgstr "Options de configuration DNS" msgid "DNS Global Configuration" msgstr "Configuration DNS globale" msgid "Global forwarders" msgstr "Transmetteurs globaux" msgid "" "Global forwarders. A custom port can be specified for each forwarder using a " "standard format \"IP_ADDRESS port PORT\"" msgstr "" "Transmetteurs globaux. Un port personnalisé peut être spécifié pour chaque " "transmetteur en utilisant le format standard « adresse_IP port PORT »" msgid "" "Global forwarding policy. Set to \"none\" to disable any configured global " "forwarders." msgstr "" "Politique de transmission globale. Mettre à « none » pour désactiver tout " "transmetteur global configuré." msgid "Allow synchronization of forward (A, AAAA) and reverse (PTR) records" msgstr "" "Autoriser la synchronisation des enregistrements directs (A, AAAA) et " "inverses (PTR)" msgid "Zone refresh interval" msgstr "Intervalle de rafraichissement de zone" msgid "An interval between regular polls of the name server for new DNS zones" msgstr "" "Intervalle entre deux sondages réguliers du serveur de noms pour les " "nouvelles zones" msgid "Global DNS configuration is empty" msgstr "La configuration globale DNS est vide" msgid "Modify global DNS configuration." msgstr "Modifier la configuration DNS globale." msgid "Show the current global DNS configuration." msgstr "Afficher la configuration DNS globale." msgid "" "\n" "Groups of users\n" "\n" "Manage groups of users. By default, new groups are POSIX groups. You\n" "can add the --nonposix option to the group-add command to mark a new group\n" "as non-POSIX. You can use the --posix argument with the group-mod command\n" "to convert a non-POSIX group into a POSIX group. POSIX groups cannot be\n" "converted to non-POSIX groups.\n" "\n" "Every group must have a description.\n" "\n" "POSIX groups must have a Group ID (GID) number. Changing a GID is\n" "supported but can have an impact on your file permissions. It is not " "necessary\n" "to supply a GID when creating a group. IPA will generate one automatically\n" "if it is not provided.\n" "\n" "EXAMPLES:\n" "\n" " Add a new group:\n" " ipa group-add --desc='local administrators' localadmins\n" "\n" " Add a new non-POSIX group:\n" " ipa group-add --nonposix --desc='remote administrators' remoteadmins\n" "\n" " Convert a non-POSIX group to posix:\n" " ipa group-mod --posix remoteadmins\n" "\n" " Add a new POSIX group with a specific Group ID number:\n" " ipa group-add --gid=500 --desc='unix admins' unixadmins\n" "\n" " Add a new POSIX group and let IPA assign a Group ID number:\n" " ipa group-add --desc='printer admins' printeradmins\n" "\n" " Remove a group:\n" " ipa group-del unixadmins\n" "\n" " To add the \"remoteadmins\" group to the \"localadmins\" group:\n" " ipa group-add-member --groups=remoteadmins localadmins\n" "\n" " Add multiple users to the \"localadmins\" group:\n" " ipa group-add-member --users=test1 --users=test2 localadmins\n" "\n" " Remove a user from the \"localadmins\" group:\n" " ipa group-remove-member --users=test2 localadmins\n" "\n" " Display information about a named group.\n" " ipa group-show localadmins\n" "\n" "External group membership is designed to allow users from trusted domains\n" "to be mapped to local POSIX groups in order to actually use IPA resources.\n" "External members should be added to groups that specifically created as\n" "external and non-POSIX. Such group later should be included into one of " "POSIX\n" "groups.\n" "\n" "An external group member is currently a Security Identifier (SID) as defined " "by\n" "the trusted domain. When adding external group members, it is possible to\n" "specify them in either SID, or DOM\\name, or name@domain format. IPA will " "attempt\n" "to resolve passed name to SID with the use of Global Catalog of the trusted " "domain.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" msgstr "" "\n" "Groupes d'utilisateurs\n" "\n" "Gérer des groupes d'utilisateurs. Par défaut, les nouveaux groupes sont des " "groupes POSIX.\n" "Vous pouvez ajouter l'option --nonposix à la commande group-add pour marquer " "un nouveau groupe\n" "comme non-POSIX. Vous pouvez utiliser --posix argument avec la commande " "group-mod\n" "pour convertir un groupe non-POSIX en groupe POSIX. Des groupes POSIX ne " "peuvent pas être\n" "convertis en groupes non-POSIX.\n" "\n" "Chaque groupe doit avoir une description.\n" "\n" "Les groupes POSIX doivent avoir un numéro d'ID de groupe (GID). Modifier un " "GID est\n" "accepté mais peut avoir un impact sur vos droits d'accès aux fichiers. Il " "n'est pas nécessaire\n" "de fournir un GID à la création d'un groupe. IPA en générera un " "automatiquement\n" "s'il n'est pas indiqué.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau groupe :\n" " ipa group-add --desc='local administrators' localadmins\n" "\n" " Ajouter un nouveau groupe non-POSIX :\n" " ipa group-add --nonposix --desc='remote administrators' remoteadmins\n" "\n" " Convertir un groupe non-POSIX en groupe POSIX :\n" " ipa group-mod --posix remoteadmins\n" "\n" " Ajouter un nouveau groupe POSIX avec un numéro d'ID de groupe donné :\n" " ipa group-add --gid=500 --desc='unix admins' unixadmins\n" "\n" " Ajouter un nouveau groupe POSIX et laisser IPA assigner un numéro d'ID de " "groupe :\n" " ipa group-add --desc='printer admins' printeradmins\n" "\n" " Supprimer un groupe :\n" " ipa group-del unixadmins\n" "\n" " Ajouter le groupe « remoteadmins » au groupe « localadmins » :\n" " ipa group-add-member --groups=remoteadmins localadmins\n" "\n" " Ajouter plusieurs utilisateurs au groupe « localadmins » :\n" " ipa group-add-member --users=test1 --users=test2 localadmins\n" "\n" " Supprimer un utilisateur du groupe « localadmins » :\n" " ipa group-remove-member --users=test2 localadmins\n" "\n" " Afficher des informations à propos d'un groupe donné :\n" " ipa group-show localadmins\n" "\n" "L'appartenance d'un groupe externe est conçue pour permettre aux utilisateur " "de domaines de confiance\n" "d'être assimilés aux groupes POSIX locaux en vue d'utiliser réellement les " "ressources IPA.\n" "Des membres externes peuvent être ajoutés aux groupes spécifiquement crées " "comme\n" "externes et non-POSIX. Un tel groupe peut plus tard être incorporé dans un " "des groupes\n" "POSIX\n" "\n" "Un membre de groupe externe est actuellement identifié par un « Security " "Identifier (SID) » tel que défini pour\n" "le domaine de confiance. En ajoutant des membres de groupe externe, il est " "possible de les\n" "définir au format, soit SID, soit DOM\\name, soit name@domain. IPA essayera\n" "de résoudre le nom passé en SID en se servant du « Global Catalog » des " "domaines de confiance.\n" "\n" "Exemple:\n" "\n" "1. Créer un groupe par assimilation au domaine de confiance « admins » et à " "leur groupe POSIX local :\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Ajouter l'identifiant de sécurité de « Domain Admins » au " "groupe\n" " externe ad_admins_external :\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Autoriser des membres du groupe ad_admins_external à être associés au " "groupe POSIX ad_admins :\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. Lister les membres externes du groupe ad_admins_external pour voir leur " "SID :\n" "\n" " ipa group-show ad_admins_external\n" msgid "group" msgstr "groupe" msgid "groups" msgstr "groupes" msgid "User Groups" msgstr "Groupes d'utilisateurs" msgid "User Group" msgstr "Groupe d'Utilisateurs" msgid "Group name" msgstr "Nom du groupe" msgid "Group description" msgstr "Description du groupe" msgid "GID" msgstr "GID" msgid "GID (use this option to set it manually)" msgstr "GID (utiliser cette option pour le positionner manuellement)" msgid "External member" msgstr "Member externe" msgid "Members of a trusted domain in DOM\\name or name@domain form" msgstr "Membres d'un domaine approuvé sous la forme DOM\\nom ou nom@domaine" msgid "Create a new group." msgstr "Créer un nouveau groupe." #, python-format msgid "Added group \"%(value)s\"" msgstr "Groupe \"%(value)s\" créé" msgid "Create as a non-POSIX group" msgstr "Créer en tant que groupe non-POSIX" msgid "Allow adding external non-IPA members from trusted domains" msgstr "" "Autoriser l'ajout de membres externes non-IPA depuis les domaines approuvés" msgid "Delete group." msgstr "Supprimer un groupe." #, python-format msgid "Deleted group \"%(value)s\"" msgstr "Groupe \"%(value)s\" supprimé" msgid "privileged group" msgstr "groupe avec privilèges" msgid "Modify a group." msgstr "Modifier un groupe." #, python-format msgid "Modified group \"%(value)s\"" msgstr "Groupe \"%(value)s\" modifié" msgid "change to a POSIX group" msgstr "Transformer en groupe POSIX" msgid "change to support external non-IPA members from trusted domains" msgstr "" "modifier afin de permettre des membres externes non-IPA depuis les domaines " "approuvés" msgid "Search for groups." msgstr "Rechercher des groupes." #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "%(count)d groupe correspondant" msgstr[1] "%(count)d groupes correspondants" msgid "search for private groups" msgstr "rechercher des groupes privés" msgid "search for POSIX groups" msgstr "rechercher des groupes POSIX" msgid "" "search for groups with support of external non-IPA members from trusted " "domains" msgstr "" "rechercher des groupes autorisant des membres externes non-IPA depuis les " "domaines approuvés" msgid "search for non-POSIX groups" msgstr "rechercher des groupes non-POSIX" msgid "Display information about a named group." msgstr "Afficher les informations d'un groupe nommé." msgid "Add members to a group." msgstr "Ajouter des membres à un groupe." msgid "" "Cannot perform external member validation without Samba 4 support installed. " "Make sure you have installed server-trust-ad sub-package of IPA on the server" msgstr "" "Impossible de réaliser la validation de membre externe sans installer la " "prise en charge Samba 4. Assurez-vous d'avoir installé le sous-paquet " "IPAserver-trust-ad sub-package sur le serveur" msgid "" "Cannot perform join operation without own domain configured. Make sure you " "have run ipa-adtrust-install on the IPA server first" msgstr "" "Impossible de rejoindre un domaine sans avoir au préalable configuré son " "propre domaine. Assurez-vous d'avoir d'abord lancé ipa-adtrust-install sur " "le serveur" msgid "Remove members from a group." msgstr "Supprimer des membres d'un groupe." msgid "Detach a managed group from a user." msgstr "Détacher un groupe administré d'un utilisateur." #, python-format msgid "Detached group \"%(value)s\" from user \"%(value)s\"" msgstr "Groupe \"%(value)s\" détaché de l'utilisateur \"%(value)s\"" msgid "not allowed to modify user entries" msgstr "interdit de modifier les entrées d'utilisateurs" msgid "not allowed to modify group entries" msgstr "interdit de modifier les entrées de groupe" msgid "Not a managed group" msgstr "Pas un groupe administré" msgid "" "\n" "Host-based access control\n" "\n" "Control who can access what services on what hosts. You\n" "can use HBAC to control which users or groups can\n" "access a service, or group of services, on a target host.\n" "\n" "You can also specify a category of users and target hosts.\n" "This is currently limited to \"all\", but might be expanded in the\n" "future.\n" "\n" "Target hosts in HBAC rules must be hosts managed by IPA.\n" "\n" "The available services and groups of services are controlled by the\n" "hbacsvc and hbacsvcgroup plug-ins respectively.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that grants all users access to the host \"server" "\" from\n" " anywhere:\n" " ipa hbacrule-add --usercat=all test1\n" " ipa hbacrule-add-host --hosts=server.example.com test1\n" "\n" " Display the properties of a named HBAC rule:\n" " ipa hbacrule-show test1\n" "\n" " Create a rule for a specific service. This lets the user john access\n" " the sshd service on any machine from any machine:\n" " ipa hbacrule-add --hostcat=all john_sshd\n" " ipa hbacrule-add-user --users=john john_sshd\n" " ipa hbacrule-add-service --hbacsvcs=sshd john_sshd\n" "\n" " Create a rule for a new service group. This lets the user john access\n" " the FTP service on any machine from any machine:\n" " ipa hbacsvcgroup-add ftpers\n" " ipa hbacsvc-add sftp\n" " ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers\n" " ipa hbacrule-add --hostcat=all john_ftp\n" " ipa hbacrule-add-user --users=john john_ftp\n" " ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp\n" "\n" " Disable a named HBAC rule:\n" " ipa hbacrule-disable test1\n" "\n" " Remove a named HBAC rule:\n" " ipa hbacrule-del allow_server\n" msgstr "" "\n" "Contrôle d'accès des systèmes (HBAC)\n" "\n" "HBAC (Host-based acces control) permet de contrôler qui peut accéder\n" "à quels services sur quels systèmes, et d'où. Il est possible\n" "d'utiliser le système HBAC afin de contrôler quels utilisateurs ou\n" "groupes d'un système source peuvent accéder quels services, ou groupes\n" "de services, sur un système cible.\n" "\n" "Vous pouvez aussi spécifier une catégorie d'utilisateur, de systèmes\n" "cibles et de systèmes sources. La seule catégorie existante pour le\n" "moment est \"all\", mais pourra être étendu dans le futur.\n" "\n" "Les systèmes sources et cibles des règles HBAC doivent être des systèmes\n" "administrés par IPA.\n" "\n" "Les services et groupes de services disponibles sont gérés respectivement\n" "par les greffons hbacsvc and hbacsvcgroup.\n" "\n" "EXEMPLES:\n" "\n" " Créer une règle \"test1\" autorisant tous les utilisateurs à accéder\n" " le serveur « server » depuis n'importe où :\n" " ipa hbacrule-add --usercat=all test1\n" " ipa hbacrule-add-host --hosts=server.example.com test1\n" "\n" " Afficher les propriétés d'une règle HBAC nommée :\n" " ipa hbacrule-show test1\n" "\n" " Créer une règle pour un service spécifique, permettant à\n" " l'utilisateur john d'accéder au service sshd sur toute machine depuis\n" " n'importe quelle machine :\n" " ipa hbacrule-add --hostcat=all john_sshd\n" " ipa hbacrule-add-user --users=john john_sshd\n" " ipa hbacrule-add-service --hbacsvcs=sshd john_sshd\n" "\n" " Créer une règle pour un nouveau groupe de services, permettant à\n" " l'utilisateur john d'accéder au service FTP de toute machine depuis\n" " n'importe quelle machine.\n" " ipa hbacsvcgroup-add ftpers\n" " ipa hbacsvc-add sftp\n" " ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers\n" " ipa hbacrule-add --hostcat=all john_ftp\n" " ipa hbacrule-add-user --users=john john_ftp\n" " ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp\n" "\n" " Désactiver une règle HBAC nommée :\n" " ipa hbacrule-disable test1\n" "\n" " Supprimer une règle HBAC nommée :\n" " ipa hbacrule-del allow_server\n" "\n" msgid "Host-based access control commands" msgstr "Commandes de contrôle d'accès des systèmes" msgid "The deny type has been deprecated." msgstr "Le type deny est obsolète." msgid "HBAC rule" msgstr "Règle HBAC" msgid "HBAC rules" msgstr "Règles HBAC" msgid "HBAC Rules" msgstr "Règles HBAC" msgid "HBAC Rule" msgstr "Règle HBAC" msgid "Rule name" msgstr "Nom de règle" msgid "Rule type (allow)" msgstr "Type de règle (allow)" msgid "Rule type" msgstr "Type de règle" msgid "User category" msgstr "Catégorie d'utilisateur" msgid "User category the rule applies to" msgstr "Catégorie d'utilisateur sur laquelle la règle s'applique" msgid "Host category" msgstr "Catégorie de système" msgid "Host category the rule applies to" msgstr "Catégorie de système sur laquelle la règle s'applique" msgid "Service category" msgstr "Catégorie de service" msgid "Service category the rule applies to" msgstr "Catégorie de service sur laquelle la règle s'applique" msgid "Enabled" msgstr "Activée" msgid "Users" msgstr "Utilisateurs" msgid "Hosts" msgstr "Systèmes" msgid "Host Groups" msgstr "Groupes de systèmes" msgid "Services" msgstr "Services" msgid "Service Groups" msgstr "Groupes de services" msgid "Create a new HBAC rule." msgstr "Créer une nouvelle règle HBAC." #, python-format msgid "Added HBAC rule \"%(value)s\"" msgstr "Règle HBAC \"%(value)s\" ajoutée" msgid "Delete an HBAC rule." msgstr "Supprimer une règle HBAC." #, python-format msgid "Deleted HBAC rule \"%(value)s\"" msgstr "Règle HBAC \"%(value)s\" supprimée" msgid "Modify an HBAC rule." msgstr "Modifier une règle HBAC." #, python-format msgid "Modified HBAC rule \"%(value)s\"" msgstr "Règle HBAC \"%(value)s\" modifiée" msgid "user category cannot be set to 'all' while there are allowed users" msgstr "" "la catégorie d'utilisateur ne peut être définie à 'all' alors qu'il y a des " "utilisateurs autorisés" msgid "host category cannot be set to 'all' while there are allowed hosts" msgstr "" "la catégorie système ne peut être définie à 'all' alors qu'il reste des " "systèmes autorisés" msgid "" "service category cannot be set to 'all' while there are allowed services" msgstr "" "la catégorie service ne peut être définie à 'all' alors qu'il reste des " "systèmes autorisés" msgid "Search for HBAC rules." msgstr "Rechercher des règles HBAC." #, python-format msgid "%(count)d HBAC rule matched" msgid_plural "%(count)d HBAC rules matched" msgstr[0] "%(count)d règle HBAC correspondante" msgstr[1] "%(count)d règles HBAC correspondantes" msgid "Display the properties of an HBAC rule." msgstr "Afficher les propriétés d'une règle HBAC." msgid "Enable an HBAC rule." msgstr "Activer une règle HBAC." #, python-format msgid "Enabled HBAC rule \"%(value)s\"" msgstr "Règle HBAC \"%(value)s\" activée" msgid "Disable an HBAC rule." msgstr "Désactiver une règle HBAC." #, python-format msgid "Disabled HBAC rule \"%(value)s\"" msgstr "Règle HBAC \"%(value)s\" désactivée" msgid "Access time" msgstr "Horaire d'accès" msgid "Add users and groups to an HBAC rule." msgstr "Ajouter des utilisateurs et groupes à une règle HBAC." msgid "users cannot be added when user category='all'" msgstr "" "des utilisateurs ne peuvent être ajoutés quand la catégorie utilisateurs est " "définie à 'all'" msgid "Remove users and groups from an HBAC rule." msgstr "Retirer des utilisateurs et groupes d'une règle HBAC." msgid "Add target hosts and hostgroups to an HBAC rule." msgstr "Ajouter des systèmes et groupes de systèmes cibles à une règle HBAC." msgid "hosts cannot be added when host category='all'" msgstr "" "des systèmes ne peuvent être ajoutés quand la catégorie systèmes est définie " "à 'all'" msgid "Remove target hosts and hostgroups from an HBAC rule." msgstr "Retirer des systèmes et groupes de systèmes cibles d'une règle HBAC." msgid "Add services to an HBAC rule." msgstr "Ajouter des services à une règle HBAC." msgid "services cannot be added when service category='all'" msgstr "" "aucun service ne peut être ajouté quand la catégorie de services sources est " "à « all »" msgid "Remove service and service groups from an HBAC rule." msgstr "Ajouter des services et groupes de services d'une règle HBAC." msgid "" "\n" "HBAC Services\n" "\n" "The PAM services that HBAC can control access to. The name used here\n" "must match the service name that PAM is evaluating.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service:\n" " ipa hbacsvc-add tftp\n" "\n" " Modify an existing HBAC service:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Search for HBAC services. This example will return two results, the FTP\n" " service and the newly-added tftp service:\n" " ipa hbacsvc-find ftp\n" "\n" " Delete an HBAC service:\n" " ipa hbacsvc-del tftp\n" "\n" msgstr "" "\n" "Services HBAC\n" "\n" "Les services PAM dont le système HBAC peut contrôler l'accès. Le nom\n" "utilisé ici doit correspondre au nom de service utilisé par PAM.\n" "EXEMPLES:\n" "\n" " Ajouter un nouveau service HBAC :\n" " ipa hbacsvc-add tftp\n" "\n" " Modifier un service HBAC existant :\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Chercher des services HBAC. Cet exemple renverra deux résultats,\n" " le service FTP et le service tftp nouvellement ajouté :\n" " ipa hbacsvc-find ftp\n" "\n" " Supprimer un service HBAC :\n" " ipa hbacsvc-del tftp\n" "\n" msgid "Host based access control commands" msgstr "Commandes HBAC." msgid "HBAC service" msgstr "Service HBAC" msgid "HBAC services" msgstr "Services HBAC" msgid "HBAC Services" msgstr "Services HBAC" msgid "HBAC Service" msgstr "Service HBAC" msgid "Service name" msgstr "Nom de service" msgid "HBAC service description" msgstr "Description de service HBAC" msgid "Add a new HBAC service." msgstr "Ajouter un nouveau service HBAC." #, python-format msgid "Added HBAC service \"%(value)s\"" msgstr "Service HBAC \"%(value)s\" ajouté" msgid "Delete an existing HBAC service." msgstr "Supprimer un service HBAC existant." #, python-format msgid "Deleted HBAC service \"%(value)s\"" msgstr "Service HBAC \"%(value)s\" supprimé" msgid "Modify an HBAC service." msgstr "Modifier un service HBAC." #, python-format msgid "Modified HBAC service \"%(value)s\"" msgstr "Service HBAC \"%(value)s\" modifié" msgid "Search for HBAC services." msgstr "Rechercher des services HBAC." #, python-format msgid "%(count)d HBAC service matched" msgid_plural "%(count)d HBAC services matched" msgstr[0] "%(count)d service HBAC correspondant" msgstr[1] "%(count)d services HBAC correspondants" msgid "Display information about an HBAC service." msgstr "Afficher les informations sur un service HBAC." msgid "" "\n" "HBAC Service Groups\n" "\n" "HBAC service groups can contain any number of individual services,\n" "or \"members\". Every group must have a description.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service group:\n" " ipa hbacsvcgroup-add --desc=\"login services\" login\n" "\n" " Add members to an HBAC service group:\n" " ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login\n" "\n" " Display information about a named group:\n" " ipa hbacsvcgroup-show login\n" "\n" " Delete an HBAC service group:\n" " ipa hbacsvcgroup-del login\n" msgstr "" "\n" "Groupes de services HBAC\n" "\n" "Les groupes de services HBAC peuvent contenir n'importe quel nombre de\n" "services individuels, dit « membres ». Chaque groupe doit avoir une\n" "description.\n" "\n" "EXEMPLES:\n" "\n" " Ajouter un nouveau groupe de services HBAC :\n" " ipa hbacsvcgroup-add --desc=\"login services\" login\n" "\n" " Ajouter des membres à un groupe de services HBAC :\n" " ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login\n" "\n" " Afficher les informations d'un groupe nommé :\n" " ipa hbacsvcgroup-show login\n" "\n" " Supprimer un groupe de services HBAC :\n" " ipa hbacsvcgroup-del login\n" msgid "HBAC service group" msgstr "Groupe de services HBAC" msgid "HBAC service groups" msgstr "Groupes de services HBAC" msgid "HBAC Service Groups" msgstr "Groupes de services HBAC" msgid "HBAC Service Group" msgstr "Groupe de services HBAC" msgid "Service group name" msgstr "Nom de groupe de services HBAC" msgid "HBAC service group description" msgstr "Description de groupe de services HBAC" msgid "Add a new HBAC service group." msgstr "Ajouter un nouveau groupe de services HBAC." #, python-format msgid "Added HBAC service group \"%(value)s\"" msgstr "Groupe de services HBAC \"%(value)s\" ajouté" msgid "Delete an HBAC service group." msgstr "Supprimer un groupe de services HBAC." #, python-format msgid "Deleted HBAC service group \"%(value)s\"" msgstr "Groupe de services HBAC \"%(value)s\" supprimé" msgid "Modify an HBAC service group." msgstr "Supprimer un groupe de services HBAC." #, python-format msgid "Modified HBAC service group \"%(value)s\"" msgstr "Groupe de services HBAC \"%(value)s\" modifié" msgid "Search for an HBAC service group." msgstr "Rechercher des groupes de services HBAC." #, python-format msgid "%(count)d HBAC service group matched" msgid_plural "%(count)d HBAC service groups matched" msgstr[0] "%(count)d groupe de services HBAC correspondant" msgstr[1] "%(count)d groupes de services HBAC correspondants" msgid "Display information about an HBAC service group." msgstr "Afficher les informations sur un groupe de services HBAC." msgid "Add members to an HBAC service group." msgstr "Ajouter des membres à un groupe de services HBAC." msgid "Remove members from an HBAC service group." msgstr "Supprimer des membres d'un groupe de services HBAC." msgid "" "\n" "Simulate use of Host-based access controls\n" "\n" "HBAC rules control who can access what services on what hosts.\n" "You can use HBAC to control which users or groups can access a service,\n" "or group of services, on a target host.\n" "\n" "Since applying HBAC rules implies use of a production environment,\n" "this plugin aims to provide simulation of HBAC rules evaluation without\n" "having access to the production environment.\n" "\n" " Test user coming to a service on a named host against\n" " existing enabled rules.\n" "\n" " ipa hbactest --user= --host= --service=\n" " [--rules=rules-list] [--nodetail] [--enabled] [--disabled]\n" " [--sizelimit= ]\n" "\n" " --user, --host, and --service are mandatory, others are optional.\n" "\n" " If --rules is specified simulate enabling of the specified rules and test\n" " the login of the user using only these rules.\n" "\n" " If --enabled is specified, all enabled HBAC rules will be added to " "simulation\n" "\n" " If --disabled is specified, all disabled HBAC rules will be added to " "simulation\n" "\n" " If --nodetail is specified, do not return information about rules matched/" "not matched.\n" "\n" " If both --rules and --enabled are specified, apply simulation to --rules " "_and_\n" " all IPA enabled rules.\n" "\n" " If no --rules specified, simulation is run against all IPA enabled rules.\n" " By default there is a IPA-wide limit to number of entries fetched, you can " "change it\n" " with --sizelimit option.\n" "\n" "EXAMPLES:\n" "\n" " 1. Use all enabled HBAC rules in IPA database to simulate:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 2. Disable detailed summary of how rules were applied:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail\n" " --------------------\n" " Access granted: True\n" " --------------------\n" "\n" " 3. Test explicitly specified HBAC rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: myrule\n" "\n" " 4. Use all enabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --enabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 5. Test all disabled HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: new-rule\n" "\n" " 6. Test all disabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" "\n" " 7. Test all (enabled and disabled) HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --enabled --disabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Not matched rules: new-rule\n" " Matched rules: allow_all\n" "\n" "\n" "HBACTEST AND TRUSTED DOMAINS\n" "\n" "When an external trusted domain is configured in IPA, HBAC rules are also " "applied\n" "on users accessing IPA resources from the trusted domain. Trusted domain " "users and\n" "groups (and their SIDs) can be then assigned to external groups which can " "be\n" "members of POSIX groups in IPA which can be used in HBAC rules and thus " "allowing\n" "access to resources protected by the HBAC system.\n" "\n" "hbactest plugin is capable of testing access for both local IPA users and " "users\n" "from the trusted domains, either by a fully qualified user name or by user " "SID.\n" "Such user names need to have a trusted domain specified as a short name\n" "(DOMAIN\\Administrator) or with a user principal name (UPN), " "Administrator@ad.test.\n" "\n" "Please note that hbactest executed with a trusted domain user as --user " "parameter\n" "can be only run by members of \"trust admins\" group.\n" "\n" "EXAMPLES:\n" "\n" " 1. Test if a user from a trusted domain specified by its shortname " "matches any\n" " rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Administrator' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 2. Test if a user from a trusted domain specified by its domain name " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 3. Test if a user from a trusted domain specified by its SID matches any " "rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 4. Test if other user from a trusted domain specified by its SID matches " "any rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" "\n" " 5. Test if other user from a trusted domain specified by its shortname " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Otheruser' --host `hostname` --service " "sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" msgstr "" "\n" "Simuler l'utilisation des contrôles d'accès fondés sur l'hôte\n" "\n" "Les règles HBAC contrôlent qui peut accéder à quel service sur quels hôtes.\n" "Vous pouvez utiliser HBAC pour contrôler quels utilisateurs ou quels " "groupes\n" "peuvent accéder à un service ou à un groupe de services, sur un hôte cible.\n" "\n" "Comme l'application des règles HBAC suppose l'utilisation d'un environnement " "de\n" "production, ce greffon vise à fournir une simulation de l'évaluation des " "règles\n" "HBAC sans nécessiter l'accès à l'environnement de production.\n" "\n" " Testez les règles existantes activées au regard de l'arrivée d'un " "utilisateur\n" " sur un service sur un hôte donné.\n" "\n" "ipa hbactest --user= --host= --service=âŽ\n" " [--rules=rules-list] [--nodetail] [--enabled] [--disabled]âŽ\n" " [--sizelimit= ]\n" "\n" " --user, --host et --service sont obligatoires, les autres sont " "optionnelles.\n" "\n" " Si --rules est défini, l'activation des règles indiquées est simulée et\n" " l'identifiant de l'utilisateur est testé uniquement sur ces règles.\n" "\n" " Si --enabled est défini, toutes les règles HBAC activées sont ajoutées à " "la\n" " simulation\n" "\n" " Si --disabled est défini, toutes les règles HBAC désactivées sont ajoutées\n" " à la simulation\n" "\n" " Si --nodetail est défini, il n'est pas renvoyé d'information sur les règles " "en correspondance ou pas.\n" "\n" " Si --rules et --enabled sont définis tous deux, la simulation sera " "appliquée à\n" " --rules _et_ à tous les règles IPA activées.\n" "\n" " Si --rules n'est pas défini, la simulation est lancée avec toutes les " "règles\n" " IPA activées. Par défaut, il existe une limite globale à IPA sur le nombre\n" " d'entrées renvoyées, vous pouvez la modifier avec l'option --sizelimit.\n" "\n" " Si --srchost est spécifié, elle sera ignorée. Elle est conservée pour des\n" " raisons de compatibilité uniquement.\n" "\n" "EXEMPLES :\n" "\n" " 1. Utiliser toutes les règles HBAC activées dans IPA pour la " "simulation :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " notmatched: my-second-rule\n" " notmatched: my-third-rule\n" " notmatched: myrule\n" " matched: allow_all\n" "\n" " 2. Désactiver le résumé détaillé de la façon dont les règles sont " "appliquées :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail\n" " --------------------\n" " Access granted: True\n" " --------------------\n" "\n" " 3. Tester explicitement les règles HBAC spécifiées :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \n" "--rules=my-second-rule,myrule\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " notmatched: my-second-rule\n" " notmatched: myrule\n" "\n" " 4. Utiliser toutes les règles HBAC activées de la base de données IPA + " "les règles explicitement définies :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \n" "--rules=my-second-rule,myrule --enabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " notmatched: my-second-rule\n" " notmatched: my-third-rule\n" " notmatched: myrule\n" " matched: allow_all\n" "\n" " 5. Tester toutes les règles HBAC désactivées de la base de données " "IPA :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " notmatched: new-rule\n" "\n" " 6. Tester toutes les règles HBAC désactivées de la base de données IPA + " "les règles explicitement définies :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \n" "--rules=my-second-rule,myrule --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " notmatched: my-second-rule\n" " notmatched: my-third-rule\n" " notmatched: myrule\n" "\n" " 7. Tester toutes les règles HBAC (activées et desactivées) de la base de " "données IPA :\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --enabled --disabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " notmatched: my-second-rule\n" " notmatched: my-third-rule\n" " notmatched: myrule\n" " notmatched: new-rule\n" " matched: allow_all\n" "\n" "\n" "TEST HBAC ET DOMAINES DE CONFIANCE\n" "\n" "Quand un domaine externe de confiance est configuré dans IPA, les règles " "HBAC sont aussi appliquées\n" "aux utilisateurs accédant aux ressources IPA à partir du domaine de " "confiance. Les utilisateurs des domaines de confiance et\n" "les groupes (et leurs SID) peuvent être assignés à des groupes externes " "pouvant être\n" "membres de groupes POSIX dans IPA intégrables dans les règles HBAC, ce qui " "autorise\n" "un accès aux ressources protégées par le système HBAC.\n" "\n" "Un greffon hbactest est capable de tester des accès à la fois des " "utilisateurs IPA locaux et des utilisateurs\n" "de domaines de confiance avec, soit le nom d'utilisateur pleinement " "qualifié, soit le SID utilisateur.\n" "De tels noms d'utilisateur doivent avoir un domaine de confiance précisé en " "nom court\n" "(DOMAINE/Administrateur) ou avec un nom de principal (UPN), " "Administrator@ad.test.\n" "\n" "Veuillez noter que hbactest exécuté avec un utilisateur de domaine de " "confiance en tant que paramètre --user\n" "ne peut être lancé que des membres du groupe des « administrateurs de " "confiance ».\n" "\n" "EXEMPLES :\n" "\n" " 1. Tester si un utilisateur d'un domaine de confiance défini par son nom " "court\n" " s'accorde à toute règle :\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Administrator' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 2. Tester si un utilisateur d'un domaine de confiance défini par son nom " "de domaine\n" " s'accorde à toute règle :\n" "\n" " $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 3. Tester si un utilisateur d'un domaine de confiance défini par son " "SID\n" " s'accorde à toute règle :\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 4. Tester si un autre utilisateur d'un domaine de confiance défini par " "son SID\n" " s'accorde à toute règle :\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" "\n" " 5. Tester si un autre utilisateur d'un domaine de confiance défini par " "son nom court\n" " s'accorde à toute règle :\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Otheruser' --host `hostname` --service " "sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" msgid "Simulate use of Host-based access controls" msgstr "Simulation de règles de contrôle d'accès basé sur les systèmes" msgid "Warning" msgstr "Attention" msgid "Matched rules" msgstr "Règles correspondantes" msgid "Not matched rules" msgstr "Règles non-correspondantes" msgid "Non-existent or invalid rules" msgstr "Règles inexistantes ou invalides" msgid "Result of simulation" msgstr "Résultat de la simulation" msgid "User name" msgstr "Nom d'utilisateur" msgid "Target host" msgstr "Système cible" msgid "Rules to test. If not specified, --enabled is assumed" msgstr "Règles à tester. Si non-spécifié, --enabled est implicite" msgid "Hide details which rules are matched, not matched, or invalid" msgstr "Masquer les détails des règles correspondantes ou non, ou invalides" msgid "Include all enabled IPA rules into test [default]" msgstr "Inclure toutes les règles IPA actives dans le test [par défaut]" msgid "Include all disabled IPA rules into test" msgstr "Inclure toutes les règles IPA inactives dans le test" msgid "Maximum number of rules to process when no --rules is specified" msgstr "" "Nombre maximal de règles à traiter quand aucune option --rules n'est " "spécifiée" msgid "Unresolved rules in --rules" msgstr "Règles non résolues dans --rules" msgid "" "Cannot search in trusted domains without own domain configured. Make sure " "you have run ipa-adtrust-install on the IPA server first" msgstr "" "Impossible d'effectuer une recherche sur les domaines approuvés sans avoir " "au préalable configuré son propre domaine. Assurez-vous d'avoir d'abord " "lancé ipa-adtrust-install sur le serveur" #, python-format msgid "Access granted: %s" msgstr "Accès autorisé : %s" msgid "" "\n" "Hosts/Machines\n" "\n" "A host represents a machine. It can be used in a number of contexts:\n" "- service entries are associated with a host\n" "- a host stores the host/ service principal\n" "- a host can be used in Host-based Access Control (HBAC) rules\n" "- every enrolled client generates a host entry\n" "\n" "ENROLLMENT:\n" "\n" "There are three enrollment scenarios when enrolling a new client:\n" "\n" "1. You are enrolling as a full administrator. The host entry may exist\n" " or not. A full administrator is a member of the hostadmin role\n" " or the admins group.\n" "2. You are enrolling as a limited administrator. The host must already\n" " exist. A limited administrator is a member a role with the\n" " Host Enrollment privilege.\n" "3. The host has been created with a one-time password.\n" "\n" "A host can only be enrolled once. If a client has enrolled and needs to\n" "be re-enrolled, the host entry must be removed and re-created. Note that\n" "re-creating the host entry will result in all services for the host being\n" "removed, and all SSL certificates associated with those services being\n" "revoked.\n" "\n" "A host can optionally store information such as where it is located,\n" "the OS that it runs, etc.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host:\n" " ipa host-add --location=\"3rd floor lab\" --locality=Dallas test.example." "com\n" "\n" " Delete a host:\n" " ipa host-del test.example.com\n" "\n" " Add a new host with a one-time password:\n" " ipa host-add --os='Fedora 12' --password=Secret123 test.example.com\n" "\n" " Add a new host with a random one-time password:\n" " ipa host-add --os='Fedora 12' --random test.example.com\n" "\n" " Modify information about a host:\n" " ipa host-mod --os='Fedora 12' test.example.com\n" "\n" " Remove SSH public keys of a host and update DNS to reflect this change:\n" " ipa host-mod --sshpubkey= --updatedns test.example.com\n" "\n" " Disable the host Kerberos key, SSL certificate and all of its services:\n" " ipa host-disable test.example.com\n" "\n" " Add a host that can manage this host's keytab and certificate:\n" " ipa host-add-managedby --hosts=test2 test\n" msgstr "" "\n" "Systèmes/Machines\n" "\n" "Un système représente une machine, et peut être utilisé dans plusieurs\n" "contextes :\n" "- les entrées de services sont associés à un système\n" "- un système stocke les entrées des principaux de services host/\n" "- un système peut être utilisé dans les règles de contrôles d'accès HBAC\n" "- chaque client enregistré crée une entrée système\n" "\n" "INSCRIPTION :\n" "\n" "Trois scenarii d'inscriptions d'un nouveau client sont possibles :\n" "\n" "1. La machine est enregistrée par un administrateur de plein droit.\n" " L'entrée système peut pré-exister ou non. Un administrateur de\n" " plein droit est membre du rôle hostadmin ou du groupe admins\n" "2. L'inscription est faite par un administrateur limité. Le système\n" " doit avoir été préalablement créé. Un administrateur limité\n" " possède le privilège Host Enrollment.\n" "3. Le système a été créé avec un mot de passe à usage unique.\n" "\n" "Un système peut être inscrit une seule fois. Si un client est déjà\n" "inscrit et nécessite d'être ré-inscrit, il faut d'abord le supprimer\n" "puis re-créé. La re-création du système provoquera la perte de tous\n" "les services du système à supprimer, ainsi que la révocation de tous\n" "les certificats SSL associés aux services supprimés.\n" "\n" "Un système peut de façon optionnelle stocker des informations\n" "complémentaires comme sa localisation, son système d'exploitation, etc.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau système :\n" " ipa host-add --location=\"labo 3e étage\" --locality=Dallas test.example." "com\n" "\n" " Supprimer un système :\n" " ipa host-del test.example.com\n" "\n" " Ajouter un système avec un mot de passe à usage unique :\n" " ipa host-add --os='Fedora 12' --password=Secret123 test.example.com\n" "\n" " Ajouter un nouveau système avec un mot de passe à usage unique aléatoire :\n" " ipa host-add --os='Fedora 12' --random test.example.com\n" "\n" " Modifier les informations d'un système :\n" " ipa host-mod --os='Fedora 12' test.example.com\n" "\n" " Supprimer les clés publiques SSH du système et modifie les DNS pour " "refléter ce changement :\n" " ipa host-mod --sshpubkey= --updatedns test.example.com\n" "\n" " Désactiver la clé Kerberos du système, ses certificats SSL et tous\n" " ses services :\n" " ipa host-disable test.example.com\n" "\n" " Ajouter un système pouvant administrer le keytab et les certificats\n" " du système sur lequel la commande est lancée :\n" " ipa host-add-managedby --hosts=test2 test\n" msgid "Keytab" msgstr "Keytab" msgid "Serial Number" msgstr "Numéro de série" msgid "Serial Number (hex)" msgstr "Numéro de série (hex)" msgid "Failed managedby" msgstr "managedby en échec" msgid "SSH public key fingerprint" msgstr "Empreinte de clé publique SSH" msgid "host" msgstr "système" msgid "hosts" msgstr "systèmes" msgid "Host" msgstr "Système" msgid "Host name" msgstr "Nom de système" msgid "A description of this host" msgstr "Description de ce système" msgid "Locality" msgstr "Ville" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "Ville du système (par ex. \"Paris, IDF\")" msgid "Host location (e.g. \"Lab 2\")" msgstr "Localisation du système (par ex. \"Lab 2\")" msgid "Platform" msgstr "Plate-forme" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "Plate-forme matérielle du système (par ex. \"Lenovo T61\")" msgid "Operating system" msgstr "Système d'exploitation" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "Système d'exploitation et version (par ex. \"Fedora 9\")" msgid "User password" msgstr "Mot de passe utilisateur" msgid "Password used in bulk enrollment" msgstr "Mot de passe utilisé pour les inscriptions en masse" msgid "Generate a random password to be used in bulk enrollment" msgstr "Crée un mot de passe aléatoire utilisé pour l'inscription en masse" msgid "Random password" msgstr "Mot de passe aléatoire" msgid "Base-64 encoded server certificate" msgstr "Certificat du serveur encodé en Base-64" msgid "Principal name" msgstr "Nom du principal" msgid "MAC address" msgstr "Adresse MAC" msgid "Hardware MAC address(es) on this host" msgstr "Adresse(s) MAC du matériel sur ce serveur" msgid "SSH public key" msgstr "Clé publique SSH" msgid "" "Host category (semantics placed on this attribute are for local " "interpretation)" msgstr "" "Catégorie d'hôte (les sémantiques associées à cet attribut vous sont propres)" msgid "Add a new host." msgstr "Ajouter un nouveau système." #, python-format msgid "Added host \"%(value)s\"" msgstr "Système \"%(value)s\" ajouté" msgid "force host name even if not in DNS" msgstr "forcer le nom même si absent des DNS" msgid "skip reverse DNS detection" msgstr "passer outre la détection de DNS inverse" msgid "Add the host to DNS with this IP address" msgstr "Ajouter le système aux DNS avec cette adresse IP" #, python-format msgid "The host was added but the DNS update failed with: %(exc)s" msgstr "Le système a été ajouté mais la mise à jour DNS a échoué : %(exc)s" msgid "Delete a host." msgstr "Supprimer un système." #, python-format msgid "Deleted host \"%(value)s\"" msgstr "Système \"%(value)s\" supprimé" msgid "Remove entries from DNS" msgstr "Supprimer les entrées DNS" msgid "Modify information about a host." msgstr "Modifier les informations d'un système." #, python-format msgid "Modified host \"%(value)s\"" msgstr "Système \"%(value)s\" modifié" msgid "Kerberos principal name for this host" msgstr "Nom de principal Kerberos pour ce système" msgid "Update DNS entries" msgstr "Mettre à jour les entrées DNS" msgid "Password cannot be set on enrolled host." msgstr "Le mot de passe ne peut être défini pour le système enregistré." msgid "cn is immutable" msgstr "cn est immuable" msgid "Search for hosts." msgstr "Rechercher des systèmes." #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "%(count)d système correspondant" msgstr[1] "%(count)d systèmes correspondants" msgid "Display information about a host." msgstr "Afficher les informations sur un système." msgid "file to store certificate in" msgstr "fichier où stocker le certificat" #, python-format msgid "Certificate stored in file '%(file)s'" msgstr "Certificat enregistré dans le fichier '%(file)s'" msgid "Disable the Kerberos key, SSL certificate and all services of a host." msgstr "" "Désactiver la clé Kerberos, les certificats SSL et tous les services d'un " "système." #, python-format msgid "Disabled host \"%(value)s\"" msgstr "Système \"%(value)s\" désactivé" msgid "Add hosts that can manage this host." msgstr "Ajouter les systèmes qui peuvent gérer ce système." msgid "Remove hosts that can manage this host." msgstr "Supprimer les systèmes qui peuvent gérer ce système." msgid "" "\n" "Groups of hosts.\n" "\n" "Manage groups of hosts. This is useful for applying access control to a\n" "number of hosts by using Host-based Access Control.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host group:\n" " ipa hostgroup-add --desc=\"Baltimore hosts\" baltimore\n" "\n" " Add another new host group:\n" " ipa hostgroup-add --desc=\"Maryland hosts\" maryland\n" "\n" " Add members to the hostgroup (using Bash brace expansion):\n" " ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore\n" "\n" " Add a hostgroup as a member of another hostgroup:\n" " ipa hostgroup-add-member --hostgroups=baltimore maryland\n" "\n" " Remove a host from the hostgroup:\n" " ipa hostgroup-remove-member --hosts=box2 baltimore\n" "\n" " Display a host group:\n" " ipa hostgroup-show baltimore\n" "\n" " Delete a hostgroup:\n" " ipa hostgroup-del baltimore\n" msgstr "" "\n" "Groupes de systèmes.\n" "\n" "Gestion des groupes de systèmes. Permet d'appliquer des contrôles d'accès\n" "à plusieurs systèmes en utilisant les contrôles HBAC.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau groupe de systèmes :\n" " ipa hostgroup-add --desc=\"Systèmes de Baltimore\" baltimore\n" "\n" " Ajouter un nouveau groupe de systèmes :\n" " ipa hostgroup-add --desc=\"Systèmes du Maryland\" maryland\n" "\n" " Ajouter des membres à un groupe de systèmes :\n" " ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore\n" "\n" " Ajouter un groupe de systèmes en tant que membre d'un autre :\n" " ipa hostgroup-add-member --hostgroups=baltimore maryland\n" "\n" " Supprimer un système d'un groupe :\n" " ipa hostgroup-remove-member --hosts=box2 baltimore\n" "\n" " Afficher un groupe de systèmes :\n" " ipa hostgroup-show baltimore\n" "\n" " Supprimer un groupe de systèmes :\n" " ipa hostgroup-del baltimore\n" msgid "host group" msgstr "groupe de systèmes" msgid "host groups" msgstr "groupes de systèmes" msgid "Host Group" msgstr "Groupe de systèmes" msgid "Host-group" msgstr "Groupe de systèmes" msgid "Name of host-group" msgstr "Nom du groupe de systèmes" msgid "A description of this host-group" msgstr "Description de ce groupe de systèmes" msgid "Add a new hostgroup." msgstr "Ajouter un nouveau groupe de systèmes." #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "Groupe de systèmes \"%(value)s\" ajouté" #, python-format msgid "" "netgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "Un netgroup nommé \"%s\" existe déjà. Les groupes de systèmes et les " "netgroups partagent un même espace de nommage." msgid "Delete a hostgroup." msgstr "Supprimer un groupe de systèmes." #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "Groupe de systèmes \"%(value)s\" supprimé" msgid "Modify a hostgroup." msgstr "Modifier un groupe de systèmes." #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "Groupe de systèmes \"%(value)s\" modifié" msgid "Search for hostgroups." msgstr "Rechercher un groupe de systèmes." #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "%(count)d groupe de systèmes correspondant" msgstr[1] "%(count)d groupes de systèmes correspondants" msgid "Display information about a hostgroup." msgstr "Afficher les informations sur un groupe de systèmes." msgid "Add members to a hostgroup." msgstr "Ajouter des membres à un groupe de systèmes." msgid "Remove members from a hostgroup." msgstr "Supprimer des membres d'un groupe de systèmes." msgid "" "\n" "ID ranges\n" "\n" "Manage ID ranges used to map Posix IDs to SIDs and back.\n" "\n" "There are two type of ID ranges which are both handled by this utility:\n" "\n" " - the ID ranges of the local domain\n" " - the ID ranges of trusted remote domains\n" "\n" "Both types have the following attributes in common:\n" "\n" " - base-id: the first ID of the Posix ID range\n" " - range-size: the size of the range\n" "\n" "With those two attributes a range object can reserve the Posix IDs starting\n" "with base-id up to but not including base-id+range-size exclusively.\n" "\n" "Additionally an ID range of the local domain may set\n" " - rid-base: the first RID(*) of the corresponding RID range\n" " - secondary-rid-base: first RID of the secondary RID range\n" "\n" "and an ID range of a trusted domain must set\n" " - rid-base: the first RID of the corresponding RID range\n" " - sid: domain SID of the trusted domain\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for a trusted domain\n" "\n" "Since there might be more than one trusted domain the domain SID must be " "given\n" "while creating the ID range.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\\n" " --dom-sid=S-1-5-21-123-456-789 trusted_dom_range\n" "\n" "This ID range is then used by the IPA server and the SSSD IPA provider to\n" "assign Posix UIDs to users from the trusted domain.\n" "\n" "If e.g a range for a trusted domain is configured with the following " "values:\n" " base-id = 1200000\n" " range-size = 200000\n" " rid-base = 0\n" "the RIDs 0 to 199999 are mapped to the Posix ID from 1200000 to 13999999. " "So\n" "RID 1000 <-> Posix ID 1201000\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for the local domain\n" "\n" "To create an ID range for the local domain it is not necessary to specify a\n" "domain SID. But since it is possible that a user and a group can have the " "same\n" "value as Posix ID a second RID interval is needed to handle conflicts.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\\n" " --secondary-rid-base=1000000 local_range\n" "\n" "The data from the ID ranges of the local domain are used by the IPA server\n" "internally to assign SIDs to IPA users and groups. The SID will then be " "stored\n" "in the user or group objects.\n" "\n" "If e.g. the ID range for the local domain is configured with the values " "from\n" "the example above then a new user with the UID 1200007 will get the RID " "1007.\n" "If this RID is already used by a group the RID will be 1000007. This can " "only\n" "happen if a user or a group object was created with a fixed ID because the\n" "automatic assignment will not assign the same ID twice. Since there are " "only\n" "users and groups sharing the same ID namespace it is sufficient to have " "only\n" "one fallback range to handle conflicts.\n" "\n" "To find the Posix ID for a given RID from the local domain it has to be\n" "checked first if the RID falls in the primary or secondary RID range and\n" "the rid-base or the secondary-rid-base has to be subtracted, respectively,\n" "and the base-id has to be added to get the Posix ID.\n" "\n" "Typically the creation of ID ranges happens behind the scenes and this CLI\n" "must not be used at all. The ID range for the local domain will be created\n" "during installation or upgrade from an older version. The ID range for a\n" "trusted domain will be created together with the trust by 'ipa trust-" "add ...'.\n" "\n" "USE CASES:\n" "\n" " Add an ID range from a transitively trusted domain\n" "\n" " If the trusted domain (A) trusts another domain (B) as well and this " "trust\n" " is transitive 'ipa trust-add domain-A' will only create a range for\n" " domain A. The ID range for domain B must be added manually.\n" "\n" " Add an additional ID range for the local domain\n" "\n" " If the ID range of the local domain is exhausted, i.e. no new IDs can " "be\n" " assigned to Posix users or groups by the DNA plugin, a new range has to " "be\n" " created to allow new users and groups to be added. (Currently there is " "no\n" " connection between this range CLI and the DNA plugin, but a future " "version\n" " might be able to modify the configuration of the DNS plugin as well)\n" "\n" "In general it is not necessary to modify or delete ID ranges. If there is " "no\n" "other way to achieve a certain configuration than to modify or delete an ID\n" "range it should be done with great care. Because UIDs are stored in the " "file\n" "system and are used for access control it might be possible that users are\n" "allowed to access files of other users if an ID range got deleted and " "reused\n" "for a different domain.\n" "\n" "(*) The RID is typically the last integer of a user or group SID which " "follows\n" "the domain SID. E.g. if the domain SID is S-1-5-21-123-456-789 and a user " "from\n" "this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of " "the\n" "user. RIDs are unique in a domain, 32bit values and are used for users and\n" "groups.\n" "\n" "WARNING:\n" "\n" "DNA plugin in 389-ds will allocate IDs based on the ranges configured for " "the\n" "local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" "on the local ranges set via this family of commands.\n" "\n" "Manual configuration change has to be done in the DNA plugin configuration " "for\n" "the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to " "be\n" "modified to match the new range.\n" msgstr "" "\n" "Plages d'identifiants\n" "\n" "Gérer les plages d'ID faisant correspondre les ID Posix avec les SID et " "inversement.\n" "\n" "Il y a deux types de plages d'ID gérées par cet utilitaire :\n" "\n" " - les plages d'ID du domaine local\n" " - les plages d'ID des domaines de confiance distants\n" "\n" "Les deux types ont les attributs suivants en commun :\n" "\n" " - base-id: le premier ID de la plage des ID Posix\n" " - range-size: la taille de la plage\n" "\n" "Avec ces deux attributs un objet plage peut réserver le point de départ des " "ID Posix\n" "avec base-id jusqu'à base-id+range-size non inclus exclusivement.\n" "\n" "En plus une plage d'ID du domaine local peut déterminer\n" " - rid-base : le premier RID(*) de la plage de RID correspondante\n" " - secondary-rid-base : le premier RID de la plage RID secondaire\n" "\n" "et une plage d'ID d'un domaine de confiance peut déterminer\n" " - rid-base : le premier RID de la plage de RID correspondante\n" " - sid : le domaine SID du domaine de confiance\n" "\n" "\n" "\n" "EXEMPLE : Ajouter une nouvelle plage d'ID pour un domaine de confiance\n" "\n" "Étant donné qu'il peut y avoir plus d'un domaine de confiance, le SID du " "domaine\n" "doit être donné lors de la création de la plage.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\\n" " --dom-sid=S-1-5-21-123-456-789 trusted_dom_range\n" "\n" "Cette plage d'ID est ensuite utilisée par le serveur IPA et le fournisseur " "SSSD IPA pour\n" "assigner des UID Posix aux utilisateurs du domaine de confiance.\n" "\n" "Si par ex. une plage pour un domaine de confiance est configurée avec les " "valeurs suivantes :\n" " base-id = 1200000\n" " range-size = 200000\n" " rid-base = 0\n" "les RID de 0 à 199999 sont associés aux ID Posix de 1200000 à 13999999. " "Donc\n" "RID 1000 <-> Posix ID 1201000\n" "\n" "\n" "\n" "EXEMPLE: Ajouter une nouvelle plage d'ID pour le domaine local\n" "\n" "Pour créer une plage d'ID pour le domaine local il n'est pas nécessaire de " "définir un\n" "SID de domaine. Mais comme il est possible qu'un utilisateur et un groupe " "aient une même \n" "valeur comme ID Posix un second intervalle RID est nécessaire pour éviter " "les conflits.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\\n" " --secondary-rid-base=1000000 local_range\n" "\n" "Les données des plages d'ID du domaine local sont utilisées en interne par " "le serveur IPA\n" "pour assigner des SID aux utilisateurs et aux groupes IPA. Le SID sera alors " "enregistré\n" "dans les objets utilisateur ou groupe.\n" "\n" "Si par ex. la plage d'ID du domaine local est configurée pour les valeurs " "de\n" "l'exemple ci-dessus alors un nouvel utilisateur avec l'UID 1200007 aura le " "RID 1007.\n" "Si ce RID est déjà utilié par un groupe le RID sera 1000007. Ceci ne peut " "arriver\n" "que si un objet utilisateur ou groupe a été créé avec un ID donné parce que\n" "l'assignation automatique n'assigne pas le même ID deux fois. Étant donné " "qu'il n'y a que\n" "les utilisateurs et les groupes partageant le même ID de nom d'espace, il " "suffit d'avoir\n" "une seule plage de recours pour gérer les conflits.\n" "\n" "Pour trouver l'ID Posix pour un RID donné dans le domaine local il faut " "d'abord\n" "vérifier si le RID tombe dans la première ou la deuxième plage de RID ;\n" "le rid-base ou le secondary-rid-base seront respectivement à soustraire,\n" "et le base-id à ajouter pour obtenir l'ID Posix.\n" "\n" "Généralement la création des plages d'ID s'effectue en arrière-plan et ce " "CLI\n" "n'a pas besoin d'être du tout utilisé. Les plages d'ID pour le domaine local " "seront créées\n" "à l'installation ou au cours de la mise à jour d'une version précédente. La " "plage d'ID pour un\n" "domaine de confiance sera créé en même temps que la confiance par 'ipa trust-" "add ...'.\n" "\n" "CAS PRATIQUES :\n" "\n" " Ajouter une plage d'ID pour un domaine de confiance par transition\n" "\n" " Si le domaine de confiance (A) fait confiance à un domaine (B) et que " "cette confiance\n" " est transitive 'ipa trust-add domain-A' ne créera de plage que pour le " "domaine A.\n" " La plage d'ID pour le domaine B doit être ajoutée manuellement.\n" "\n" " Ajouter une plage d'ID supplémentaire pour le domaine local\n" "\n" " Si la plage d'ID du domaine local est épuisée, i.e. qu'aucun nouvel ID " "ne peut être\n" " assigné aux utilisateurs ou groupes Posix par le greffon DNA, il faut " "créer une nouvelle\n" " plage pour permettre l'ajout de nouveaux utilisateurs ou groupes " "(actuellement il n'y a\n" " pas de connexion entre cette plage CLI et le greffon DNA, mais une " "future version\n" " sera capable de modifier de même la configuration du greffon DNS).\n" "\n" "En règle générale il n'est pas nécessaire de modifier ou supprimer les " "plages d'ID. S'il\n" "n'y a pas d'autre moyen de mener à bien un configuration donnée qu'en " "modifiant ou supprimant\n" "une plage d'ID cela doit être fait avec grand soin. Comme les UID sont " "enregistrés dans le\n" "fichier système et sont utilisés pour les contrôles d'accès il se pourrait " "que des\n" "utilisateurs soit autorisés à avoir accès à des fichiers d'autres " "utilisateurs si une plage\n" "d'ID a été détruite puis réutilisée pour un domaine différent.\n" "\n" "(*) Le RID est généralement le dernier entier du SID d'un utilisateur ou " "d'un groupe suivant\n" "le SID du domaine. Ex. si le SID du domaine est S-1-5-21-123-456-789 et " "qu'un utilisateur de\n" "ce domaine a le SID S-1-5-21-123-456-789-1010, alors 010 est le RID de " "l'utilisateur. Les RID\n" "sont uniques dans un domaine, ce sont des valeurs sur 32 bits utilisées pour " "les utilisateurs\n" "et les groupes.\n" "\n" "AVERTISSEMENT :\n" "\n" "Le greffon DNA dans 389-ds alloue des ID selon les plages configurées pour " "le\n" "domaine local. Actuellement le greffon DNA *ne peut pas* être lui-même " "reconfiguré selon\n" "les plages locales définies par cette famille de commandes.\n" "\n" "Une modification manuelle de la configuration du greffon DNA doit être " "effectuée pour\n" "la nouvelle plage locale. Généralement, l'attribut dnaNextRange de " "« cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config » doit " "être\n" "modifié pour correspondre à la nouvelle plage.\n" msgid "ID Ranges" msgstr "Plages d'ID" msgid "ID Range" msgstr "Plage d'ID" msgid "local domain range" msgstr "Plage pour domaine local" msgid "Active Directory winsync range" msgstr "Plage winsync pour Active Directory" msgid "Active Directory domain range" msgstr "Plage pour domaine Active Directory" msgid "Active Directory trust range with POSIX attributes" msgstr "Plage pour le domaine Active Directory approuvé avec attributs POSIX" msgid "IPA trust range" msgstr "Plage de domaine IPA approuvé" msgid "Range name" msgstr "Nom de la plage" msgid "First Posix ID of the range" msgstr "Premier ID POSIX de la plage" msgid "Number of IDs in the range" msgstr "Nombre d'IDs dans la plage" msgid "First RID of the corresponding RID range" msgstr "Premier RID dans la plage de RID correspondante" msgid "First RID of the secondary RID range" msgstr "Premier RID dans la plage de RID secondaire" msgid "Domain SID of the trusted domain" msgstr "SID du domaine à approuver" msgid "Name of the trusted domain" msgstr "Nom du domaine à approuver" msgid "Range type" msgstr "Type de plage" msgid "ID range type, one of {vals}" msgstr "Type de plage d'identifiants, valeur à prendre parmi {vals}" msgid "" "range modification leaving objects with ID out of the defined range is not " "allowed" msgstr "" "la modification de plage laissant des objets ayant un ID en dehors de la " "plage n'est pas autorisée" msgid "" "Cannot perform SID validation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA on the server" msgstr "" "Impossible de réaliser la validation de SID sans installer la prise en " "charge Samba 4. Assurez-vous d'avoir installé le sous-paquet IPAserver-trust-" "ad sub-package sur le serveur" msgid "" "Cross-realm trusts are not configured. Make sure you have run ipa-adtrust-" "install on the IPA server first" msgstr "" "Les approbations de domaines n'ont pas été configurées. Assurez-vous d'avoir " "d'abord lancé ipa-adtrust-install sur le serveur" msgid "SID is not recognized as a valid SID for a trusted domain" msgstr "Le SID n'est pas reconnu comme SID valide pour un domaine approuvé" msgid "" "\n" " Add new ID range.\n" "\n" " To add a new ID range you always have to specify\n" "\n" " --base-id\n" " --range-size\n" "\n" " Additionally\n" "\n" " --rid-base\n" " --secondary-rid-base\n" "\n" " may be given for a new ID range for the local domain while\n" "\n" " --rid-base\n" " --dom-sid\n" "\n" " must be given to add a new range for a trusted AD domain.\n" "\n" " WARNING:\n" "\n" " DNA plugin in 389-ds will allocate IDs based on the ranges configured " "for the\n" " local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" " on the local ranges set via this family of commands.\n" "\n" " Manual configuration change has to be done in the DNA plugin " "configuration for\n" " the new local range. Specifically, The dnaNextRange attribute of " "'cn=Posix\n" " IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has " "to be\n" " modified to match the new range.\n" " " msgstr "" "\n" "Ajouter une nouvelle plage d'identifiants.\n" "\n" "Pour ajouter une nouvelle plage d'identifiants vous devez toujours préciser\n" "\n" "--base-id\n" "--range-size\n" "\n" "En outre\n" "\n" "--rid-base\n" "--secondary-rid-base\n" "\n" "doivent être indiqués pour une nouvelle plage d'identifiants dans le domaine " "local alors que\n" "\n" "--rid-base\n" "--dom-sid\n" "\n" "doivent l'être pour ajouter une nouvelle plage pour un domaine AD de " "confiance.\n" "\n" "AVERTISSEMENT :\n" "\n" "Le greffon DNA dans 389-ds allouera des ID suivant les plages configurées au " "titre du\n" "domaine local. Actuellement le greffon DNA *ne peut pas* être lui-même " "reconfiguré selon\n" "les plages locales définies par l'intermédiaire de cette famille de " "commandes.\n" "\n" "Un changement manuel de configuration doit être opéré dans la configuration " "du greffon DNA pour\n" "la nouvelle plage locale. En particulier, l'attribut dnaNextRange de " "« cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config » doivent " "être modifiés\n" "pour correspondre à cette nouvelle plage.\n" " " #, python-format msgid "Added ID range \"%(value)s\"" msgstr "Plage d'ID « %(value)s » ajoutée" msgid "Options dom-sid and dom-name cannot be used together" msgstr "" "Les options dom-sid et dom-name ne peuvent être utilisées simultanément" msgid "" "SID for the specified trusted domain name could not be found. Please specify " "the SID directly using dom-sid option." msgstr "" "Impossible de trouver le SID du domaine à approuver spécifié. Merci de " "spécifier le SID directement avec l'option dom-sid." msgid "" "IPA Range type must be one of ipa-ad-trust or ipa-ad-trust-posix when SID of " "the trusted domain is specified." msgstr "" "Le type de plage d'identifiants IPA doit être au choix ipa-ad-trust ou ipa-" "ad-trust-posix lorsque le SID du domaine approuvé est indiqué." msgid "Options dom-sid/dom-name and secondary-rid-base cannot be used together" msgstr "" "Les options dom-sid/dom-name et secondary-rid-base ne peuvent être utilisées " "simultanément" msgid "Options dom-sid/dom-name and rid-base must be used together" msgstr "" "Les options dom-sid/dom-name et rid-base doivent être utilisées simultanément" msgid "" "IPA Range type must not be one of ipa-ad-trust or ipa-ad-trust-posix when " "SID of the trusted domain is not specified." msgstr "" "Le type de plage d'identifiants IPA ne doit pas ipa-ad-trust ou ipa-ad-trust-" "posix lorsque le SID du domaine approuvé n'est pas indiqué." msgid "Options secondary-rid-base and rid-base must be used together" msgstr "" "Les options secondary-rid-base et rid-base doivent être utilisées " "simultanément" msgid "Primary RID range and secondary RID range cannot overlap" msgstr "Les plages de RID primaires et secondaires ne peuvent se recouvrir" msgid "" "You must specify both rid-base and secondary-rid-base options, because ipa-" "adtrust-install has already been run." msgstr "" "Vous devez préciser les deux options rid-base et secondary-rid-base, car ipa-" "adtrust-install a déjà été exécuté." msgid "Delete an ID range." msgstr "Supprimer une plage d'ID.." #, python-format msgid "Deleted ID range \"%(value)s\"" msgstr "Plage d'ID « %(value)s » supprimée" msgid "Search for ranges." msgstr "Rechercher des plages." #, python-format msgid "%(count)d range matched" msgid_plural "%(count)d ranges matched" msgstr[0] "%(count)d plage correspondante" msgstr[1] "%(count)d plages correspondantes" msgid "Display information about a range." msgstr "Afficher les informations sur une plage." msgid "Modify ID range." msgstr "Modifier une plage." #, python-format msgid "Modified ID range \"%(value)s\"" msgstr "Plage d'ID « %(value)s » modifiée" msgid "Options dom-sid and secondary-rid-base cannot be used together" msgstr "" "Les options dom-sid et secondary-rid-base ne peuvent être utilisées " "simultanément" msgid "Options dom-sid and rid-base must be used together" msgstr "Les options dom-sid et rid-base doivent être utilisées simultanément" msgid "Name of object to export" msgstr "Nom de l'objet à exporter" msgid "Name of method to export" msgstr "Nom de la méthode à exporter" msgid "Name of command to export" msgstr "Nom de la commande à exporter" msgid "Dict of JSON encoded IPA Objects" msgstr "Dictionnaire d'objets IPA encodés JSON" msgid "Dict of JSON encoded IPA Methods" msgstr "Dictionnaire de méthode IPA encodées JSON" msgid "Dict of JSON encoded IPA Commands" msgstr "Dictionnaire de commande IPA encodées en JSON" msgid "Your session has expired. Please re-login." msgstr "Votre session a expiré. Merci de vous reconnecter." msgid "Apply" msgstr "Appliquer" msgid "Are you sure you want to proceed with the action." msgstr "Êtes-vous sûr de vouloir procéder à cette action ?" msgid "Are you sure you want to delete ${object}" msgstr "Êtes-vous sûr de vouloir supprimer ${object} ?" msgid "Are you sure you want to disable ${object}" msgstr "Êtes-vous sûr de vouloir désactiver ${object} ?" msgid "Are you sure you want to enable ${object}" msgstr "Êtes-vous sûr de vouloir activer ${object} ?" msgid "Actions" msgstr "Actions" msgid "Add RunAs ${other_entity} into ${entity} ${primary_key}" msgstr "Ajouter RunAs ${other_entity} à ${entity} ${primary_key}" msgid "Add RunAs Groups into ${entity} ${primary_key}" msgstr "Ajouter RunAs Groups à ${entity} ${primary_key}" msgid "Add ${other_entity} Managing ${entity} ${primary_key}" msgstr "Ajouter ${other_entity} gérant ${entity} ${primary_key}" msgid "Add ${other_entity} into ${entity} ${primary_key}" msgstr "Ajouter un objet ${other_entity} à l'objet ${entity} ${primary_key}" msgid "Add Allow ${other_entity} into ${entity} ${primary_key}" msgstr "Ajouter Allow ${other_entity} à ${entity} ${primary_key}" msgid "Add Deny ${other_entity} into ${entity} ${primary_key}" msgstr "Ajouter Deny ${other_entity} à ${entity} ${primary_key}" msgid "Add ${entity} ${primary_key} into ${other_entity}" msgstr "Ajouter ${entity} ${primary_key} à ${other_entity}" msgid "${count} item(s) added" msgstr "${count} élément(s) ajouté(s)" msgid "Direct Membership" msgstr "Appartenance directe" msgid "Indirect Membership" msgstr "Appartenance indirecte" msgid "No entries." msgstr "Pas d'entrées." msgid "Showing ${start} to ${end} of ${total} entries." msgstr "Affichage des entrées ${start} à ${end} sur ${total}." msgid "Remove RunAs ${other_entity} from ${entity} ${primary_key}" msgstr "Supprimer RunAs${other_entity} de ${entity} ${primary_key}" msgid "Remove RunAs Groups from ${entity} ${primary_key}" msgstr "Supprimer RunAs Groups de ${entity} ${primary_key}" msgid "Remove ${other_entity} Managing ${entity} ${primary_key}" msgstr "Supprimer ${other_entity} gérant ${entity} ${primary_key}" msgid "Remove ${other_entity} from ${entity} ${primary_key}" msgstr "Supprimer l'objet ${other_entity} de l'objet ${entity} ${primary_key}" msgid "Remove Allow ${other_entity} from ${entity} ${primary_key}" msgstr "" "Supprimer l'autorisation de ${other_entity} de ${entity} ${primary_key}" msgid "Remove Deny ${other_entity} from ${entity} ${primary_key}" msgstr "" "Supprimer l'interdiction de ${other_entity} de ${entity} ${primary_key}" msgid "Remove ${entity} ${primary_key} from ${other_entity}" msgstr "Supprimer ${entity} ${primary_key} de ${other_entity}" msgid "${count} item(s) removed" msgstr "${count} élément(s) supprimé(s)" msgid "Show Results" msgstr "Afficher les résultats" msgid "Add" msgstr "Ajouter" msgid "Add and Add Another" msgstr "Ajouter, puis ajouter un nouveau" msgid "Add and Close" msgstr "Ajouter et fermer" msgid "Add and Edit" msgstr "Ajouter et modifier" msgid "Add Many" msgstr "Ajouter plusieurs" msgid "Back" msgstr "Retour" msgid "Cancel" msgstr "Annuler" msgid "Close" msgstr "Fermer" msgid "Disable" msgstr "Désactiver" msgid "Edit" msgstr "Modifier" msgid "Enable" msgstr "Activer" msgid "Find" msgstr "Rechercher" msgid "Get" msgstr "Obtenir" msgid "Issue" msgstr "Émettre" msgid "OK" msgstr "OK" msgid "Refresh" msgstr "Rafraîchir" msgid "Delete" msgstr "Supprimer" msgid "Reset" msgstr "Réinitialiser" msgid "Reset Password and Login" msgstr "R.À.Z. du mot de passe et de l'identifiant de connexion" msgid "Restore" msgstr "Restaurer" msgid "Retry" msgstr "Réessayer" msgid "Revoke" msgstr "Révoquer" msgid "Set" msgstr "Définir" msgid "Update" msgstr "Modifier" msgid "View" msgstr "Voir" msgid "Collapse All" msgstr "T" msgid "Expand All" msgstr "Tout déplier" msgid "General" msgstr "Général" msgid "Identity Settings" msgstr "Paramètres d'identité" msgid "${entity} ${primary_key} Settings" msgstr "Paramètres de l'objet ${entity} ${primary_key}" msgid "Back to Top" msgstr "Haut de page" msgid "${entity} ${primary_key} updated" msgstr "${entity} ${primary_key} modifié" msgid "${entity} successfully added" msgstr "${entity} ajoutée avec succès" msgid "Add ${entity}" msgstr "Ajouter ${entity}" msgid "Available" msgstr "Disponible" msgid "Some operations failed." msgstr "Certaines opérations ont échoué." msgid "Operations Error" msgstr "Erreur sur les opérations" msgid "Confirmation" msgstr "Confirmation" msgid "This page has unsaved changes. Please save or revert." msgstr "" "Cette page comporte des modifications non-sauvegardées. Merci de sauvegarder " "ou de réinitialiser." msgid "Unsaved Changes" msgstr "Modifications non sauvegardées" msgid "Edit ${entity}" msgstr "Modifier ${entity}" msgid "Hide details" msgstr "Cacher les détails" msgid "Prospective" msgstr "Potentiel" msgid "Redirection" msgstr "Redirection" msgid "Select entries to be removed." msgstr "Sélectionner les entrées à supprimer." msgid "Remove ${entity}" msgstr "Supprimer ${entity}" msgid "Show details" msgstr "Afficher les détails" msgid "Validation error" msgstr "Erreur de validation" msgid "Input form contains invalid or missing values." msgstr "Le formulaire de saisie comporte des valeurs invalides ou manquantes." msgid "Please try the following options:" msgstr "Merci d'essayer les alternatives suivantes :" msgid "If the problem persists please contact the system administrator." msgstr "" "Si le problème persiste, merci de contacter l'administrateur du système." msgid "Refresh the page." msgstr "Rafraîchir la page." msgid "Reload the browser." msgstr "Recharger le navigateur." msgid "Return to the main page and retry the operation" msgstr "Retourner à la page principale et retenter l'opération" msgid "An error has occurred (${error})" msgstr "Une erreur est survenue (${error})" msgid "HTTP Error" msgstr "Erreur HTTP" msgid "Internal Error" msgstr "Erreur interne" msgid "IPA Error" msgstr "Erreur IPA" msgid "No response" msgstr "Pas de réponse" msgid "Unknown Error" msgstr "Erreur inconnue" msgid "URL" msgstr "URL" msgid "${primary_key} is managed by:" msgstr "${primary_key} est gérée par :" msgid "${primary_key} members:" msgstr "membres ${primary_key} :" msgid "${primary_key} is a member of:" msgstr "${primary_key} est membre de :" msgid "Settings" msgstr "Paramètres" msgid "Search" msgstr "Rechercher" msgid "False" msgstr "Faux" msgid "Inherited from server configuration" msgstr "Hérité de la configuration du serveur" msgid "MS-PAC" msgstr "MS-PAC" msgid "Override inherited settings" msgstr "Surcharger la configuration héritée" msgid "PAD" msgstr "PAD" msgid "" "To login with username and password, enter them in the fields below then " "click Login." msgstr "" "Afin de vous connecter avec un nom d'utilisateur et un mot de passe, merci " "de les saisir dans les champs ci-dessous puis cliquer sur « Connexion »." msgid "Logged In As" msgstr "Connecté en tant que" msgid "" "To login with Kerberos, please make sure you have valid tickets (obtainable " "via kinit) and configured the browser correctly, then click Login." msgstr "" "Afin de se connecter avec Kerberos, il faut s'assurer d'avoir un ticket " "valide (via kinit), que le navigateur est configuré correctement, puis cliquer sur « Connexion " "»." msgid "Login" msgstr "Connexion" msgid "Logout" msgstr "Déconnexion" msgid "Logout error" msgstr "Erreur de déconnexion" msgid "Username" msgstr "Nom d'utilisateur" msgid "number of passwords" msgstr "nombre de mots de passe" msgid "seconds" msgstr "secondes" msgid "Attribute" msgstr "Attribut" msgid "Add Condition into ${pkey}" msgstr "Ajouter une condition à ${pkey}" msgid "Add Rule" msgstr "Ajouter une règle" msgid "Default host group" msgstr "Groupe de système par défaut" msgid "Default user group" msgstr "Groupe d'utilisateur par défaut" msgid "Exclusive" msgstr "Exclus" msgid "Expression" msgstr "Expression" msgid "Host group rule" msgstr "Règle de groupes de systèmes" msgid "Host group rules" msgstr "Règles de groupes de systèmes" msgid "Inclusive" msgstr "Inclus" msgid "User group rule" msgstr "Règle de groupe utilisateur" msgid "User group rules" msgstr "Règles de groupes d'utilisateurs" msgid "Automount Location Settings" msgstr "Détail d'un lieu d'automontage" msgid "Map Type" msgstr "Type de carte" msgid "Direct" msgstr "Direct" msgid "Indirect" msgstr "Indirect" msgid "AA Compromise" msgstr "Autorité d'attribut compromise" msgid "Affiliation Changed" msgstr "L'affiliation a changé" msgid "CA Compromise" msgstr "AC compromise" msgid "Certificates" msgstr "Certificats" msgid "Certificate Hold" msgstr "Certificat bloqué" msgid "Cessation of Operation" msgstr "Cessation d'activité" msgid "Common Name" msgstr "Nom usuel" msgid "Expires On" msgstr "Expire le" msgid "Issued on from" msgstr "Émis à partir du" msgid "Issued on to" msgstr "Émis jusqu'au" msgid "Maximum serial number" msgstr "Numéro de série maximum" msgid "Minimum serial number" msgstr "Numéro de série minimum" msgid "Revoked on from" msgstr "Révoqué à partir du" msgid "Revoked on to" msgstr "Révoqué jusqu'au" msgid "Valid not after from" msgstr "Invalide après, à partir du" msgid "Valid not after to" msgstr "Invalide après, jusqu'au" msgid "Valid not before from" msgstr "Invalide avant, à partir du" msgid "Valid not before to" msgstr "Invalide avant, jusqu'au" msgid "Fingerprints" msgstr "Condensés" msgid "Issue New Certificate for ${entity} ${primary_key}" msgstr "Émettre un nouveau certificat pour l'objet ${entity} ${primary_key}" msgid "Issued By" msgstr "Émis par" msgid "Issued On" msgstr "Émis le" msgid "Issued To" msgstr "Émis pour" msgid "Key Compromise" msgstr "Clé compromise" msgid "MD5 Fingerprint" msgstr "Condensé MD5" msgid "No Valid Certificate" msgstr "Pas de certificat valide" msgid "New Certificate" msgstr "Nouveau certificat" msgid "Note" msgstr "Note" msgid "Organization" msgstr "Organisation" msgid "Organizational Unit" msgstr "Unité organisationnelle" msgid "Privilege Withdrawn" msgstr "Privilège retiré" msgid "Reason for Revocation" msgstr "Raison de la révocation" msgid "Remove from CRL" msgstr "Retrait de la LRC" msgid "" "
  1. Create a certificate database or use an existing one. To create a " "new database:
    # certutil -N -d <database path>
  2. " "
  3. Create a CSR with subject CN=<hostname>,O=<realm>, " "for example:
    # certutil -R -d <database path> -a -g <key " "size> -s 'CN=${hostname},O=${realm}'
  4. Copy and paste the " "CSR (from -----BEGIN NEW CERTIFICATE REQUEST----- to -----END " "NEW CERTIFICATE REQUEST-----) into the text area below:
" msgstr "" "
  1. Créer une base de données de certificats ou utiliser une base " "existante. Pour créer une nouvelle  :
    # certutil -N -d <" "database path>
  2. Créer une demande de signature (CSR) de " "certificat avec le sujet CN=<hostname>,O=<realm>, par " "exemple :
    # certutil -R -d <database path> -a -g <key " "size> -s 'CN=${hostname},O=${realm}'
  3. Copier/coller le " "CSR (de -----BEGIN NEW CERTIFICATE REQUEST----- à -----END NEW " "CERTIFICATE REQUEST-----) dans la zone de texte ci-dessous :
" msgid "Certificate requested" msgstr "Certificat demandé" msgid "Restore Certificate for ${entity} ${primary_key}" msgstr "Restaurer un certificat pour ${entity} ${primary_key}" msgid "Restore Certificate" msgstr "Restaurer le certificat" msgid "" "To confirm your intention to restore this certificate, click the \"Restore\" " "button." msgstr "" "Afin de confirmer votre intention de restaurer ce certificat, cliquer sur le " "bouton \"Restaurer\"." msgid "Certificate restored" msgstr "Certificat restauré" msgid "Revoke Certificate for ${entity} ${primary_key}" msgstr "Révoquer un certificat pour l'objet ${entity} ${primary_key}" msgid "Revoke Certificate" msgstr "Révoquer le certificat" msgid "" "To confirm your intention to revoke this certificate, select a reason from " "the pull-down list, and click the \"Revoke\" button." msgstr "" "Afin de confirmer votre intention de révoquer ce certificat, sélectionner " "une raison dans la liste, puis de cliquer sur le bouton \"Révoquer\"." msgid "Certificate Revoked" msgstr "Certificat révoqué" msgid "SHA1 Fingerprint" msgstr "Condensé SHA1" msgid "Superseded" msgstr "Obsolète" msgid "Unspecified" msgstr "Non-spécifié" msgid "Valid Certificate Present" msgstr "Certificat validé présent" msgid "Validity" msgstr "Validité" msgid "Certificate for ${entity} ${primary_key}" msgstr "Certificat pour l'objet ${entity} ${primary_key}" msgid "Group Options" msgstr "Options de groupe" msgid "Search Options" msgstr "Options de recherche" msgid "SELinux Options" msgstr "Options SELinux" msgid "Service Options" msgstr "Options du service" msgid "User Options" msgstr "Options utilisateurs" msgid "Forward first" msgstr "Forward first" msgid "Forwarding disabled" msgstr "Transmission désactivée" msgid "Forward only" msgstr "Forward only" msgid "Options" msgstr "Options" msgid "Data" msgstr "Données" msgid "DNS record was deleted because it contained no data." msgstr "L'enregistrement DNS a été supprimé car vide" msgid "Other Record Types" msgstr "Autres types d'enregistrements" msgid "Address not valid, can't redirect" msgstr "Adresse invalide, impossible de rediriger" msgid "Create dns record" msgstr "Créer un enregistrement DNS" msgid "Creating record." msgstr "Création de l'enregistrement." msgid "Record creation failed." msgstr "La création de l'enregistrement a échoué." msgid "Checking if record exists." msgstr "Vérification de l'existence de l'enregistrement." msgid "Record not found." msgstr "Enregistrement non trouvé." msgid "Redirection to PTR record" msgstr "Redirection vers l'enregistrement PTR" msgid "Zone found: ${zone}" msgstr "Zone trouvée : ${zone}" msgid "Target reverse zone not found." msgstr "Zone inverse cible non trouvée." msgid "Fetching DNS zones." msgstr "Récupération des zones DNS." msgid "An error occurred while fetching dns zones." msgstr "Une erreur est survenue lors de la récupération des zones DNS." msgid "You will be redirected to DNS Zone." msgstr "Vous allez être redirigé vers la zone DNS." msgid "Standard Record Types" msgstr "Types d'enregistrement standard" msgid "Records for DNS Zone" msgstr "Enregistrements pour la zone DNS" msgid "Record Type" msgstr "Type d'enregistrement" msgid "DNS Zone Settings" msgstr "Paramètres de zone DNS" msgid "Add Permission" msgstr "Ajouter une permission" msgid "Remove Permission" msgstr "Supprimer une permission" msgid "Group Settings" msgstr "Paramètres de groupe" msgid "External" msgstr "Externe" msgid "Change to external group" msgstr "Transformer en groupe externe" msgid "Change to POSIX group" msgstr "Transformer en groupe POSIX" msgid "Normal" msgstr "Normal" msgid "POSIX" msgstr "POSIX" msgid "Group Type" msgstr "Type de groupe" msgid "Any Host" msgstr "N'importe quel système" msgid "Any Service" msgstr "N'importe quel service" msgid "Anyone" msgstr "N'importe qui" msgid "Accessing" msgstr "Accédant à" msgid "Rule status" msgstr "État de la règle" msgid "Via Service" msgstr "Via le service" msgid "Specified Hosts and Groups" msgstr "Systèmes et groupes spécifiques" msgid "Specified Services and Groups" msgstr "Services et groupes spécifiques" msgid "Specified Users and Groups" msgstr "Utilisateurs et groupes spécifiques" msgid "Who" msgstr "Qui" msgid "Access Denied" msgstr "Accès interdit" msgid "Access Granted" msgstr "Accès autorisé" msgid "Include Disabled" msgstr "Inclusion désactivée" msgid "Include Enabled" msgstr "Inclusion activée" msgid "HBAC Test" msgstr "Test HBAC" msgid "Matched" msgstr "Correspondance" msgid "Missing values: " msgstr "Valeurs manquantes :" msgid "New Test" msgstr "Nouveau test" msgid "Rules" msgstr "Règles" msgid "Run Test" msgstr "Lancer test" msgid "Specify external ${entity}" msgstr "Spécifier un ${entity} externe" msgid "Unmatched" msgstr "Pas de correspondance" msgid "Host Certificate" msgstr "Certificat de système" msgid "Host Name" msgstr "Nom de système" msgid "Delete Key, Unprovision" msgstr "Supprimer la clé, décommissionner" msgid "Host Settings" msgstr "Paramètres de système" msgid "Enrolled" msgstr "Enregistré" msgid "Enrollment" msgstr "Inscription" msgid "Fully Qualified Host Name" msgstr "Nom de système pleinement qualifié" msgid "Kerberos Key" msgstr "Clé Kerberos" msgid "Kerberos Key Not Present" msgstr "Clé Kerberos absente" msgid "Kerberos Key Present, Host Provisioned" msgstr "Clé Kerberos présente, système provisionné" msgid "One-Time-Password" msgstr "Mot de passe à usage unique" msgid "One-Time-Password Not Present" msgstr "Absence de mot de passe à usage unique" msgid "One-Time-Password Present" msgstr "Présence de mot de passe à usage unique" msgid "Reset OTP" msgstr "Remise à zéro OTP" msgid "Reset One-Time-Password" msgstr "Remise à zéro du mot de passe à usage unique" msgid "Set OTP" msgstr "Paramétrer le mot de passe à usage unique" msgid "OTP set" msgstr "OTP configuré" msgid "Set One-Time-Password" msgstr "Définir mot de passe à usage unique" msgid "Unprovision" msgstr "Décommissioner" msgid "Are you sure you want to unprovision this host?" msgstr "Êtes-vous sûr de vouloir décommissionner ce système ?" msgid "Unprovisioning ${entity}" msgstr "Décommissionnement de l'objet ${entity}" msgid "Host unprovisioned" msgstr "Système déprovisionné" msgid "Host Group Settings" msgstr "Paramètres du groupe de systèmes" msgid "Kerberos Ticket Policy" msgstr "Politique de ticket Kerberos" msgid "Netgroup Settings" msgstr "Paramètres du netgroup" msgid "User" msgstr "Utilisateur" msgid "Identity" msgstr "Identité" msgid "Permission with invalid target specification" msgstr "Permission avec spécification de cible invalide" msgid "Privilege Settings" msgstr "Paramètres du privilège" msgid "Password Policy" msgstr "Politique de gestion des mots de passe" msgid "Range Settings" msgstr "Configuration des plages" msgid "Base ID" msgstr "ID de base" msgid "Primary RID base" msgstr "Base de RID primaire" msgid "Range size" msgstr "Taille de la plage" msgid "Domain SID" msgstr "SID du domaine" msgid "Secondary RID base" msgstr "Base de RID secondaire" msgid "Active Directory domain" msgstr "Domaine Active Directory" msgid "Active Directory domain with POSIX attributes" msgstr "Domaine Active Directory avec attributs POSIX" msgid "Local domain" msgstr "Domaine local :" msgid "IPA trust" msgstr "Relations d'approbations avec IPA" msgid "Active Directory winsync" msgstr "Active Directory winsync" msgid "Realm Domains" msgstr "Domaines" msgid "Check DNS" msgstr "Vérification DNS" msgid "Do you also want to perform DNS check?" msgstr "Voulez-vous aussi faire une vérification DNS ?" msgid "Force Update" msgstr "Forcer la mise à jour" msgid "Role Settings" msgstr "Paramètres de rôles" msgid "Service Certificate" msgstr "Certificat de service" msgid "Service Settings" msgstr "Paramètres de service" msgid "Provisioning" msgstr "Commissionnement" msgid "Are you sure you want to unprovision this service?" msgstr "Êtes-vous sûr de vouloir décommissionner ce service ?" msgid "Service unprovisioned" msgstr "Service décommissionné" msgid "Kerberos Key Present, Service Provisioned" msgstr "Clé Kerberos présente, service commissionné" msgid "SSH public keys" msgstr "Clés publiques SSH" msgid "SSH public key:" msgstr "Clé publique SSH :" msgid "Set SSH key" msgstr "Définir la clé SSH" msgid "Show/Set key" msgstr "Afficher/définir la clé" msgid "Modified: key not set" msgstr "Modifié : clé non définie" msgid "Modified" msgstr "Modifié" msgid "New: key not set" msgstr "Ajout : clé non définie" msgid "New: key set" msgstr "Ajout : clé définie" msgid "Groups" msgstr "Groupes" msgid "Commands" msgstr "Commandes" msgid "Allow" msgstr "Autoriser" msgid "Any Command" msgstr "Toute commande" msgid "Any Group" msgstr "Tout groupe" msgid "Run Commands" msgstr "Exécute les commandes" msgid "Deny" msgstr "Interdire" msgid "Access this host" msgstr "Accède ce système" msgid "Option added" msgstr "Option ajoutée" msgid "${count} option(s) removed" msgstr "${count} option(s) supprimée(s)" msgid "As Whom" msgstr "En tant que" msgid "Specified Commands and Groups" msgstr "Commandes et groupes spécifiés" msgid "Specified Groups" msgstr "Groupes spécifiés" msgid "Account" msgstr "Compte" msgid "Administrative account" msgstr "Compte administrateur" msgid "SID blacklists" msgstr "Listes noires de SID" msgid "Trust Settings" msgstr "Configuration des approbations" msgid "Domain" msgstr "Domaine" msgid "Establish using" msgstr "Établir en utilisant" msgid "Domain NetBIOS name" msgstr "Nom de domaine NetBIOS" msgid "Domain Security Identifier" msgstr "Identifiant de sécurité du domaine" msgid "Pre-shared password" msgstr "Mot de passe pré-partagé" msgid "Trust direction" msgstr "Sens de l'approbation" msgid "Trust status" msgstr "État de l'approbation" msgid "Trust type" msgstr "Type d'approbation" msgid "Account Settings" msgstr "Paramètres de compte" msgid "Account Status" msgstr "État du compte" msgid "Contact Settings" msgstr "Paramètres de contact" msgid "Employee Information" msgstr "Informations employé" msgid "Error changing account status" msgstr "Erreur lors du changement d'état du compte" msgid "Password expiration" msgstr "Expiration de mot de passe" msgid "Mailing Address" msgstr "Adresse postale" msgid "Misc. Information" msgstr "Informations diverses" msgid "" "Are you sure you want to ${action} the user?
The change will take effect " "immediately." msgstr "" "Êtes-vous sûr de vouloir ${action} l'utilisateur ?
Le changement prendra " "effet immédiatement." msgid "Click to ${action}" msgstr "Cliquer pour ${action}." msgid "Current Password" msgstr "Mot de passe actuel" msgid "Current password is required" msgstr "Le mot de passe actuel est requis" msgid "Your password expires in ${days} days." msgstr "Votre mot de passe expire dans ${days} jours." msgid "The password or username you entered is incorrect." msgstr "Le mot de passe ou le nom d'utilisateur entré est incorrect." msgid "New Password" msgstr "Nouveau mot de passe" msgid "New password is required" msgstr "Un nouveau mot de passe est requis" msgid "Password change complete" msgstr "Modification du mot de passe terminée" msgid "Passwords must match" msgstr "Les mots de passe doivent correspondre" msgid "Password reset was not successful." msgstr "La réinitialisation du mot de passe a échoué." msgid "Reset Password" msgstr "Réinitialiser le mot de passe" msgid "Reset your password." msgstr "Réinitialiser votre mot de passe." msgid "Verify Password" msgstr "Vérifier le mot de passe" msgid "Are you sure you want to delete selected entries?" msgstr "Êtes-vous sûr de vouloir supprimer les entrées sélectionnées ?" msgid "${count} item(s) deleted" msgstr "${count} élément(s) supprimé(s)" msgid "Are you sure you want to disable selected entries?" msgstr "Êtes-vous sûr de vouloir désactiver les entrées sélectionnées ?" msgid "${count} item(s) disabled" msgstr "${count} élément(s) désactivé(s)" msgid "Are you sure you want to enable selected entries?" msgstr "Êtes-vous sûr de vouloir activer les entrées sélectionnées ?" msgid "${count} item(s) enabled" msgstr "${count} élément(s) activé(s)" msgid "Some entries were not deleted" msgstr "Certaines entrées n'ont pas été supprimées" msgid "Quick Links" msgstr "Liens rapides" msgid "Select All" msgstr "Tout sélectionner" msgid "" "Query returned more results than the configured size limit. Displaying the " "first ${counter} results." msgstr "" "La recherche a retourné plus de résultats que le nombre limite configuré. " "Affichage des ${counter} premiers résultats." msgid "Unselect All" msgstr "Tout déselectionner" msgid "Disabled" msgstr "Désactivé" msgid "Audit" msgstr "Audit" msgid "Automember" msgstr "Auto-adhésion" msgid "Automount" msgstr "Automontage" msgid "DNS" msgstr "DNS" msgid "Host Based Access Control" msgstr "Contrôlé d'accès basé sur les systèmes (HBAC)" msgid "IPA Server" msgstr "Serveur IPA" msgid "Policy" msgstr "Politique" msgid "Role Based Access Control" msgstr "Contrôle d'accès basé sur les rôles" msgid "Sudo" msgstr "Sudo" msgid "Trusts" msgstr "Approbations" msgid "True" msgstr "Vrai" msgid "Next" msgstr "Suivant(e)" msgid "Page" msgstr "Page" msgid "Prev" msgstr "Précédent(e)" msgid "undo" msgstr "défaire" msgid "undo all" msgstr "tout défaire" msgid "Text does not match field pattern" msgstr "Le texte ne correspond pas au motif de champ" msgid "Must be a decimal number" msgstr "Doit être un nombre décimal" msgid "Must be an integer" msgstr "Doit être un entier" msgid "Not a valid IP address" msgstr "Pas une adresse IP valide" msgid "Not a valid IPv4 address" msgstr "Pas une adresse IPv4 valide" msgid "Not a valid IPv6 address" msgstr "Pas une adresse IPv6 valide" msgid "Maximum value is ${value}" msgstr "La valeur maximale est ${value}" msgid "Minimum value is ${value}" msgstr "La valeur minimale est ${value}" msgid "Not a valid network address" msgstr "Pas une adresse réseau valide" msgid "'${port}' is not a valid port" msgstr "« ${port} » n'est pas un port valide" msgid "Required field" msgstr "Champ requis" msgid "Unsupported value" msgstr "Valeur non supportée" msgid "Dict of I18N messages" msgstr "Dictionnaire de messages I18N" msgid "" "\n" "Kerberos ticket policy\n" "\n" "There is a single Kerberos ticket policy. This policy defines the\n" "maximum ticket lifetime and the maximum renewal age, the period during\n" "which the ticket is renewable.\n" "\n" "You can also create a per-user ticket policy by specifying the user login.\n" "\n" "For changes to the global policy to take effect, restarting the KDC service\n" "is required, which can be achieved using:\n" "\n" "service krb5kdc restart\n" "\n" "Changes to per-user policies take effect immediately for newly requested\n" "tickets (e.g. when the user next runs kinit).\n" "\n" "EXAMPLES:\n" "\n" " Display the current Kerberos ticket policy:\n" " ipa krbtpolicy-show\n" "\n" " Reset the policy to the default:\n" " ipa krbtpolicy-reset\n" "\n" " Modify the policy to 8 hours max life, 1-day max renewal:\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Display effective Kerberos ticket policy for user 'admin':\n" " ipa krbtpolicy-show admin\n" "\n" " Reset per-user policy for user 'admin':\n" " ipa krbtpolicy-reset admin\n" "\n" " Modify per-user policy for user 'admin':\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgstr "" "\n" "Politique de ticket Kerberos\n" "\n" "Il n'existe qu'une unique politique de ticket Kerberos. Cette politique\n" "définit la durée de vie maximale des tickets, ainsi que l'âge maximal de\n" "renouvellement, période pendant laquelle le ticket est renouvelable.\n" "\n" "Vous pouvez aussi créer une politique par utilisateur en spécifiant\n" "l'identifiant de l'utilisateur.\n" "\n" "Pour que les changements à la politique globale s'appliquent, il est \n" "nécessaire de redémarrer le service KDC, par exemple :\n" "\n" "service krb5kdc restart\n" "\n" "Les changements à une politique spécifique à un utilisateur prennent effet\n" "immédiatement pour les tickets nouvellement demandés (i.e. quand\n" "l'utilisateur lance kinit).\n" "\n" "EXEMPLES :\n" "\n" " Affiche la politique actuelle de ticket Kerberos :\n" " ipa krbtpolicy-show\n" "\n" " Réinitialise la politique aux valeurs par défaut :\n" " ipa krbtpolicy-reset\n" "\n" " Modifie la politique à 8 heures de durée de vie, 1 journée de durée\n" " maximale de renouvellement :\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Affiche la politique actuelle de ticket Kerberos de l'utilisateur " "'admin' :\n" " ipa krbtpolicy-show admin\n" "\n" " Réinitialise la politique de ticket Kerberos de l'utilisateur 'admin' :\n" " ipa krbtpolicy-reset admin\n" "\n" " Modifie la politique de ticket Kerberos de l'utilisateur 'admin' :\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgid "kerberos ticket policy settings" msgstr "configuration de la politique de ticket Kerberos" msgid "Manage ticket policy for specific user" msgstr "Administre la politique de ticket d'un utilisateur spécifique" msgid "Max life" msgstr "Vie max." msgid "Maximum ticket life (seconds)" msgstr "Durée de vie maximale (secondes)" msgid "Max renew" msgstr "Renouvellement max." msgid "Maximum renewable age (seconds)" msgstr "Âge maximale de renouvellement (secondes)" msgid "Modify Kerberos ticket policy." msgstr "Modifier la politique de ticket Kerberos." msgid "Display the current Kerberos ticket policy." msgstr "Afficher la politique de ticket Kerberos." msgid "Reset Kerberos ticket policy to the default values." msgstr "Réinitialiser la politique de ticket Kerberos." msgid "" "\n" "Migration to IPA\n" "\n" "Migrate users and groups from an LDAP server to IPA.\n" "\n" "This performs an LDAP query against the remote server searching for\n" "users and groups in a container. In order to migrate passwords you need\n" "to bind as a user that can read the userPassword attribute on the remote\n" "server. This is generally restricted to high-level admins such as\n" "cn=Directory Manager in 389-ds (this is the default bind user).\n" "\n" "The default user container is ou=People.\n" "\n" "The default group container is ou=Groups.\n" "\n" "Users and groups that already exist on the IPA server are skipped.\n" "\n" "Two LDAP schemas define how group members are stored: RFC2307 and\n" "RFC2307bis. RFC2307bis uses member and uniquemember to specify group\n" "members, RFC2307 uses memberUid. The default schema is RFC2307bis.\n" "\n" "The schema compat feature allows IPA to reformat data for systems that\n" "do not support RFC2307bis. It is recommended that this feature is disabled\n" "during migration to reduce system overhead. It can be re-enabled after\n" "migration. To migrate with it enabled use the \"--with-compat\" option.\n" "\n" "Migrated users do not have Kerberos credentials, they have only their\n" "LDAP password. To complete the migration process, users need to go\n" "to http://ipa.example.com/ipa/migration and authenticate using their\n" "LDAP password in order to generate their Kerberos credentials.\n" "\n" "Migration is disabled by default. Use the command ipa config-mod to\n" "enable it:\n" "\n" " ipa config-mod --enable-migration=TRUE\n" "\n" "If a base DN is not provided with --basedn then IPA will use either\n" "the value of defaultNamingContext if it is set or the first value\n" "in namingContexts set in the root of the remote LDAP server.\n" "\n" "Users are added as members to the default user group. This can be a\n" "time-intensive task so during migration this is done in a batch\n" "mode for every 100 users. As a result there will be a window in which\n" "users will be added to IPA but will not be members of the default\n" "user group.\n" "\n" "EXAMPLES:\n" "\n" " The simplest migration, accepting all defaults:\n" " ipa migrate-ds ldap://ds.example.com:389\n" "\n" " Specify the user and group container. This can be used to migrate user\n" " and group data from an IPA v1 server:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Since IPA v2 server already contain predefined groups that may collide " "with\n" " groups in migrated (IPA v1) server (for example admins, ipausers), users\n" " having colliding group as their primary group may happen to belong to\n" " an unknown group on new IPA v2 server.\n" " Use --group-overwrite-gid option to overwrite GID of already existing " "groups\n" " to prevent this issue:\n" " ipa migrate-ds --group-overwrite-gid \\\n" " --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Migrated users or groups may have object class and accompanied attributes\n" " unknown to the IPA v2 server. These object classes and attributes may be\n" " left out of the migration process:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " --user-ignore-objectclass=radiusprofile \\\n" " --user-ignore-attribute=radiusgroupname \\\n" " ldap://ds.example.com:389\n" "\n" "LOGGING\n" "\n" "Migration will log warnings and errors to the Apache error log. This\n" "file should be evaluated post-migration to correct or investigate any\n" "issues that were discovered.\n" "\n" "For every 100 users migrated an info-level message will be displayed to\n" "give the current progress and duration to make it possible to track\n" "the progress of migration.\n" "\n" "If the log level is debug, either by setting debug = True in\n" "/etc/ipa/default.conf or /etc/ipa/server.conf, then an entry will be " "printed\n" "for each user added plus a summary when the default user group is\n" "updated.\n" msgstr "" "\n" "Migration vers IPA\n" "\n" "Faire migrer des utilisateurs et des groupes d'un serveur LDAP vers IPA.\n" "\n" "Ceci réalise une requête LDAP sur le serveur distant pour rechercher\n" "utilisateurs et groupes dans un conteneur. Pour faire migrer les mots de " "passe, vous devez\n" "vous connecter en tant qu'utilisateur capable de lire l'attribut " "userPassword sur le serveur\n" "distant. La chose est généralement réservée aux administrateurs de haut " "niveau comme le\n" "cn=Directory Manager dans 389-ds (utilisateur de la connexion par défaut).\n" "\n" "Par défaut, le conteneur utilisateur est ou=People.\n" "\n" "Par défaut, le conteneur groupe est ou=Groups.\n" "\n" "Utilisateurs et groupes préexistants sur le serveur IPA sont laissés de " "côté.\n" "\n" "Deux schémas LDAP définissent comment les membres du groupe sont " "enregistrés : RFC2307 et\n" "RFC2307bis. RFC2307bis utilise member et uniquemember pour définir les " "membres du groupe,\n" "RFC2307 utilise memberUid. Le schéma par défaut est RFC2307bis.\n" "\n" "La fonctionnalité du schéma compat autorise IPA à formater à nouveau les " "données pour les\n" "systèmes ne prenant pas en charge RFC2307bis. Il est recommandé de " "désactiver cette fonction\n" "pendant la migration pour éviter des dépassements de capacité. Vous la " "réactiverez après\n" "migration. Pour faire la migration avec la fonction activée,utilisez " "l'option \"--with-compat\".\n" "\n" "Les utilisateurs émigrés n'ont pas de références Kerberos, ils n'ont que " "leur mot de passe\n" "LDAP. Pour achever le processus de migration, les utilisateurs doivent aller " "à la page\n" "http://ipa.example.com/ipa/migration et s'authentifier en utilisant leur mot " "de passe\n" "LDAP pour générer leur justificatif d'identité Kerberos.\n" "\n" "Par défaut, la migration est désactivée. Utilisez la commande ipa config-mod " "pour\n" "l'activer :\n" "\n" " ipa config-mod --enable-migration=TRUE\n" "\n" "Si un DN de base n'est pas indiqué avec --basedn, IPA utilise alors, soit\n" "la valeur de defaultNamingContext si elle est définie, soit la première " "valeur fixée\n" "dans namingContexts dans la racine du serveur LDAP distant.\n" "\n" "Les utilisateurs sont ajoutés comme membres du groupe utilisateur par " "défaut. Cela peut être\n" "une tâche consommatrice de temps, ainsi pendant la migration cela se fait en " "mode batch\n" "tous les 100 utilisateurs. Il en résulte une fenêtre dans laquelle les " "utilisateurs sont\n" "ajoutés à IPA mais sans être des membres du groupe d'utilisateurs par " "défaut.\n" "\n" "\n" "EXEMPLES :\n" "\n" " La migration la plus simple, acceptant tous les paramètres par défaut :\n" " ipa migrate-ds ldap://ds.example.com:389\n" "\n" " En précisant le conteneur utilisateur et groupe. S'utilise pour migrer les " "données\n" " utilisateur et groupe d'un serveur IPA v1 :\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Comme un serveur IPA v2 comporte déjà des groupes prédéfinis pouvant entrer " "en conflit avec\n" " des groupes du serveur IPA v1) migré (par exemple admins, ipausers), des " "utilisateurs avec\n" " un groupe conflictuel comme groupe principal peuvent se voir rattachés à un " "groupe inconnu\n" " sur le nouveau serveur IPA v2.\n" " Utilisez l'option --group-overwrite-gid pour écraser le GID des groupes " "préexistants\n" " afin d'éviter ce problème :\n" " ipa migrate-ds --group-overwrite-gid \\\n" " --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Des utilisateurs ou des groupes migrés peuvent posséder des classes d'objet " "et des attributs\n" " accompagnants inconnus du serveur IPA v2. Ces classes d'objets et attributs " "doivent être\n" " tenus hors du processus de migration :\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " --user-ignore-objectclass=radiusprofile \\\n" " --user-ignore-attribute=radiusgroupname \\\n" " ldap://ds.example.com:389\n" "\n" "JOURNALISATION\n" "\n" "La migration déclenchera des avertissements et des erreurs sur le journal " "d'erreurs Apache.\n" "Ce fichier devra être examiné après la migration pour corriger ou enquêter " "sur tout problème\n" "qui apparaîtrait.\n" "\n" "Tous les 100 utilisateurs migrés un message de niveau info est affiché " "indiquant\n" "l'avancement en cours et la durée écoulée pour permettre un suivi du " "processus\n" "de progression de la migration.\n" "\n" "Si le niveau de journalisation est debug, soit en définissant debug = True " "dans\n" "/etc/ipa/default.conf ou /etc/ipa/server.conf, alors une entrée sera " "affichée\n" "pour chaque utilisateur plus un résumé quand le groupe utilisateur par " "défaut\n" "est mis à jour.\n" #, python-format msgid "" "Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually." msgstr "" "Le principal Kerberos %s existe déjà. Utiliser la commande 'ipa user-mod' " "pour le créer manuellement." #, python-format msgid "" "Unable to determine if Kerberos principal %s already exists. Use 'ipa user-" "mod' to set it manually." msgstr "" "Impossible de savoir si le principal Kerberos %s existe déjà. Utiliser la " "commande 'ipa user-mod' pour le créer manuellement." msgid "" "Failed to add user to the default group. Use 'ipa group-add-member' to add " "manually." msgstr "" "Échec à l'ajout de l'utlisateur dans le groupe par défaut. Utiliser la " "commande 'ipa group-add-member' pour l'ajouter manuellement." msgid "Migration of LDAP search reference is not supported." msgstr "La migration de références de recherche LDAP n'est pas supportée." msgid "Malformed DN" msgstr "DN malformé" #, python-format msgid "%(user)s is not a POSIX user" msgstr "%(user)s n'est pas un utilisateur POSIX" msgid "" ". Check GID of the existing group. Use --group-overwrite-gid option to " "overwrite the GID" msgstr "" ". Vérifier le GID du groupe existant. Utiliser l'option --group-overwrite-" "gid pour réécrire le GID" msgid "Invalid LDAP URI." msgstr "URI LDAP invalide." msgid "Migrate users and groups from DS to IPA." msgstr "Migrer les utilisateurs et groupes de DS à IPA." msgid "LDAP URI" msgstr "URI LDAP" msgid "LDAP URI of DS server to migrate from" msgstr "URI LDAP du serveur d'annuaire depuis lequel migrer" msgid "bind password" msgstr "mot de passe de connexion" msgid "Bind DN" msgstr "DN de connexion" msgid "User container" msgstr "Conteneur d'utilisateurs" msgid "DN of container for users in DS relative to base DN" msgstr "" "DN du conteneur pour les utilisateurs dans l'annuaire, relatif par rapport " "au DN de base" msgid "Group container" msgstr "Conteneur de groupes" msgid "DN of container for groups in DS relative to base DN" msgstr "DN du conteneur pour les groupes relatif par rapport au DN de base" msgid "User object class" msgstr "Classes d'objet utilisateur" msgid "Objectclasses used to search for user entries in DS" msgstr "" "Classes d'objet à utiliser pour la recherche d'entrées utilisateurs dans " "l'annuaire" msgid "Group object class" msgstr "Classes d'objets groupes" msgid "Objectclasses used to search for group entries in DS" msgstr "" "Classes d'objet à utiliser pour la recherche d'entrées de groupes dans " "l'annuaire" msgid "Ignore user object class" msgstr "Ignorer une classe d'objet de l'utilisateur" msgid "Objectclasses to be ignored for user entries in DS" msgstr "" "Classes d'objets à ignorer pour les entrées utilisateurs dans l'annuaire" msgid "Ignore user attribute" msgstr "Ignorer des attributs d'un utilisateur" msgid "Attributes to be ignored for user entries in DS" msgstr "Attributs à ignorer dans les entrées utilisateurs dans l'annuaire" msgid "Ignore group object class" msgstr "Ignorer les classes d'objet des groupes" msgid "Objectclasses to be ignored for group entries in DS" msgstr "Classes d'objets à ignorer pour les entrées de groupes dans l'annuaire" msgid "Ignore group attribute" msgstr "Ignorer l'attribut groupe" msgid "Attributes to be ignored for group entries in DS" msgstr "Attributs à ignorer dans les entrées de groupes dans l'annuaire" msgid "Overwrite GID" msgstr "Réécrire le GID" msgid "" "When migrating a group already existing in IPA domain overwrite the group " "GID and report as success" msgstr "" "Lors de la migration d'un groupe existant déjà dans le domaine IPA, réécrire " "le GID du groupe et renvoyer un succès" msgid "LDAP schema" msgstr "Schéma LDAP" msgid "" "The schema used on the LDAP server. Supported values are RFC2307 and " "RFC2307bis. The default is RFC2307bis" msgstr "" "Le schéma utilisé sur le serveur LDAP. Les valeurs supportées sont RFC2307 " "et RFC2307bis. La valeur par défaut est RFC2307bis" msgid "Continue" msgstr "Continuer" msgid "" "Continuous operation mode. Errors are reported but the process continues" msgstr "Mode continu. Les erreurs sont rapportées mais le processus continue" msgid "Base DN" msgstr "DN de base" msgid "Base DN on remote LDAP server" msgstr "DN de base sur l'annuaire distant" msgid "Ignore compat plugin" msgstr "Ignorer le greffon de compatibilité" msgid "Allows migration despite the usage of compat plugin" msgstr "Autoriser les migrations malgré l'utilisation du greffon compat" msgid "Lists of objects migrated; categorized by type." msgstr "Liste des objets migrés, catégorisés par type." msgid "Lists of objects that could not be migrated; categorized by type." msgstr "Liste des objets n'ayant pu être migrés, catégorisés par type." msgid "False if migration mode was disabled." msgstr "Faux si le mode de migration est désactivé." msgid "False if migration fails because the compatibility plug-in is enabled." msgstr "" "False si la migration échoue parce que le greffon de compatibilité est " "activé." #, python-format msgid "%s to exclude from migration" msgstr "%s à exclure de la migration" msgid "" "search results for objects to be migrated\n" "have been truncated by the server;\n" "migration process might be incomplete\n" msgstr "" "les résultats de la recherche sur les objets\n" "à migrer a été tronquée par le server ; le\n" "processus peut donc être incomplet\n" msgid "Migration mode is disabled. Use 'ipa config-mod' to enable it." msgstr "" "Mode migration désactivé. Utiliser la commande 'ipa config-mod' pour " "l'activer." msgid "" "Passwords have been migrated in pre-hashed format.\n" "IPA is unable to generate Kerberos keys unless provided\n" "with clear text passwords. All migrated users need to\n" "login at https://your.domain/ipa/migration/ before they\n" "can use their Kerberos accounts." msgstr "" "Les mots de passe ont été migré dans leur format chiffré.\n" "IPA est incapable de créer des clés Kerberos sauf à\n" "utiliser les mots de passe en clair. Tous les utilisateurs\n" "migrés devront se connecter à https://your.domain/ipa/migration/\n" "avant de pouvoir utiliser leur compte Kerberos." #, python-format msgid "" "%(container)s LDAP search did not return any result (search base: " "%(search_base)s, objectclass: %(objectclass)s)" msgstr "" "La recherche LDAP %(container)s ne retourne aucun résultat (base de " "recherche : %(search_base)s, classe d'objet : %(objectclass)s)" msgid "Default group for new users not found" msgstr "Groupe par défaut pour les nouveaux utilisateurs introuvable" msgid "" "\n" "Misc plug-ins\n" msgstr "" "\n" "Greffons divers\n" msgid "Show environment variables." msgstr "Afficher les variables d'environnement." #, python-format msgid "%(count)d variables" msgstr "%(count)d variables" msgid "" "retrieve and print all attributes from the server. Affects command output." msgstr "" "récupère et affiche tous les attributs du serveur. Modifie la sortie de la " "commande." msgid "Total number of variables env (>= count)" msgstr "Nombre total de variables d'environnement (>= count)" msgid "Number of variables returned (<= total)" msgstr "Nombre de variables renvoyées (<= total)" msgid "Show all loaded plugins." msgstr "Afficher les greffons chargés." #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "%(count)d greffon chargé" msgstr[1] "%(count)d greffons chargés" msgid "Number of plugins loaded" msgstr "Nombre de greffons chargés" msgid "" "\n" "Netgroups\n" "\n" "A netgroup is a group used for permission checking. It can contain both\n" "user and host values.\n" "\n" "EXAMPLES:\n" "\n" " Add a new netgroup:\n" " ipa netgroup-add --desc=\"NFS admins\" admins\n" "\n" " Add members to the netgroup:\n" " ipa netgroup-add-member --users=tuser1 --users=tuser2 admins\n" "\n" " Remove a member from the netgroup:\n" " ipa netgroup-remove-member --users=tuser2 admins\n" "\n" " Display information about a netgroup:\n" " ipa netgroup-show admins\n" "\n" " Delete a netgroup:\n" " ipa netgroup-del admins\n" msgstr "" "\n" "Netgroups\n" "\n" "Un netgroup est un groupe utilisé pour la vérification de permissions. Il\n" "peut contenir à la fois des utilisateurs et des noms de systèmes.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau netgroup :\n" " ipa netgroup-add --desc=\"NFS admins\" admins\n" "\n" " Ajouter des membres au netgroup :\n" " ipa netgroup-add-member --users=tuser1 --users=tuser2 admins\n" "\n" " Retirer un membre du netgroup :\n" " ipa netgroup-remove-member --users=tuser2 admins\n" "\n" " Afficher les informations sur un netgroup :\n" " ipa netgroup-show admins\n" "\n" " Supprimer un netgroup :\n" " ipa netgroup-del admins\n" msgid "Member Host" msgstr "Système membre" msgid "netgroup" msgstr "netgroup" msgid "netgroups" msgstr "netgroups" msgid "Netgroups" msgstr "Netgroups" msgid "Netgroup" msgstr "Netgroup" msgid "Netgroup name" msgstr "Nom de netgroup" msgid "Netgroup description" msgstr "Description de netgroup" msgid "NIS domain name" msgstr "Nom de domaine NIS" msgid "IPA unique ID" msgstr "ID unique IPA" msgid "Add a new netgroup." msgstr "Ajouter un nouveau netgroup." #, python-format msgid "Added netgroup \"%(value)s\"" msgstr "Netgroup \"%(value)s\" ajouté" #, python-format msgid "" "hostgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "Un groupe de systèmes nommé « %s » existe déjà. Les groupes de systèmes et " "netgroups partagent le même espace de nommage" msgid "Delete a netgroup." msgstr "Supprimer un netgroup." #, python-format msgid "Deleted netgroup \"%(value)s\"" msgstr "Netgroup \"%(value)s\" supprimé" msgid "Modify a netgroup." msgstr "Modifier un netgroup." #, python-format msgid "Modified netgroup \"%(value)s\"" msgstr "Netgroup \"%(value)s\" supprimé" msgid "Search for a netgroup." msgstr "Rechercher un netgroup." #, python-format msgid "%(count)d netgroup matched" msgid_plural "%(count)d netgroups matched" msgstr[0] "%(count)d netgroup correspondant" msgstr[1] "%(count)d netgroups correspondants" msgid "search for managed groups" msgstr "rechercher les groupes administrés" msgid "Display information about a netgroup." msgstr "Afficher l'information sur un netgroup." msgid "Add members to a netgroup." msgstr "Ajouter des membres à un netgroup." msgid "Remove members from a netgroup." msgstr "Supprimer des membres d'un netgroup." msgid "" "\n" "Set a user's password\n" "\n" "If someone other than a user changes that user's password (e.g., Helpdesk\n" "resets it) then the password will need to be changed the first time it\n" "is used. This is so the end-user is the only one who knows the password.\n" "\n" "The IPA password policy controls how often a password may be changed,\n" "what strength requirements exist, and the length of the password history.\n" "\n" "EXAMPLES:\n" "\n" " To reset your own password:\n" " ipa passwd\n" "\n" " To change another user's password:\n" " ipa passwd tuser1\n" msgstr "" "\n" "Définir le mot de passe d'un utilisateur\n" "\n" "Si une personne autre que l'utilisateur change le mot de passe de cet\n" "utilisateur (par exemple en cas de réinitialisation par les services\n" "d'assistance technique), le mot de passe devra être modifié la première\n" "fois qu'il sera utilisé, afin que l'utilisateur soit le seul à connaître\n" "son mot de passe.\n" "\n" "La politique de mot de passe de IPA contrôle la fréquence de changement\n" "des mots de passe, les prérequis quant à leur résistance, et la taille\n" "de l'historique des mots de passe.\n" "\n" "EXEMPLES :\n" "\n" " Modifier son mot de passe :\n" " ipa passwd\n" "\n" " Modifier le mot de passe d'un utilisateur :\n" " ipa passwd tuser1\n" msgid "Set a user's password." msgstr "Définir le mot de passe d'un utilisateur." #, python-format msgid "Changed password for \"%(value)s\"" msgstr "Mot de passe modifié for \"%(value)s\"" msgid "Invalid credentials" msgstr "Données d'authentification invalides" msgid "" "\n" "Permissions\n" "\n" "A permission enables fine-grained delegation of rights. A permission is\n" "a human-readable form of a 389-ds Access Control Rule, or instruction " "(ACI).\n" "A permission grants the right to perform a specific task such as adding a\n" "user, modifying a group, etc.\n" "\n" "A permission may not contain other permissions.\n" "\n" "* A permission grants access to read, write, add or delete.\n" "* A privilege combines similar permissions (for example all the permissions\n" " needed to add a user).\n" "* A role grants a set of privileges to users, groups, hosts or hostgroups.\n" "\n" "A permission is made up of a number of different parts:\n" "\n" "1. The name of the permission.\n" "2. The target of the permission.\n" "3. The rights granted by the permission.\n" "\n" "Rights define what operations are allowed, and may be one or more\n" "of the following:\n" "1. write - write one or more attributes\n" "2. read - read one or more attributes\n" "3. add - add a new entry to the tree\n" "4. delete - delete an existing entry\n" "5. all - all permissions are granted\n" "\n" "Read permission is granted for most attributes by default so the read\n" "permission is not expected to be used very often.\n" "\n" "Note the distinction between attributes and entries. The permissions are\n" "independent, so being able to add a user does not mean that the user will\n" "be editable.\n" "\n" "There are a number of allowed targets:\n" "1. type: a type of object (user, group, etc).\n" "2. memberof: a member of a group or hostgroup\n" "3. filter: an LDAP filter\n" "4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a\n" " super-set of the \"type\" target.\n" "5. targetgroup: grant access to modify a specific group (such as granting\n" " the rights to manage group membership)\n" "\n" "EXAMPLES:\n" "\n" " Add a permission that grants the creation of users:\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Add a permission that grants the ability to manage group membership:\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgstr "" "\n" "Permissions\n" "\n" "Une permission permet une définition fine des délégations de droits. Une\n" "permission est une forme lisible par un humain des règles ou instructions\n" "de contrôle d'accès (ACI) de 389-ds. Une permission accorde le droit\n" "d'effectuer une tâche spécifique comme la création d'un utilisateur, la\n" "modification d'un groupe, etc.\n" "\n" "Une permission ne peut contenir d'autres permissions.\n" "\n" "* Une permission accorde un droit en lecture, écriture, ajout ou " "supression.\n" "* Un privilège combine des permissions similaires (par exemple toutes les\n" " permissions requises pour la création d'un utilisateur).\n" "* Un rôle accorde un jeu de privilèges à des utilisateurs, des groupes, des\n" " systèmes, ou à des groupes de systèmes.\n" "\n" "Une permission est constitués des éléments suivants :\n" "\n" "1. Le nom de la permission.\n" "2. La cible de la permission.\n" "3. Les droits accordés par la permission.\n" "\n" "Les droits définissent quelles opérations sont autorisées, et\n" "peuvent être une ou plusieurs parmi :\n" "1. write - écrire un ou plusieurs attributs\n" "2. read - lire un ou plusieurs attributs\n" "3. add - ajouter une nouvelle entrée dans l'arbre\n" "4. delete - supprimer une entrée existante\n" "5. all - toutes les permissions sont accordées\n" "\n" "La permission read est accordée par défaut sur la plupart des\n" "attributs, elle ne sera donc utilisée que peu souvent.\n" "\n" "Notez la distinction entre attributs and entrées. Les permissions sont\n" "indépendantes, donc la capacité de créer un utilisateur ne signifie pas\n" "que l'utilisateur sera modifiable.\n" "\n" "Il existe plusieurs sortes de cibles autorisées dans une permission :\n" "1. type: un type d'objet (user, group, etc.).\n" "2. memberof: un membre d'un groupe ou d'un groupe de systèmes\n" "3. filter: un filtre LDAP\n" "4. subtree: un filtre LDAP spécifiant une branche du DIT LDAP. Ceci est un\n" " sur-ensemble de la cible 'type'.\n" "5. targetgroup: accorde l'accès permettant de modifier un groupe spécifique\n" " (comme le fait d'accorder les droits en modification des membres d'un " "groupe)\n" "\n" "EXEMPLES :\n" "\n" " Ajouter une permission accordant la création d'utilisateurs :\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Ajouter une permission accordant la capacité de gérer les membres d'un " "groupe :\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgid "Permission Type" msgstr "Type de permission" msgid "permission" msgstr "permission" msgid "permissions" msgstr "permissions" msgid "Permission name" msgstr "Nom de permission" msgid "Permissions to grant (read, write, add, delete, all)" msgstr "Permissions à accorder (read, write, add, delete, all)" msgid "" "Type of IPA object (user, group, host, hostgroup, service, netgroup, dns)" msgstr "" "Type d'objet IPA (user, group, host, hostgroup, service, netgroup, dns)" msgid "Member of group" msgstr "Membre du groupe" msgid "Target members of a group" msgstr "Membres cible d'un groupe" msgid "Subtree to apply permissions to" msgstr "Branche sur laquelle appliquer les permissions" msgid "User group to apply permissions to" msgstr "Groupe d'utilisateur sur lequel appliquer les permissions" msgid "Add a new permission." msgstr "Ajouter une nouvelle permission." #, python-format msgid "Added permission \"%(value)s\"" msgstr "Permission \"%(value)s\" ajoutée" msgid "Add a system permission without an ACI" msgstr "Ajouter une permission système sans ACI" msgid "Permission type" msgstr "Type de permission" msgid "Delete a permission." msgstr "Supprimer une permission." #, python-format msgid "Deleted permission \"%(value)s\"" msgstr "Permission \"%(value)s\" supprimée" msgid "force delete of SYSTEM permissions" msgstr "forcer la suppression des permissions SYSTEM" msgid "A SYSTEM permission may not be removed" msgstr "Une permission SYSTEM ne peut être supprimée" msgid "Modify a permission." msgstr "Modifier une permission." #, python-format msgid "Modified permission \"%(value)s\"" msgstr "Permission \"%(value)s\" modifiée" msgid "A SYSTEM permission may not be modified" msgstr "Une permission SYSTEM ne peut être modifiée" msgid "New name can not be empty" msgstr "Un nouveau nom ne peut être vide" msgid "Search for permissions." msgstr "Recherche des permissions." #, python-format msgid "%(count)d permission matched" msgid_plural "%(count)d permissions matched" msgstr[0] "%(count)d permission correspondante" msgstr[1] "%(count)d permissions correspondantes" msgid "Display information about a permission." msgstr "Afficher les informations sur une permission." msgid "" "\n" "Ping the remote IPA server to ensure it is running.\n" "\n" "The ping command sends an echo request to an IPA server. The server\n" "returns its version information. This is used by an IPA client\n" "to confirm that the server is available and accepting requests.\n" "\n" "The server from xmlrpc_uri in /etc/ipa/default.conf is contacted first.\n" "If it does not respond then the client will contact any servers defined\n" "by ldap SRV records in DNS.\n" "\n" "EXAMPLES:\n" "\n" " Ping an IPA server:\n" " ipa ping\n" " ------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " ------------------------------------------\n" "\n" " Ping an IPA server verbosely:\n" " ipa -v ping\n" " ipa: INFO: trying https://ipa.example.com/ipa/xml\n" " ipa: INFO: Forwarding 'ping' to server 'https://ipa.example.com/ipa/xml'\n" " -----------------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " -----------------------------------------------------\n" msgstr "" "\n" "Ping sur le serveur distant IPA afin de s'assurer qu'il est en état de " "fonctionner.\n" "\n" "La commande ping envoie une requête echo au serveur IPA. Le serveur renvoie " "ses\n" "informations de version. Ce mécanisme est utilisé par le client IPA pour \n" "confirmer que le serveur est disponible et en mesure d'accepter les " "requêtes.\n" "\n" "Le serveur spécifié en xmlrpc_uri dans /etc/ipa/default.conf est contacté " "en \n" "premier. S'il ne répond pas alors le client contactera tout autre serveur " "défini\n" "dans les enregistrements SRV du DNS.\n" "\n" "EXEMPLES :\n" "\n" " Ping d'un serveur IPA :\n" " ipa ping\n" " ------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " ------------------------------------------\n" "\n" " Ping verbeux d'un serveur IPA :\n" " ipa -v ping\n" " ipa: INFO: trying https://ipa.example.com/ipa/xml\n" " ipa: INFO: Forwarding 'ping' to server u'https://ipa.example.com/ipa/" "xml'\n" " -----------------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " -----------------------------------------------------\n" msgid "Ping a remote server." msgstr "Ping sur un serveur distant." msgid "" "\n" "Kerberos pkinit options\n" "\n" "Enable or disable anonymous pkinit using the principal\n" "WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with\n" "pkinit support.\n" "\n" "EXAMPLES:\n" "\n" " Enable anonymous pkinit:\n" " ipa pkinit-anonymous enable\n" "\n" " Disable anonymous pkinit:\n" " ipa pkinit-anonymous disable\n" "\n" "For more information on anonymous pkinit see:\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgstr "" "\n" "Options Kerberos pkinit\n" "\n" "Active ou désactive l'opération pkinit anonyme utilisant\n" "le principal WELLKNOWN/ANONYMOUS@REALM. Le serveur doit avoir\n" "été installé avec le support pkinit.\n" "\n" "EXEMPLES :\n" "\n" " Active le pkinit anonyme :\n" " ipa pkinit-anonymous enable\n" "\n" " Désactive le pkinit anonyme :\n" " ipa pkinit-anonymous disable\n" "\n" "Pour plus d'informations sur l'opération pkinit anonyme, cf. :\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgid "pkinit" msgstr "pkinit" msgid "PKINIT" msgstr "PKINIT" #, python-format msgid "Unknown command %s" msgstr "Commande %s inconnue" msgid "Enable or Disable Anonymous PKINIT." msgstr "Active ou désactive le pkinit anonyme" msgid "" "\n" "Privileges\n" "\n" "A privilege combines permissions into a logical task. A permission provides\n" "the rights to do a single task. There are some IPA operations that require\n" "multiple permissions to succeed. A privilege is where permissions are\n" "combined in order to perform a specific task.\n" "\n" "For example, adding a user requires the following permissions:\n" " * Creating a new user entry\n" " * Resetting a user password\n" " * Adding the new user to the default IPA users group\n" "\n" "Combining these three low-level tasks into a higher level task in the\n" "form of a privilege named \"Add User\" makes it easier to manage Roles.\n" "\n" "A privilege may not contain other privileges.\n" "\n" "See role and permission for additional information.\n" msgstr "" "\n" "Privilèges\n" "\n" "Un privilège combine les permissions en tâches logiques. Une permission\n" "fournit les droits de réaliser une tâche unique. Certaines opérations IPA\n" "requièrent une combinaison de plusieurs permissions. Un privilège est la\n" "combinaison de ces permissions pour réaliser une tâche.\n" "\n" "Par example, la création d'utilisateur requiert les permissions suivantes :\n" " * Création d'une nouvelle entrée\n" " * Réinitialisation du mot de passe\n" " * Ajout du nouvel utilisateur au groupe d'utilisateurs par défaut de IPA\n" "\n" "La combinaison de ces trois tâches de bas niveau en privilège nommé \"Add " "User\"\n" "facilite la gestion des rôles.\n" "\n" "Un privilège ne peut contenir d'autres privilèges.\n" "\n" "Reportez-vous la gestion des rôles et des permissions pour plus " "d'informations.\n" msgid "privilege" msgstr "privilège" msgid "privileges" msgstr "privilèges" msgid "Privileges" msgstr "Privilèges" msgid "Privilege" msgstr "Privilège" msgid "Privilege name" msgstr "Nom du privilège" msgid "Privilege description" msgstr "Description du privilege" msgid "Add a new privilege." msgstr "Ajouter un nouveau privilège." #, python-format msgid "Added privilege \"%(value)s\"" msgstr "Privilège \"%(value)s\" ajouté" msgid "Delete a privilege." msgstr "Supprimer un privilège" #, python-format msgid "Deleted privilege \"%(value)s\"" msgstr "Privilège \"%(value)s\" supprimé" msgid "Modify a privilege." msgstr "Modifier un privilège." #, python-format msgid "Modified privilege \"%(value)s\"" msgstr "Privilège \"%(value)s\" supprimé" msgid "Search for privileges." msgstr "Rechercher des privilèges." #, python-format msgid "%(count)d privilege matched" msgid_plural "%(count)d privileges matched" msgstr[0] "%(count)d privilège correspondant" msgstr[1] "%(count)d privilèges correspondants" msgid "Display information about a privilege." msgstr "Afficher les informations sur un privilège." msgid "Add members to a privilege." msgstr "Ajouter des membres à un privilège." msgid "Add permissions to a privilege." msgstr "Ajouter des permissions à un privilège." msgid "Number of permissions added" msgstr "Nombre de permissions ajoutées" msgid "Remove permissions from a privilege." msgstr "Supprimer des permissions d'un privilège." msgid "Number of permissions removed" msgstr "Nombre de permissions supprimées" msgid "" "\n" "Password policy\n" "\n" "A password policy sets limitations on IPA passwords, including maximum\n" "lifetime, minimum lifetime, the number of passwords to save in\n" "history, the number of character classes required (for stronger passwords)\n" "and the minimum password length.\n" "\n" "By default there is a single, global policy for all users. You can also\n" "create a password policy to apply to a group. Each user is only subject\n" "to one password policy, either the group policy or the global policy. A\n" "group policy stands alone; it is not a super-set of the global policy plus\n" "custom settings.\n" "\n" "Each group password policy requires a unique priority setting. If a user\n" "is in multiple groups that have password policies, this priority determines\n" "which password policy is applied. A lower value indicates a higher priority\n" "policy.\n" "\n" "Group password policies are automatically removed when the groups they\n" "are associated with are removed.\n" "\n" "EXAMPLES:\n" "\n" " Modify the global policy:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Add a new group password policy:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Display the global password policy:\n" " ipa pwpolicy-show\n" "\n" " Display a group password policy:\n" " ipa pwpolicy-show localadmins\n" "\n" " Display the policy that would be applied to a given user:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modify a group password policy:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" msgstr "" "\n" "Politique de mots de passe\n" "\n" "Une politique de mots de passe permet de définir des limites sur les mots\n" "de passe dans IPA, comme leur durée de vie, minimale ou maximale, la taille\n" "de l'historique de mots de passe, le nombre de classes de caractères " "requises\n" "(pour la résistance à force brute) et la longueur minimale du mot de passe.\n" "\n" "Par défaut, une politique unique et globale est définie pour tous les\n" "utilisateurs. Vous pouvez aussi créer une politique à appliquer à un " "groupe.\n" "Chaque utilisateur est l'objet d'une seule politique de mots de passe, par\n" "un groupe ou par la politique globale. Une politique de groupe remplace\n" "totalement la politique globale ; elle n'est pas la somme de la politique\n" "globale plus quelques paramètres spécifiques.\n" "\n" "Chaque politique de groupe requiert un paramètre de priorité unique. Si un\n" "utilisateur appartient à plusieurs groupes ayant des politiques " "différentes,\n" "la priorité sera utilisée afin de déterminer quelle politique appliquer. " "Une\n" "valeur inférieure indique une priorité supérieure pour la politique de mots\n" "de passe.\n" "Les politiques de mots de passe sont automatiquement supprimées lorsque les\n" "groupes auxquels elles sont associées sont supprimés.\n" "\n" "EXEMPLES :\n" "\n" " Modifier la politique globale :\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Ajouter une nouvelle politique de groupe :\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Afficher la politique de mots de passe globale :\n" " ipa pwpolicy-show\n" "\n" " Afficher une politique de mots de passe de groupe :\n" " ipa pwpolicy-show localadmins\n" "\n" " Afficher la politique applicable à un utilisateur :\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modifier une politique de mots de passe de groupe :\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" #, python-format msgid "priority must be a unique value (%(prio)d already used by %(gname)s)" msgstr "" "la priorité doit être une valeur unique (%(prio)d déjà utilisée par " "%(gname)s)" msgid "password policy" msgstr "politique de mot de passe" msgid "password policies" msgstr "politiques de mot de passe" msgid "Max failures" msgstr "Nombre maximal d'échecs" msgid "Consecutive failures before lockout" msgstr "Échec consécutif avant verrouillage" msgid "Failure reset interval" msgstr "Intervalle de réinitialisation sur échec" msgid "Period after which failure count will be reset (seconds)" msgstr "" "Période après laquelle le compteur d'échec sera réinitialisé (secondes)" msgid "Lockout duration" msgstr "Durée de verrouillage" msgid "Period for which lockout is enforced (seconds)" msgstr "Période pendant laquelle le verrouillage est actif (secondes)" msgid "Password Policies" msgstr "Politiques de mot de passe" msgid "Group" msgstr "Groupe" msgid "Manage password policy for specific group" msgstr "Gérer la politique de mots de passe d'un groupe spécifique" msgid "Max lifetime (days)" msgstr "Durée de vie maximale (jours)" msgid "Maximum password lifetime (in days)" msgstr "Durée de vie maximale d'un mot de passe (en jours)" msgid "Min lifetime (hours)" msgstr "Durée de vie minimale (jours)" msgid "Minimum password lifetime (in hours)" msgstr "Durée de vie maximale d'un mot de passe (en jours)" msgid "History size" msgstr "Taille de l'historique" msgid "Password history size" msgstr "Taille de l'historique des mots de passe" msgid "Character classes" msgstr "Classes de caractères" msgid "Minimum number of character classes" msgstr "Nombre minimal de classes de caractères" msgid "Min length" msgstr "Longueur minimale" msgid "Minimum length of password" msgstr "Taille minimale d'un mot de passe" msgid "Priority of the policy (higher number means lower priority" msgstr "Priorité de la polique (une valeur élevé indique une priorité basse)" msgid "Maximum password life must be greater than minimum." msgstr "" "La durée de vie maximale du mot de passe doit être supérieure au minimum." msgid "Add a new group password policy." msgstr "Ajouter une nouvelle politique de mot de passe." msgid "Delete a group password policy." msgstr "Supprimer une politique de mot de passe." msgid "cannot delete global password policy" msgstr "impossible de supporimer une politique de mot de passe globale" msgid "Modify a group password policy." msgstr "Modifier une politique de mot de passe de groupe." msgid "priority cannot be set on global policy" msgstr "la priorité ne peut être définie sur la politique globale" msgid "Display information about password policy." msgstr "Afficher les informations sur une politique de mot de passe." msgid "Display effective policy for a specific user" msgstr "Afficher la politique effective sur un utilisateur spécifique" msgid "Search for group password policies." msgstr "Rechercher des politiques de mot de passe de groupe." msgid "" "\n" "Realm domains\n" "\n" "Manage the list of domains associated with IPA realm.\n" "\n" "EXAMPLES:\n" "\n" " Display the current list of realm domains:\n" " ipa realmdomains-show\n" "\n" " Replace the list of realm domains:\n" " ipa realmdomains-mod --domain=example.com\n" " ipa realmdomains-mod --domain={example1.com,example2.com,example3.com}\n" "\n" " Add a domain to the list of realm domains:\n" " ipa realmdomains-mod --add-domain=newdomain.com\n" "\n" " Delete a domain from the list of realm domains:\n" " ipa realmdomains-mod --del-domain=olddomain.com\n" msgstr "" "\n" "Domaines du royaume\n" "\n" "Gérer la liste des domaines associés au royaume IPA.\n" "\n" "EXEMPLES:\n" "\n" " Afficher la liste actuelle des domaines du royaume :\n" " ipa realmdomains-show\n" "\n" " Remplacer la liste des domaines du royaume :\n" " ipa realmdomains-mod --domain=example.com\n" " ipa realmdomains-mod --domain={example1.com,example2.com,example3.com}\n" "\n" " Ajouter un domaine à la liste des domaines du royaume :\n" " ipa realmdomains-mod --add-domain=newdomain.com\n" "\n" " Supprimer un domaine de la liste des domaines du royaume :\n" " ipa realmdomains-mod --del-domain=olddomain.com\n" msgid "Realm domains" msgstr "Domaines" msgid "Add domain" msgstr "Ajouter un domaine" msgid "Delete domain" msgstr "Supprimer un domaine" msgid "Modify realm domains." msgstr "Modifier les domaines." msgid "Force adding domain even if not in DNS" msgstr "Forcer l'ajout d'un domaine même si absent des DNS" msgid "" "you cannot specify the --domain option together with --add-domain or --del-" "domain" msgstr "" "Impossible d'utiliser l'option --domain avec les options --add-domain ou --" "del-domain" msgid "cannot delete domain of IPA server" msgstr "Impossible de supprimer le domaine du serveur IPA" #, python-format msgid "no SOA or NS records found for domains: %s" msgstr "aucun enregistrement SOA ou NS trouvé pour les domaines : %s" #, python-format msgid "no SOA or NS records found for domain %s" msgstr "aucun enregistrement SOA ou NS trouvé pour le domaine : %s" msgid "Display the list of realm domains." msgstr "Afficher la liste des domaines." msgid "" "\n" "Roles\n" "\n" "A role is used for fine-grained delegation. A permission grants the ability\n" "to perform given low-level tasks (add a user, modify a group, etc.). A\n" "privilege combines one or more permissions into a higher-level abstraction\n" "such as useradmin. A useradmin would be able to add, delete and modify " "users.\n" "\n" "Privileges are assigned to Roles.\n" "\n" "Users, groups, hosts and hostgroups may be members of a Role.\n" "\n" "Roles can not contain other roles.\n" "\n" "EXAMPLES:\n" "\n" " Add a new role:\n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" "\n" " Add some privileges to this role:\n" " ipa role-add-privilege --privileges=addusers junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege --privileges=add_user_to_default_group " "junioradmin\n" "\n" " Add a group of users to this role:\n" " ipa group-add --desc=\"User admins\" useradmins\n" " ipa role-add-member --groups=useradmins junioradmin\n" "\n" " Display information about a role:\n" " ipa role-show junioradmin\n" "\n" " The result of this is that any users in the group 'junioradmin' can\n" " add users, reset passwords or add a user to the default IPA user group.\n" msgstr "" "\n" "Rôles\n" "\n" "Les rôles sont utilisés pour les délégations fines. Une permission accorde\n" "la capacité d'effectuer une tâche de bas niveau (ajouter un utilisateur,\n" "modifier un groupe, etc.). Un privilège combine une ou plusieurs\n" "permissions\n" "en une abstraction de plus haut niveau comme useradmin. Un\n" "administrateur d'utilisateur (useradmin) sera capable d'ajouter, modifier\n" "et supprimer des utilisateurs.\n" "\n" "Les privilèges sont attribués aux Rôles.\n" "\n" "Peuvent être membres d'un rôle des utilisateurs, des groupes, des systèmes\n" "et des groupes de systèmes.\n" "\n" "Les rôles ne peuvent contenir d'autres rôles.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau rôle :\n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" "\n" " Ajouter des privilèges à ce rôle :\n" " ipa role-add-privilege --privileges=addusers junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege --privileges=add_user_to_default_group " "junioradmin\n" "\n" " Ajouter un groupe d'utilisateurs à ce rôle :\n" " ipa group-add --desc=\"User admins\" useradmins\n" " ipa role-add-member --groups=useradmins junioradmin\n" "\n" " Afficher les informations sur un rôle :\n" " ipa role-show junioradmin\n" "\n" " Le résultat des commandes ci-dessus est que le groupe 'junioradmin'\n" " peut ajouter des utilisateurs, réinitialiser des mots de passe, ou ajouter\n" " un utilisateur au groupe d'utilisateur par défaut de IPA.\n" msgid "role" msgstr "rôle" msgid "roles" msgstr "rôles" msgid "Role" msgstr "Rôle" msgid "Role name" msgstr "Nom du rôle" msgid "A description of this role-group" msgstr "Description de ce rôle" msgid "Add a new role." msgstr "Ajouter un nouveau rôle." #, python-format msgid "Added role \"%(value)s\"" msgstr "Rôle \"%(value)s\" ajouté" msgid "Delete a role." msgstr "Supprimer un rôle" #, python-format msgid "Deleted role \"%(value)s\"" msgstr "Rôle \"%(value)s\" supprimé" msgid "Modify a role." msgstr "Modifier un rôle." #, python-format msgid "Modified role \"%(value)s\"" msgstr "Rôle \"%(value)s\" modifié" msgid "Search for roles." msgstr "Rechercher des rôles." #, python-format msgid "%(count)d role matched" msgid_plural "%(count)d roles matched" msgstr[0] "%(count)d rôle correspondant" msgstr[1] "%(count)d rôles correspondants" msgid "Display information about a role." msgstr "Afficher les informations sur un rôle." msgid "Add members to a role." msgstr "Ajouter des membres à un rôle." msgid "Remove members from a role." msgstr "Supprimer des membres d'un rôle." msgid "Add privileges to a role." msgstr "Ajouter des privilèges à un rôle." msgid "Number of privileges added" msgstr "Nombre de privilèges ajoutés" msgid "Remove privileges from a role." msgstr "Supprimer des privilèges d'un rôle." msgid "Number of privileges removed" msgstr "Nombre de privilèges retirés" msgid "" "\n" "Self-service Permissions\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "A Self-service permission defines what an object can change in its own " "entry.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add a self-service rule to allow users to manage their address (using Bash\n" " brace expansion):\n" " ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c," "st} \"Users manage their own address\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones.\n" " Add telephoneNumber to the list (using Bash brace expansion):\n" " ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} " "\"Users manage their own address\"\n" "\n" " Display our updated rule:\n" " ipa selfservice-show \"Users manage their own address\"\n" "\n" " Delete a rule:\n" " ipa selfservice-del \"Users manage their own address\"\n" msgstr "" "\n" "Permissions self-service\n" "\n" "Une permission permet la délégation fine de permissions. Les règles ou\n" "instructions de contrôle d'accès (ACI) accorde la permission d'effectuer\n" "des tâches spécifiques comme ajouter un utilisateur, modifier un groupe, " "etc.\n" "\n" "Une permission self-service définit ce qu'un objet peut modifier dans sa\n" "propre entrée.\n" "\n" "\n" "EXEMPLES :\n" "\n" " Ajouter une règle self-service permettant aux utilisateurs de gérer leur " "adresse\n" " (en utilisant les capacités d'extension des accolades dans bash) :\n" " ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c," "st} \"Users manage their own address\"\n" "\n" " Tous les attributs doivent être mentionnés lors de l'utilisation de listes " "d'attributs,\n" " y compris ceux déjà existants. Ajouter telephoneNumber à la liste (en " "utilisant les capacités\n" " d'extension des accolades dans bash) :\n" " ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} " "\"Users manage their own address\"\n" "\n" " Afficher la règle modifiée :\n" " ipa selfservice-show \"Users manage their own address\"\n" "\n" " Supprimer une règle :\n" " ipa selfservice-del \"Users manage their own address\"\n" msgid "self service permission" msgstr "permission self-service" msgid "self service permissions" msgstr "permissions self-service" msgid "Self Service Permissions" msgstr "Permissions Self-Service" msgid "Self Service Permission" msgstr "Permission Self-Service" msgid "Self-service name" msgstr "Nom de la permission self-service" msgid "Attributes to which the permission applies." msgstr "Attributs auxquels les permissions s'appliquent." msgid "Add a new self-service permission." msgstr "Ajouter une nouvelle permission self-service." #, python-format msgid "Added selfservice \"%(value)s\"" msgstr "Permission self-service \"%(value)s\" ajoutée" msgid "Delete a self-service permission." msgstr "Supprimer une permission self-service." #, python-format msgid "Deleted selfservice \"%(value)s\"" msgstr "Permission selfservice \"%(value)s\" supprimée" msgid "Modify a self-service permission." msgstr "Modifier une permission self-service." #, python-format msgid "Modified selfservice \"%(value)s\"" msgstr "Permission selfservice \"%(value)s\" modifiée" msgid "Search for a self-service permission." msgstr "Rechercher des permissions self-service." #, python-format msgid "%(count)d selfservice matched" msgid_plural "%(count)d selfservices matched" msgstr[0] "%(count)d permission self-service correspondante" msgstr[1] "%(count)d permissions self-service correspondantes" msgid "Display information about a self-service permission." msgstr "Afficher les informations sur une permission self-service." msgid "" "\n" "SELinux User Mapping\n" "\n" "Map IPA users to SELinux users by host.\n" "\n" "Hosts, hostgroups, users and groups can be either defined within\n" "the rule or it may point to an existing HBAC rule. When using\n" "--hbacrule option to selinuxusermap-find an exact match is made on the\n" "HBAC rule name, so only one or zero entries will be returned.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that sets all users to xguest_u:s0 on the host " "\"server\":\n" " ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1\n" " ipa selinuxusermap-add-host --hosts=server.example.com test1\n" "\n" " Create a rule, \"test2\", that sets all users to guest_u:s0 and uses an " "existing HBAC rule for users and hosts:\n" " ipa selinuxusermap-add --usercat=all --hbacrule=webserver --" "selinuxuser=guest_u:s0 test2\n" "\n" " Display the properties of a rule:\n" " ipa selinuxusermap-show test2\n" "\n" " Create a rule for a specific user. This sets the SELinux context for\n" " user john to unconfined_u:s0-s0:c0.c1023 on any machine:\n" " ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0." "c1023 john_unconfined\n" " ipa selinuxusermap-add-user --users=john john_unconfined\n" "\n" " Disable a rule:\n" " ipa selinuxusermap-disable test1\n" "\n" " Enable a rule:\n" " ipa selinuxusermap-enable test1\n" "\n" " Find a rule referencing a specific HBAC rule:\n" " ipa selinuxusermap-find --hbacrule=allow_some\n" "\n" " Remove a rule:\n" " ipa selinuxusermap-del john_unconfined\n" "\n" "SEEALSO:\n" "\n" " The list controlling the order in which the SELinux user map is applied\n" " and the default SELinux user are available in the config-show command.\n" msgstr "" "\n" "Correspondances d'utilisateurs SELinux\n" "\n" "Correspondance des utilisateurs IPA vers les utilisateurs SELinux par hôte.\n" "\n" "Systèmes, groupes de systèmes, utilisateurs et groupes peuvent être définis " "soit\n" "au sein de la règle ou peuvent pointer vers une règle HBAC existante. Lors " "de\n" "l'utilisation de l'option --hbacrule à selinuxusermap-find, une " "correspondance\n" "exacte est faite sur le nom de la règle HBAC, de sorte que seule une ou " "aucune entrée\n" "soit renvoyée.\n" "\n" "EXEMPLES :\n" "\n" " Créer une règle « test1 » qui attribue tous les utilisateurs à xguest_u:s0 " "sur\n" " le système « server » :\n" " ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1\n" " ipa selinuxusermap-add-host --hosts=server.example.com test1\n" "\n" " Créer une règle « test2 » qui attribue tous les utilisateurs à guest_u:s0 " "et\n" " utilise un règle HBAC existante pour les utilisateurs et systèmes :\n" " ipa selinuxusermap-add --usercat=all --hbacrule=webserver --" "selinuxuser=guest_u:s0 test1\n" "\n" " Afficher les informations d'une règle :\n" " ipa selinuxusermap-show test2\n" "\n" " Créer une règle pour un utilisateur spécifique. Ceci définit le contexte\n" " SELinux d'un utilisateur john à unconfined_u:s0-s0:c0.c1023 sur toute " "machine :\n" " ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0." "c1023 john_unconfined\n" " ipa selinuxusermap-add-user --users=john john_unconfined\n" "\n" " Désactiver une règle nommée :\n" " ipa selinuxusermap-disable test1\n" "\n" " Activer une règle nommée :\n" " ipa selinuxusermap-enable test1\n" "\n" " Trouver une règle référençant une règle HBAC spécifique :\n" " ipa selinuxusermap-find --hbacrule=allow_some\n" "\n" " Supprimer une règle nommée :\n" " ipa selinuxusermap-del john_unconfined\n" "\n" "VOIR AUSSI :\n" "\n" " La liste contrôlant l'ordre dans lequel la carte de correspondance SELinux " "est appliquée et l'utilisateur SELinux par défaut sont disponibles dans la " "commande config-show.\n" msgid "HBAC rule and local members cannot both be set" msgstr "" "Les règles HBAC et les membres locaux ne peuvent être définis simultanément" msgid "Invalid SELinux user name, only a-Z and _ are allowed" msgstr "Nom d'utilisateur SELinux invalide, seuls a-Z et _ sont autorisés" msgid "Invalid MLS value, must match s[0-15](-s[0-15])" msgstr "Valeur pour MLS invalide, doit correspondre à s[0-15](-s[0-15])" msgid "" "Invalid MCS value, must match c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123]" msgstr "" "Valeur pour MLS invalide, doit correspondre à c[0-1023].c[0-1023] et/ou " "c[0-1023]-c[0-c0123]" msgid "SELinux user map list not found in configuration" msgstr "" "Liste de correspondance d'utilisateurs SELinux introuvable dans cette " "configuration" #, python-format msgid "SELinux user %(user)s not found in ordering list (in config)" msgstr "" "Utilisateur SELinux %(user)s introuvable dans la liste ordonnée (dans la " "configuration)" msgid "SELinux User Map rule" msgstr "Règle de correspondance d'utilisateurs SELinux" msgid "SELinux User Map rules" msgstr "Règles de correspondance d'utilisateurs SELinux" msgid "SELinux User Maps" msgstr "Correspondance utilisateurs SELinux" msgid "SELinux User Map" msgstr "Liste de correspondance d'utilisateurs SELinux" msgid "SELinux User" msgstr "Utilisateur SELinux" msgid "HBAC Rule that defines the users, groups and hostgroups" msgstr "" "Règles HBAC définissant les utilisateurs, les groupes et les groupes de " "systèmes" #, python-format msgid "HBAC rule %(rule)s not found" msgstr "Règle HBAC %(rule)s introuvable" msgid "Create a new SELinux User Map." msgstr "Créer une nouvelle liste de correspondance d'utilisateurs SELinux" #, python-format msgid "Added SELinux User Map \"%(value)s\"" msgstr "Liste de correspondance d'utilisateurs SELinux \"%(value)s\" ajoutée" msgid "Delete a SELinux User Map." msgstr "Supprimer une liste de correspondance d'utilisateurs SELinux" #, python-format msgid "Deleted SELinux User Map \"%(value)s\"" msgstr "" "Liste de correspondance d'utilisateurs SELinux \"%(value)s\" supprimée." msgid "Modify a SELinux User Map." msgstr "Modifier une liste de correspondance d'utilisateurs SELinux" #, python-format msgid "Modified SELinux User Map \"%(value)s\"" msgstr "Liste de correspondance d'utilisateurs SELinux \"%(value)s\" modifiée" msgid "Search for SELinux User Maps." msgstr "Rechercher des listes de correspondance d'utilisateurs SELinux" #, python-format msgid "%(count)d SELinux User Map matched" msgid_plural "%(count)d SELinux User Maps matched" msgstr[0] "" "%(count)d liste de correspondance d'utilisateurs SELinux correspondante" msgstr[1] "" "%(count)d listes de correspondance d'utilisateurs SELinux correspondantes" msgid "Display the properties of a SELinux User Map rule." msgstr "" "Afficher les propriétés d'une règle de correspondance d'utilisateurs SELinux" msgid "Enable an SELinux User Map rule." msgstr "Activer une règle de correspondance d'utilisateurs SELinux" #, python-format msgid "Enabled SELinux User Map \"%(value)s\"" msgstr "Règle de correspondance d'utilisateurs SELinux \"%(value)s\" activée" msgid "Disable an SELinux User Map rule." msgstr "Désactiver une règle de correspondance d'utilisateurs SELinux" #, python-format msgid "Disabled SELinux User Map \"%(value)s\"" msgstr "" "Règle de correspondance d'utilisateurs SELinux \"%(value)s\" désactivée" msgid "Add users and groups to an SELinux User Map rule." msgstr "" "Ajouter des utilisateurs et groupes à une règle de correspondance " "d'utilisateurs SELinux" msgid "Remove users and groups from an SELinux User Map rule." msgstr "" "Supprimer des utilisateurs et groupes d'une règle de correspondance " "d'utilisateurs SELinux" msgid "Add target hosts and hostgroups to an SELinux User Map rule." msgstr "" "Ajouter des systèmes et groupes de systèmes cibles à une règle de " "correspondance d'utilisateurs SELinux" msgid "Remove target hosts and hostgroups from an SELinux User Map rule." msgstr "" "Supprimer des systèmes et groupes de systèmes cibles d'une règle de " "correspondance d'utilisateurs SELinux" msgid "" "\n" "Services\n" "\n" "A IPA service represents a service that runs on a host. The IPA service\n" "record can store a Kerberos principal, an SSL certificate, or both.\n" "\n" "An IPA service can be managed directly from a machine, provided that\n" "machine has been given the correct permission. This is true even for\n" "machines other than the one the service is associated with. For example,\n" "requesting an SSL certificate using the host service principal credentials\n" "of the host. To manage a service using host credentials you need to\n" "kinit as the host:\n" "\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\n" "\n" "Adding an IPA service allows the associated service to request an SSL\n" "certificate or keytab, but this is performed as a separate step; they\n" "are not produced as a result of adding the service.\n" "\n" "Only the public aspect of a certificate is stored in a service record;\n" "the private key is not stored.\n" "\n" "EXAMPLES:\n" "\n" " Add a new IPA service:\n" " ipa service-add HTTP/web.example.com\n" "\n" " Allow a host to manage an IPA service certificate:\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\n" " ipa role-add-member --hosts=web.example.com certadmin\n" "\n" " Override a default list of supported PAC types for the service:\n" " ipa service-mod HTTP/web.example.com --pac-type=MS-PAC\n" "\n" " A typical use case where overriding the PAC type is needed is NFS.\n" " Currently the related code in the Linux kernel can only handle Kerberos\n" " tickets up to a maximal size. Since the PAC data can become quite large " "it\n" " is recommended to set --pac-type=NONE for NFS services.\n" "\n" " Delete an IPA service:\n" " ipa service-del HTTP/web.example.com\n" "\n" " Find all IPA services associated with a host:\n" " ipa service-find web.example.com\n" "\n" " Find all HTTP services:\n" " ipa service-find HTTP\n" "\n" " Disable the service Kerberos key and SSL certificate:\n" " ipa service-disable HTTP/web.example.com\n" "\n" " Request a certificate for an IPA service:\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\n" "\n" " Generate and retrieve a keytab for an IPA service:\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\n" "\n" msgstr "" "\n" "Services\n" "\n" "Un service IPA est un service qui s'exécute sur un hôte. L'enregistrement du " "service IPA\n" "peut comporter un principal Kerberos, un certificat SSL ou les deux.\n" "\n" "Un service IPA peut être directement géré à partir d'une machine, pour " "autant que des\n" "autorisations d'accès correctes aient été fournies à la machine. Ceci est " "vrai même pour\n" "les machines autres que celle à laquelle le service est associé. Par " "exemple,\n" "demander un certificat SSL en utilisant les justificatifs d'identité du " "principal du service\n" "hôte de l'hôte. Pour gérer un service en utilisant les références de l'hôte, " "vous devrez\n" "exécuter kinit en tant qu'hôte :\n" "\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\n" "\n" "Ajouter un service IPA permet au service associé de demander un certificat " "SSL ou\n" "un tableau de clés, mais cela est réalisé dans une étape distincte ; cela " "n'est pas\n" "le résultat de l'ajout du service.\n" "\n" "Seule la composante publique du certificat est stockée dans un " "enregistrement de service ;\n" "la clé privée n'y est pas mise.\n" "\n" "EXEMPLES:\n" "\n" " Ajouter un nouveau service IPA :\n" " ipa service-add HTTP/web.example.com\n" "\n" " Autoriser un hôte à gérer un certificat de service IPA :\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\n" " ipa role-add-member --hosts=web.example.com certadmin\n" "\n" " Écraser la liste par défaut des types PAC pris en charge par le service :\n" " ipa service-mod HTTP/web.example.com --pac-type=MS-PAC\n" "\n" " Un cas classique de l'utilisation de l'écrasement du type PAC est " "nécessaire avec NFS.\n" " Actuellement le code relatif à cette fonction dans le noyau Linux ne gère " "les tickets\n" " Kerberos que jusqu'à une taille maximale donnée. Comme les données PAC " "peuvent devenir\n" " bien plus grandes, il est recommandé de fixer --pac-type=NONE pour les " "services NFS.\n" "\n" " Supprimer un service IPA :\n" " ipa service-del HTTP/web.example.com\n" "\n" " Trouver tous les services IPA associés à un hôte :\n" " ipa service-find web.example.com\n" "\n" " Trouver tous les service HTTP :\n" " ipa service-find HTTP\n" "\n" " Désactiver la clé du service Kerberos key et le certificat SSL :\n" " ipa service-disable HTTP/web.example.com\n" "\n" " Réclamer un certificat pour un service IPA :\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\n" "\n" " Générer et retrouver un tableau de clés pour un service IPA :\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\n" "\n" msgid "Requires pre-authentication" msgstr "Nécessite une pré-authentification" msgid "Pre-authentication is required for the service" msgstr "Une pré-authentification est requise pour le service" msgid "Trusted for delegation" msgstr "Approuvé pour délégation." msgid "Client credentials may be delegated to the service" msgstr "" "Les informations d'identification du client peuvent être déléguées au service" msgid "missing service" msgstr "service manquant" msgid "blank service" msgstr "service vierge" msgid "unable to determine realm" msgstr "impossible de déterminer le domaine" msgid "This principal is required by the IPA master" msgstr "Ce principal est nécessaire au serveur IPA" msgid "service" msgstr "service" msgid "services" msgstr "services" msgid "Service principal" msgstr "Principal du service" msgid "PAC type" msgstr "type de PAC" msgid "" "Override default list of supported PAC types. Use 'NONE' to disable PAC " "support for this service, e.g. this might be necessary for NFS services." msgstr "" "Surcharger la liste par défaut des types PAC pris en charge. Utiliser « NONE " "» pour désactiver la prise en charge PAC pour ce service, ce qui peut être " "nécessaire pour les services NFS par exemple." msgid "NONE value cannot be combined with other PAC types" msgstr "La valeur NONE ne peut être combinée avec d'autres types de PAC" msgid "Add a new IPA new service." msgstr "Ajouter un nouveau service IPA." #, python-format msgid "Added service \"%(value)s\"" msgstr "Service \"%(value)s\" ajouté" msgid "force principal name even if not in DNS" msgstr "forcer le nom du principal même si absent du DNS" #, python-format msgid "The host '%s' does not exist to add a service to." msgstr "Le système « %s » auquel ajouter un service n'existe pas." msgid "Delete an IPA service." msgstr "Supprimer un service IPA." #, python-format msgid "Deleted service \"%(value)s\"" msgstr "Service \"%(value)s\" supprimé" msgid "Modify an existing IPA service." msgstr "Modifier un service IPA." #, python-format msgid "Modified service \"%(value)s\"" msgstr "Service \"%(value)s\" modifié" msgid "Search for IPA services." msgstr "Rechercher des services IPA." #, python-format msgid "%(count)d service matched" msgid_plural "%(count)d services matched" msgstr[0] "%(count)d service correspondant" msgstr[1] "%(count)d services correspondants" msgid "Display information about an IPA service." msgstr "Afficher les informations sur un service IPA." msgid "Add hosts that can manage this service." msgstr "Ajouter des sytèmes pouvant administrer ce service." msgid "Remove hosts that can manage this service." msgstr "Supprimer des sytèmes pouvant administrer ce service." msgid "Disable the Kerberos key and SSL certificate of a service." msgstr "Désactiver la clé Kerberos et le certificat SSL d'un service." #, python-format msgid "Disabled service \"%(value)s\"" msgstr "Service \"%(value)s\" désactivé" msgid "" "\n" "Sudo Commands\n" "\n" "Commands used as building blocks for sudo\n" "\n" "EXAMPLES:\n" "\n" " Create a new command\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Remove a command\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgstr "" "\n" "Commandes sudo\n" "\n" "Commandes utilisées en tant que briques de base pour sudo\n" "\n" "EXEMPLES :\n" "\n" " Ajouter une nouvelle commande\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Supprimer une commande\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgid "commands for controlling sudo configuration" msgstr "commandes pour contrôler la configuration sudo" msgid "sudo command" msgstr "commande sudo" msgid "sudo commands" msgstr "commandes sudo" msgid "Sudo Commands" msgstr "Commandes sudo" msgid "Sudo Command" msgstr "Commande sudo" msgid "A description of this command" msgstr "Description de la commande" msgid "Create new Sudo Command." msgstr "Créer une nouvelle commande Sudo." #, python-format msgid "Added Sudo Command \"%(value)s\"" msgstr "Commande Sudo \"%(value)s\" ajoutée" msgid "Delete Sudo Command." msgstr "Supprimer une commande Sudo." #, python-format msgid "Deleted Sudo Command \"%(value)s\"" msgstr "Commande Sudo \"%(value)s\" supprimée" msgid "Modify Sudo Command." msgstr "Modifier une commande Sudo." #, python-format msgid "Modified Sudo Command \"%(value)s\"" msgstr "Commande Sudo \"%(value)s\" modifiée" msgid "Search for Sudo Commands." msgstr "Rechercher des commandes Sudo." #, python-format msgid "%(count)d Sudo Command matched" msgid_plural "%(count)d Sudo Commands matched" msgstr[0] "%(count)d commande Sudo correspondante" msgstr[1] "%(count)d commandes Sudo correspondantes" msgid "Display Sudo Command." msgstr "Afficher une commande Sudo." msgid "" "\n" "Groups of Sudo Commands\n" "\n" "Manage groups of Sudo Commands.\n" "\n" "EXAMPLES:\n" "\n" " Add a new Sudo Command Group:\n" " ipa sudocmdgroup-add --desc='administrators commands' admincmds\n" "\n" " Remove a Sudo Command Group:\n" " ipa sudocmdgroup-del admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/" "vim admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa group-remove-member --sudocmds=/usr/bin/less admincmds\n" "\n" " Show a Sudo Command Group:\n" " ipa group-show localadmins\n" msgstr "" "\n" "Groupes de commandes Sudo\n" "\n" "Administre les groupes de commandes Sudo.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouveau groupe de commandes Sudo :\n" " ipa sudocmdgroup-add --desc='commandes administrateurs' admincmds\n" "\n" " Supprimer un groupe de commandes Sudo :\n" " ipa sudocmdgroup-del admincmds\n" "\n" " Administrer l'appartenance et les commandes d'un groupe de commandes " "Sudo :\n" " ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/" "vim admincmds\n" "\n" " Administrer l'appartenance et les commandes d'un groupe de commandes " "Sudo :\n" " ipa group-remove-member --sudocmds=/usr/bin/less admincmds\n" "\n" " Afficher un groupe de commandes Sudo :\n" " ipa group-show localadmins\n" msgid "sudo command group" msgstr "groupe de commandes sudo" msgid "sudo command groups" msgstr "groupes de commandes sudo" msgid "Sudo Command Group" msgstr "Groupe de commandes sudo" msgid "Create new Sudo Command Group." msgstr "Créer un nouveau groupe de commandes Sudo." #, python-format msgid "Added Sudo Command Group \"%(value)s\"" msgstr "Groupe de commandes Sudo \"%(value)s\" ajouté" msgid "Delete Sudo Command Group." msgstr "Supprimer un groupe de commandes Sudo." #, python-format msgid "Deleted Sudo Command Group \"%(value)s\"" msgstr "Groupe de commandes Sudo \"%(value)s\" supprimé" msgid "Modify Sudo Command Group." msgstr "Modifier un groupe de commandes Sudo." #, python-format msgid "Modified Sudo Command Group \"%(value)s\"" msgstr "Groupe de commandes Sudo \"%(value)s\" modifié." msgid "Search for Sudo Command Groups." msgstr "Rechercher des groupes de commandes Sudo." #, python-format msgid "%(count)d Sudo Command Group matched" msgid_plural "%(count)d Sudo Command Groups matched" msgstr[0] "%(count)d groupe de commandes Sudo correspondant" msgstr[1] "%(count)d groupes de commandes Sudo correspondants" msgid "Display Sudo Command Group." msgstr "Afficher un groupe de commandes Sudo." msgid "Add members to Sudo Command Group." msgstr "Ajouter des membres à un groupe de commandes Sudo." msgid "Remove members from Sudo Command Group." msgstr "Supprimer des membres d'un groupe de commandes Sudo." msgid "" "\n" "Sudo Rules\n" "\n" "Sudo (su \"do\") allows a system administrator to delegate authority to\n" "give certain users (or groups of users) the ability to run some (or all)\n" "commands as root or another user while providing an audit trail of the\n" "commands and their arguments.\n" "\n" "FreeIPA provides a means to configure the various aspects of Sudo:\n" " Users: The user(s)/group(s) allowed to invoke Sudo.\n" " Hosts: The host(s)/hostgroup(s) which the user is allowed to to invoke " "Sudo.\n" " Allow Command: The specific command(s) permitted to be run via Sudo.\n" " Deny Command: The specific command(s) prohibited to be run via Sudo.\n" " RunAsUser: The user(s) or group(s) of users whose rights Sudo will be " "invoked with.\n" " RunAsGroup: The group(s) whose gid rights Sudo will be invoked with.\n" " Options: The various Sudoers Options that can modify Sudo's behavior.\n" "\n" "An order can be added to a sudorule to control the order in which they\n" "are evaluated (if the client supports it). This order is an integer and\n" "must be unique.\n" "\n" "FreeIPA provides a designated binddn to use with Sudo located at:\n" "uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com\n" "\n" "To enable the binddn run the following command to set the password:\n" "LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -" "ZZ -D \"cn=Directory Manager\" uid=sudo,cn=sysaccounts,cn=etc,dc=example," "dc=com\n" "\n" "For more information, see the FreeIPA Documentation to Sudo.\n" msgstr "" "\n" "Règles Sudo\n" "\n" "Sudo (su « do ») permet à un administrateur système de donner l'autorisation " "à certains\n" "utilisateurs (ou groupes d'utilisateurs) d'exécuter certaines (ou toute)\n" "commandes en tant qu'utilisateur root ou autre, tout en fournissant une " "piste de vérification\n" "des commandes et de leurs arguments.\n" "\n" "FreeIPA donne des possibilités de configurer divers aspects de Sudo :\n" " Users : les utilisateurs ou groupes autorisés à faire appel à Sudo.\n" " Hosts : les hôtes ou groupes d'hôtes sur lesquels l'utilisateur peut " "faire appel à Sudo.\n" " Allow Command : les commandes précises pouvant être lancées via Sudo.\n" " Deny Command : les commandes précises ne pouvant pas être lancées via " "Sudo.\n" " RunAsUser : utilisateurs ou groupes ayant des droits Sudo avec lesquels " "il sera fait appel.\n" " RunAsGroup : les groupes dont le gid permet de faire appel avec certains " "droits Sudo.\n" " Options : les diverses options Sudoers susceptibles de modifier le " "comportement de Sudo.\n" "\n" "Un numéro d'ordre peut être ajouté à des règles Sudo pour contrôler l'ordre " "dans lequel\n" "elles sont évaluées (si le client la prend en charge). Ce numéro d'ordre est " "un entier et\n" "doit être unique.\n" "\n" "FreeIPA met à disposition un binddn conçu pour être utilisé avec Sudo situé " "à :\n" "uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com\n" "\n" "Pour activer binddn, exécutez la commande ci-après pour définir le mot de " "passe :\n" "LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -" "ZZ -D \"cn=Directory Manager\" uid=sudo,cn=sysaccounts,cn=etc,dc=example," "dc=com\n" "\n" "Pour plus d'informations, voyez la documentation FreeIPA de Sudo.\n" msgid "Commands for controlling sudo configuration" msgstr "Commandes pour le contrôle d'une configuration sudo" msgid "this option has been deprecated." msgstr "cette option a été rendue obsolète." msgid "sudo rule" msgstr "règle sudo" msgid "sudo rules" msgstr "règles sudo" msgid "Sudo Rules" msgstr "Règles Sudo" msgid "Sudo Rule" msgstr "Règle sudo" msgid "Command category" msgstr "Catégorie de commande" msgid "Command category the rule applies to" msgstr "Catégorie de commande à laquelle la règle s'applique" msgid "RunAs User category" msgstr "Catégorie RunAs User" msgid "RunAs User category the rule applies to" msgstr "Catégorie RunAs User à laquelle la règle s'applique" msgid "RunAs Group category" msgstr "Catégorie RunAs Group" msgid "RunAs Group category the rule applies to" msgstr "Catégorie RunAs Group à laquelle la règle s'applique" msgid "Sudo order" msgstr "Ordre sudo" msgid "integer to order the Sudo rules" msgstr "nombre entier pour ordonner les règles sudo" msgid "Sudo Allow Commands" msgstr "Commandes sudo allow" msgid "Sudo Deny Commands" msgstr "Commande sudo deny" msgid "Sudo Allow Command Groups" msgstr "Autorisation de groupes de commandes Sudo" msgid "Sudo Deny Command Groups" msgstr "Interdiction de groupes de commandes Sudo" msgid "RunAs Users" msgstr "RunAs Users" msgid "Run as a user" msgstr "Lancer en tant qu'un utilisateur" msgid "Groups of RunAs Users" msgstr "Groupe de RunAs Users" msgid "Run as any user within a specified group" msgstr "Lancer en tant que n'importe quel utilisateur du groupe spécifié" msgid "External User" msgstr "Utilisateur externe" msgid "External User the rule applies to (sudorule-find only)" msgstr "" "Utilisateur externe auquel la règle s'applique (sudorule-find uniquement)" msgid "RunAs External User" msgstr "Lancer en tant que l'utilisateur externe" msgid "External User the commands can run as (sudorule-find only)" msgstr "" "Utilisateur externe en tant que lequel les commandes sont lancées (sudorule-" "find uniquement)" msgid "RunAs External Group" msgstr "Utilisateur externe" msgid "External Group the commands can run as (sudorule-find only)" msgstr "" "Groupe externe en tant que lequel les commandes sont lancées (sudorule-find " "uniquement)" msgid "Sudo Option" msgstr "Option sudo" msgid "RunAs Groups" msgstr "RunAs Groups" msgid "Run with the gid of a specified POSIX group" msgstr "Lancer avec le GID d'un groupe POSIX spécifique" #, python-format msgid "order must be a unique value (%(order)d already used by %(rule)s)" msgstr "" "l'ordre doit être une valeur unique (%(order)d déjà utilisée par %(rule)s)" msgid "Create new Sudo Rule." msgstr "Créer une nouvelle règle Sudo." #, python-format msgid "Added Sudo Rule \"%(value)s\"" msgstr "Règle Sudo \"%(value)s\" ajoutée" msgid "Delete Sudo Rule." msgstr "Règle Sudo supprimée." #, python-format msgid "Deleted Sudo Rule \"%(value)s\"" msgstr "Règle Sudo \"%(value)s\" supprimée" msgid "Modify Sudo Rule." msgstr "Modifier une règle Sudo." #, python-format msgid "Modified Sudo Rule \"%(value)s\"" msgstr "Règle Sudo \"%(value)s\" modifiée" msgid "" "command category cannot be set to 'all' while there are allow or deny " "commands" msgstr "" "la catégorie commandes ne peut être définie à 'all' alors qu'il reste des " "commandes autorisées ou interdites" msgid "user runAs category cannot be set to 'all' while there are users" msgstr "" "la catégorie RunAs de l'utilisateur ne peut être mise à 'all' tant qu'il y a " "des utilisateurs" msgid "group runAs category cannot be set to 'all' while there are groups" msgstr "" "la catégorie RunAs du groupe ne peut être mise à 'all' tant qu'il y a des " "groupes" msgid "Search for Sudo Rule." msgstr "Rechercher une règle Sudo." #, python-format msgid "%(count)d Sudo Rule matched" msgid_plural "%(count)d Sudo Rules matched" msgstr[0] "%(count)d règle Sudo correspondante" msgstr[1] "%(count)d règles Sudo correspondantes" msgid "Display Sudo Rule." msgstr "Afficher une règle Sudo." msgid "Enable a Sudo Rule." msgstr "Activer une règle Sudo." #, python-format msgid "Enabled Sudo Rule \"%s\"" msgstr "Règle Sudo \"%s\" activée" msgid "Disable a Sudo Rule." msgstr "Désactiver une règle Sudo." #, python-format msgid "Disabled Sudo Rule \"%s\"" msgstr "Règle Sudo \"%s\" désactivée" msgid "Add commands and sudo command groups affected by Sudo Rule." msgstr "" "Ajouter des commandes et groupes de commandes sudo affectés par la règle " "Sudo." msgid "commands cannot be added when command category='all'" msgstr "" "des commandes ne peuvent être ajoutées quand la catégorie commandes est " "définie à 'all'" msgid "Remove commands and sudo command groups affected by Sudo Rule." msgstr "" "Retirer des commandes et groupes de commandes sudo affectés par la règle " "Sudo." msgid "Add users and groups affected by Sudo Rule." msgstr "Ajouter des utilisateurs et groupes affectés par la règle Sudo." msgid "Remove users and groups affected by Sudo Rule." msgstr "Retirer des utilisateurs et groupes affectés par la règle Sudo." msgid "Add hosts and hostgroups affected by Sudo Rule." msgstr "" "Ajouter des systèmes et groupes de systèmes affectés par la règle Sudo." msgid "Remove hosts and hostgroups affected by Sudo Rule." msgstr "" "Retirer des systèmes et groupes de systèmes affectés par la règle Sudo." msgid "Add users and groups for Sudo to execute as." msgstr "Ajouter des utilisateurs et groupes pour que sudo exécute en tant que." msgid "users cannot be added when runAs user or runAs group category='all'" msgstr "" "des utilisateurs ne peuvent être ajoutés quand une catégorie RunAs User ou " "Group est définie à 'all'" #, python-format msgid "RunAsUser does not accept '%(name)s' as a user name" msgstr "RunAsUser n'accepte pas '%(name)s' comme nom d'utilisateur" #, python-format msgid "RunAsUser does not accept '%(name)s' as a group name" msgstr "RunAsUser n'accepte pas '%(name)s' comme nom de groupe" msgid "Remove users and groups for Sudo to execute as." msgstr "Retirer des utilisateurs et groupes pour que sudo exécute en tant que." msgid "Add group for Sudo to execute as." msgstr "Ajouter un groupe pour que sudo exécute en tant que." #, python-format msgid "RunAsGroup does not accept '%(name)s' as a group name" msgstr "RunAsGroup n'accepte pas '%(name)s' comme nom de groupe" msgid "Remove group for Sudo to execute as." msgstr "Retirer un groupe pour que sudo exécute en tant que." msgid "Add an option to the Sudo Rule." msgstr "Ajouter une option à la règle Sudo." #, python-format msgid "Added option \"%(option)s\" to Sudo Rule \"%(rule)s\"" msgstr "Option \"%(option)s\" ajoutée à la règle Sudo \"%(rule)s\"" msgid "Remove an option from Sudo Rule." msgstr "Retirer une option d'une règle Sudo." #, python-format msgid "Removed option \"%(option)s\" from Sudo Rule \"%(rule)s\"" msgstr "Option \"%(option)s\" supprimée de la règle Sudo \"%(rule)s\"" msgid "" "\n" "Cross-realm trusts\n" "\n" "Manage trust relationship between IPA and Active Directory domains.\n" "\n" "In order to allow users from a remote domain to access resources in IPA\n" "domain, trust relationship needs to be established. Currently IPA supports\n" "only trusts between IPA and Active Directory domains under control of " "Windows\n" "Server 2008 or later, with functional level 2008 or later.\n" "\n" "Please note that DNS on both IPA and Active Directory domain sides should " "be\n" "configured properly to discover each other. Trust relationship relies on\n" "ability to discover special resources in the other domain via DNS records.\n" "\n" "Examples:\n" "\n" "1. Establish cross-realm trust with Active Directory using AD administrator\n" " credentials:\n" "\n" " ipa trust-add --type=ad --admin --" "password\n" "\n" "2. List all existing trust relationships:\n" "\n" " ipa trust-find\n" "\n" "3. Show details of the specific trust relationship:\n" "\n" " ipa trust-show \n" "\n" "4. Delete existing trust relationship:\n" "\n" " ipa trust-del \n" "\n" "Once trust relationship is established, remote users will need to be mapped\n" "to local POSIX groups in order to actually use IPA resources. The mapping " "should\n" "be done via use of external membership of non-POSIX group and then this " "group\n" "should be included into one of local POSIX groups.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" "\n" "\n" "GLOBAL TRUST CONFIGURATION\n" "\n" "When IPA AD trust subpackage is installed and ipa-adtrust-install is run,\n" "a local domain configuration (SID, GUID, NetBIOS name) is generated. These\n" "identifiers are then used when communicating with a trusted domain of the\n" "particular type.\n" "\n" "1. Show global trust configuration for Active Directory type of trusts:\n" "\n" " ipa trustconfig-show --type ad\n" "\n" "2. Modify global configuration for all trusts of Active Directory type and " "set\n" " a different fallback primary group (fallback primary group GID is used " "as\n" " a primary user GID if user authenticating to IPA domain does not have any " "other\n" " primary GID already set):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"alternative AD " "group\"\n" "\n" "3. Change primary fallback group back to default hidden group (any group " "with\n" " posixGroup object class is allowed):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"Default SMB Group" "\"\n" msgstr "" "\n" "Confiance croisée entre royaumes\n" "\n" "Gérer les relations de confiance entre les domaines IPA et Active " "Directory.\n" "\n" "Pour permettre aux utilisateurs d'un domaine distant l'accès aux ressources " "d'un domaine IPA,\n" "des relations de confiance doivent être établies. Actuellement IPA ne prend " "en charge que\n" "la confiance entre des domaines IPA et Active Directory sous le contrôle de " "Windows\n" "Server 2008 ou ultérieur, avec le niveau fonctionnel 2008 ou ultérieur.\n" "\n" "Veuillez noter que DNS doit être correctement configuré à la fois côté " "domaine IPA et côté\n" "Active Directory pour une découverte mutuelle. La relation de confiance " "repose sur la capacité\n" "à repérer des ressources spéciales dans l'autre domaine via des " "enregistrements DNS.\n" "\n" "Exemples :\n" "\n" "1. Établir des relations de confiance croisées entre royaume avec Active " "Directory avec les\n" "autorisations d'accès de l'administrateur AD :\n" "\n" " ipa trust-add --type=ad --admin --" "password\n" "\n" "2. Lister toutes les relations de confiance existantes :\n" "\n" " ipa trust-find\n" "\n" "3. Voir les détails d'une relation de confiance donnée :\n" "\n" " ipa trust-show \n" "\n" "4. Supprimer une relation de confiance existante :\n" "\n" " ipa trust-del \n" "\n" "Une fois la relation de confiance établie, les utilisateurs distants doivent " "être mis en\n" "relation avec des groupes POSIX locaux pour utiliser réellement des " "ressources IPA. La\n" "relation doit se faire via l'appartenance à un groupe non-POSIX externe, " "puis ce groupe\n" "doit être intégré dans un des groupes POSIX locaux.\n" "\n" "Exemple :\n" "\n" "1. Créer un groupe pour la mise en relation avec le domaine de confiance " "admins et leur\n" " groupe POSIX local :\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Ajouter un identifiant de sécurité de de Domain Admins au " "groupe\n" " externe ad_admins :\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Associer des membres du groupe ad_admins_external avec le groupe POSIX " "ad_admins :\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. Lister les membrer externes du groupe externe ad_admins_external pour " "voir leur SID :\n" "\n" " ipa group-show ad_admins_external\n" "\n" "\n" "CONFIGURATION D'UNE CONFIANCE GLOBALE\n" "\n" "Quand le sous-paquet IPA AD trust est installé et ipa-adtrust-install est " "exécuté,\n" "une configuration de domaine local (SID, GUID, nom NetBIOS) est créée. Ces " "identifiants\n" "sont alors utilisés lors de communications avec un domaine de confiance\n" "de type particulier.\n" "\n" "1. Afficher la configuration de confiance globale pour les types de " "confiance Active Directory :\n" "\n" " ipa trustconfig-show --type ad\n" "\n" "2. Modifier la configuration globale de toutes les confiances de type Active " "Directory et\n" " définir un groupe principal de recours (le GID du groupe principal de " "recours est utilisé\n" " comme GID d'utilisateur pricipal si l'utilisateur s'authentifiant auprès " "du domaine IPA\n" " n'a pas d'autre GID principal déjà défini) :\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"alternative AD " "group\"\n" "\n" "3. Revenir au groupe caché par défaut comme groupe de recours principal " "(tout groupe de la\n" " classe objet posixGroup est autorisé) :\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"Default SMB Group" "\"\n" msgid "Non-Active Directory domain" msgstr "Domaine non-Active Directory" msgid "RFC4120-compliant Kerberos realm" msgstr "Domaine Kerberos conforme à la RFC4120" msgid "Trusting forest" msgstr "Forêt en cours d'approbation" msgid "Trusted forest" msgstr "Forêt approuvée" msgid "Two-way trust" msgstr "Approbation croisée" msgid "Established and verified" msgstr "Établie et vérifiée" msgid "Waiting for confirmation by remote side" msgstr "En attente de confirmation par la partie distante" msgid "Unknown" msgstr "Inconnu" msgid "Trust type (ad for Active Directory, default)" msgstr "Type d'approbation (par défaut, ad pour Active Directory)" msgid "trust" msgstr "approbation" msgid "trusts" msgstr "approbations" msgid "Trust" msgstr "Approbation" msgid "Realm name" msgstr "Nom du royaume" msgid "SID blacklist incoming" msgstr "liste noire de SID entrante" msgid "SID blacklist outgoing" msgstr "liste noire de SID sortante" #, python-format msgid "invalid SID: %(value)s" msgstr "SID invalide : %(value)s" msgid "" "\n" "Add new trust to use.\n" "\n" "This command establishes trust relationship to another domain\n" "which becomes 'trusted'. As result, users of the trusted domain\n" "may access resources of this domain.\n" "\n" "Only trusts to Active Directory domains are supported right now.\n" "\n" "The command can be safely run multiple times against the same domain,\n" "this will cause change to trust relationship credentials on both\n" "sides.\n" " " msgstr "" "\n" "Ajout d'une nouvelle relation de confiance.\n" "\n" "Cette commande établit une relation de confiance avec un autre domaine\n" "qui ainsi devient « de confiance ». En conséquence, des utilisateurs du " "domaine de confiance\n" "peuvent avoir accès aux ressources de ce domaine.\n" "\n" "Actuellement, seules les relations de confiance avec les domaines Active " "Directory sont prises en charge.\n" "\n" "Cette commande peut être lancée plusieurs fois en toute sécurité à " "l'encontre du même domaine,\n" "elle modifiera les références de la relation de confiance des deux côtés.\n" " " msgid "Active Directory domain administrator" msgstr "Administrateur du domaine Active Directory" msgid "Active directory domain administrator's password" msgstr "Mot de passe de l'administrateur du domaine Active Directory" msgid "Domain controller for the Active Directory domain (optional)" msgstr "Contrôleur de domaine pour le domaine Active Directory (optionnel)" msgid "Shared secret for the trust" msgstr "Secret partagé pour l'approbation" msgid "First Posix ID of the range reserved for the trusted domain" msgstr "Premier ID POSIX de la plage pour le domaine approuvé" msgid "Size of the ID range reserved for the trusted domain" msgstr "Taille de la plage d'ID pour le domaine approuvé" msgid "Type of trusted domain ID range, one of {vals}" msgstr "" "Type de plage d'identifiants de domaine approuvé, valeur à prendre parmi " "{vals}" #, python-format msgid "Added Active Directory trust for realm \"%(value)s\"" msgstr "Approbation Active Directory ajoutée pour le domaine « %(value)s »" msgid "AD Trust setup" msgstr "Configuration des relations d'approbations avec AD" msgid "" "Cannot perform join operation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA" msgstr "" "Impossible de rejoindre le domaine sans l'installation du support Samba 4. " "Assurez-vous de bien avoir installé sur le serveur le paquet server-trust-ad " "de IPA" msgid "missing base_id" msgstr "base_id manquant" msgid "pysss_murmur is not available on the server and no base-id is given." msgstr "" "pysss_murmur n'est pas disponible sur le serveur, et aucun base-id n'a été " "fourni." msgid "trust type" msgstr "type d'approbation" msgid "only \"ad\" is supported" msgstr "seul « ad » est pris en compte" msgid "Trusted domain and administrator account use different realms" msgstr "" "Le domaine approuvé et le compte administrateur utilisent des domaines " "différents" msgid "Realm administrator password should be specified" msgstr "Le mot de passe de l'administrateur du domaine doit être spécifié" msgid "id range type" msgstr "type de plage d'identifiants" msgid "" "Only the ipa-ad-trust and ipa-ad-trust-posix are allowed values for --range-" "type when adding an AD trust." msgstr "" "Seules les valeurs ipa-ad-trust et ipa-ad-trust-posix sont autorisées pour --" "range-type lors de l'ajout d'une relation d'approbation AD." msgid "id range" msgstr "plage d'identifiants" msgid "" "An id range already exists for this trust. You should either delete the old " "range, or exclude --base-id/--range-size options from the command." msgstr "" "Une plage d'identifiants existe déjà pour cette relation d'approbation. Vous " "devez soit supprimer l'ancienne plage, soit exclure les options --base-id/--" "range-size de la commande." msgid "range exists" msgstr "la plage existe" msgid "" "ID range with the same name but different domain SID already exists. The ID " "range for the new trusted domain must be created manually." msgstr "" "Une plage d'ID avec le même nom mais pour un SID de domaine différent existe " "déjà. La plage d'ID pour le nouveau domaine approuvé doit être créée " "manuellement." msgid "range type change" msgstr "modifier le type de plage" msgid "" "ID range for the trusted domain already exists, but it has a different type. " "Please remove the old range manually, or do not enforce type via --range-" "type option." msgstr "" "La plage d'identifiants existe déjà pour ce domaine approuvé, mais est d'un " "type différent. Vous devez soit supprimer l'ancienne plage manuellement, " "soit ne pas forcer le type via l'option --range-type." #, python-format msgid "Re-established trust to domain \"%(value)s\"" msgstr "Ré-approbation du domaine « %(value)s »" #, python-format msgid "Unable to resolve domain controller for '%s' domain. " msgstr "Impossible de résoudre le contrôleur de domaine du domaine « %s »." msgid "" "Forward policy is defined for it in IPA DNS, perhaps forwarder points to " "incorrect host?" msgstr "" "La politique de transmission est déjà définie dans le DNS IPA, peut-être le " "transmetteur pointe-t'il vers un système incorrect ?" #, python-format msgid "" "IPA manages DNS, please verify your DNS configuration and make sure that " "service records of the '%(domain)s' domain can be resolved. Examples how to " "configure DNS with CLI commands or the Web UI can be found in the " "documentation. " msgstr "" "IPA administre les DNS, merci de vérifier votre configuration DNS et de vous " "assurer que les enregistrement de service du domaine « %(domain)s » peuvent " "être résolus. La documentation apporte des exemples sur la manière de " "configurer DNS à l'aide de commandes en ligne ou avec l'interface web." #, python-format msgid "" "Since IPA does not manage DNS records, ensure DNS is configured to resolve " "'%(domain)s' domain from IPA hosts and back." msgstr "" "Puisque IPA ne gère pas les enregistrements DNS, s'assurer que les DNS sont " "bien configurés pour résoudre le domaine « %(domain)s » depuis les serveurs " "IPA, en résolution directe et inverse." msgid "Unable to verify write permissions to the AD" msgstr "Impossible de vérifier les permissions en écriture vers AD" msgid "Not enough arguments specified to perform trust setup" msgstr "Arguments insuffisants pour établir la relation d'approbation" msgid "Delete a trust." msgstr "Supprimer une approbation." #, python-format msgid "Deleted trust \"%(value)s\"" msgstr "Approbation « %(value)s » supprimée" msgid "" "\n" " Modify a trust (for future use).\n" "\n" " Currently only the default option to modify the LDAP attributes is\n" " available. More specific options will be added in coming releases.\n" " " msgstr "" "\n" " Modifier une approbation (pour une utilisation future).\n" "\n" " Actuellement seule l'option par défaut d'utiliser LDAP pour modifier\n" " les attributs est disponible. Des options plus précises seront ajoutées\n" " dans les versions à venir.\n" " " #, python-format msgid "Modified trust \"%(value)s\" (change will be effective in 60 seconds)" msgstr "" "Relation d'approbation « %(value)s » modifiée (la modification prendra effet " "d'ici 60 secondes)" msgid "Search for trusts." msgstr "Rechercher des approbations." #, python-format msgid "%(count)d trust matched" msgid_plural "%(count)d trusts matched" msgstr[0] "%(count)d approbation correspondante" msgstr[1] "%(count)d approbations correspondantes" msgid "Display information about a trust." msgstr "Afficher les informations sur une relation d'approbation." msgid "trust configuration" msgstr "configuration des relations d'approbation" msgid "Global Trust Configuration" msgstr "Configuration globale des relations d'approbation" msgid "Security Identifier" msgstr "Identifiant de sécurité" msgid "NetBIOS name" msgstr "Nom NetBIOS" msgid "Domain GUID" msgstr "GUID du domaine" msgid "Fallback primary group" msgstr "Groupe principal de repli" msgid "unsupported trust type" msgstr "type de relation d'approbation non pris en charge" msgid "Modify global trust configuration." msgstr "Modifier la configuration globale des relations d'approbation." #, python-format msgid "Modified \"%(value)s\" trust configuration" msgstr "Configuration de la relation d'approbation « %(value)s » modifiée." msgid "Show global trust configuration." msgstr "Afficher la configuration globale des relations d'approbation." msgid "Resolve security identifiers of users and groups in trusted domains" msgstr "" "Résoudre les identifiants de sécurité des groupes et utilisateurs des " "domaines approuvés" msgid "Security Identifiers (SIDs)" msgstr "Identifiants de sécurité (SID)" msgid "Name" msgstr "Nom" msgid "SID" msgstr "SID" msgid "Determine whether ipa-adtrust-install has been run on this system" msgstr "" "Déterminer si la commande ipa-adtrust-install a déjà été exécutée sur ce " "système" msgid "" "\n" "Users\n" "\n" "Manage user entries. All users are POSIX users.\n" "\n" "IPA supports a wide range of username formats, but you need to be aware of " "any\n" "restrictions that may apply to your particular environment. For example,\n" "usernames that start with a digit or usernames that exceed a certain length\n" "may cause problems for some UNIX systems.\n" "Use 'ipa config-mod' to change the username format allowed by IPA tools.\n" "\n" "Disabling a user account prevents that user from obtaining new Kerberos\n" "credentials. It does not invalidate any credentials that have already\n" "been issued.\n" "\n" "Password management is not a part of this module. For more information\n" "about this topic please see: ipa help passwd\n" "\n" "Account lockout on password failure happens per IPA master. The user-status\n" "command can be used to identify which master the user is locked out on.\n" "It is on that master the administrator must unlock the user.\n" "\n" "EXAMPLES:\n" "\n" " Add a new user:\n" " ipa user-add --first=Tim --last=User --password tuser1\n" "\n" " Find all users whose entries include the string \"Tim\":\n" " ipa user-find Tim\n" "\n" " Find all users with \"Tim\" as the first name:\n" " ipa user-find --first=Tim\n" "\n" " Disable a user account:\n" " ipa user-disable tuser1\n" "\n" " Enable a user account:\n" " ipa user-enable tuser1\n" "\n" " Delete a user:\n" " ipa user-del tuser1\n" msgstr "" "\n" "Utilisateurs\n" "\n" "Administration des utilisateurs. Tous les utilisateurs sont de type POSIX.\n" "\n" "IPA permet l'utilisation d'un grand nombre de formats de noms " "d'utilisateurs.\n" "Certaines restrictions peuvent cependant s'appliquer à un environnement\n" "particulier. À titre d'exemple, les noms d'utilisateurs commençant par\n" "un chiffre ou ceux excédant une certaine longueur peuvent poser souci à\n" "certains systèmes UNIX.\n" "Utiliser la commande « ipa config-mod » afin de modifier le format de nom\n" "autorisé par les outils IPA.\n" "\n" "La désactivation d'un compte utilisateur lui interdit d'obtenir de\n" "nouvelles informations de crédit Kerberos. Elle n'invalide pas les crédits\n" "déjà obtenus.\n" "\n" "L'administration des mots de passe ne fait pas partie de ce module. Pour\n" "plus d'informations sur ce sujet, cf. : ipa help passwd\n" "\n" "Le verrouillage de compte en cas d'échec de mot de passe se passe par \n" "maître IPA. La comamnde « user-status » peut être utilisée pour identifier \n" "le maître sur lequel l'utilisateur est bloqué. C'est sur ​​ce maître\n" "que l'administrateur doit déverrouiller l'utilisateur.\n" "\n" "EXEMPLES :\n" "\n" " Ajouter un nouvel utilisateur :\n" " ipa user-add --first=Tim --last=User --password tuser1\n" "\n" " Trouver tous les utilisateurs dont l'entrée contient la chaîne « Tim » :\n" " ipa user-find Tim\n" "\n" " Trouver tous les utilisateurs ayant « Tim » comme prénom :\n" " ipa user-find --first=Tim\n" "\n" " Désactiver un compte utilisateur :\n" " ipa user-disable tuser1\n" "\n" " Activer un compte utilisateur :\n" " ipa user-enable tuser1\n" "\n" " Supprimer un utilisateur :\n" " ipa user-del tuser1\n" "\n" msgid "Kerberos keys available" msgstr "Clés Kerberos disponibles" msgid "Server" msgstr "Serveur" msgid "Failed logins" msgstr "Connexions échouées" msgid "Last successful authentication" msgstr "Dernière authentification réussie" msgid "Last failed authentication" msgstr "Dernière authentification échouée" msgid "Time now" msgstr "Heure actuelle" msgid "must be TRUE or FALSE" msgstr "doit être TRUE ou FALSE" msgid "user" msgstr "utilisateur" msgid "users" msgstr "utilisateurs" msgid "User login" msgstr "Identifiant de connexion" msgid "First name" msgstr "Prénom" msgid "Last name" msgstr "Nom" msgid "Full name" msgstr "Nom complet" msgid "Display name" msgstr "Nom affiché" msgid "Initials" msgstr "Initiales" msgid "Home directory" msgstr "Répertoire utilisateur" msgid "GECOS" msgstr "GECOS" msgid "Login shell" msgstr "Shell de connexion" msgid "Kerberos principal" msgstr "Principal Kerberos" msgid "Email address" msgstr "Adresse courriel" msgid "Prompt to set the user password" msgstr "Invite de modification du mot de passe" msgid "Generate a random user password" msgstr "Créer un mot de passe aléatoire" msgid "UID" msgstr "UID" msgid "User ID Number (system will assign one if not provided)" msgstr "" "Numéro d'identifiant utilisateur (le système en assignera un si non spécifié)" msgid "Group ID Number" msgstr "Numéro d'identifiant de groupe" msgid "Street address" msgstr "Adresse" msgid "City" msgstr "Ville" msgid "State/Province" msgstr "État/province" msgid "ZIP" msgstr "Code postal" msgid "Telephone Number" msgstr "Numéro de téléphone" msgid "Mobile Telephone Number" msgstr "Numéro de téléphone mobile" msgid "Pager Number" msgstr "Numéro de téléavertisseur" msgid "Fax Number" msgstr "Numéro de fax" msgid "Org. Unit" msgstr "Unité organisationnelle" msgid "Job Title" msgstr "Titre de poste" msgid "Manager" msgstr "Responsable" msgid "Car License" msgstr "Carte d'identité" msgid "Account disabled" msgstr "Compte désactivé" #, python-format msgid "invalid e-mail format: %(email)s" msgstr "format d'e-mail invalide : %(email)s" #, python-format msgid "manager %(manager)s not found" msgstr "responsable %(manager)s introuvable" msgid "Add a new user." msgstr "Ajouter un nouvel utilisateur." #, python-format msgid "Added user \"%(value)s\"" msgstr "Utilisateur \"%(value)s\" ajouté" msgid "Don't create user private group" msgstr "Ne pas créer de groupe privé" #, python-format msgid "can be at most %(len)d characters" msgstr "doit contenir au plus %(len)d caractères" msgid "Default group for new users is not POSIX" msgstr "Le groupe par défaut des nouveaux utilisateurs n'est pas POSIX" msgid "Delete a user." msgstr "Supprimer un utilisateur." #, python-format msgid "Deleted user \"%(value)s\"" msgstr "Utilisateur \"%(value)s\" supprimé" msgid "Modify a user." msgstr "Modifier un utilisateur." #, python-format msgid "Modified user \"%(value)s\"" msgstr "Utilisateur \"%(value)s\" modifié" msgid "Search for users." msgstr "Rechercher des utilisateurs." msgid "Self" msgstr "Moi-même" msgid "Display user record for current Kerberos principal" msgstr "" "Afficher l'enregistrement utilisateur pour le principal Kerberos actuel" #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "%(count)d utilisateur correspondant" msgstr[1] "%(count)d utilisateurs correspondants" msgid "Display information about a user." msgstr "Afficher l'information sur un utilisateur." msgid "Disable a user account." msgstr "Désactiver un compte utilisateur." #, python-format msgid "Disabled user account \"%(value)s\"" msgstr "Compte utilisateur \"%(value)s\" désactivé" msgid "Enable a user account." msgstr "Activer un compte utilisateur." #, python-format msgid "Enabled user account \"%(value)s\"" msgstr "Compte utilisateur \"%(value)s\" activé" msgid "" "\n" " Unlock a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator." msgstr "" "\n" " Déverrouiller un compte utilisateur\n" "\n" " Un compte utilisateur peut se verrouiller si le mot de passe est saisi\n" " de manière incorrecte de trop nombreuses fois sur une période précise\n" " spécifiée par la politique de mot de passe. Le verrouillage d'un compte\n" " est une situation temporaire et le compte peut être déverrouillé par un\n" " administrateur." #, python-format msgid "Unlocked account \"%(value)s\"" msgstr "Compte utilisateur \"%(value)s\" déverrouillé" msgid "" "\n" " Lockout status of a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator.\n" "\n" " This connects to each IPA master and displays the lockout status on\n" " each one.\n" "\n" " To determine whether an account is locked on a given server you need\n" " to compare the number of failed logins and the time of the last " "failure.\n" " For an account to be locked it must exceed the maxfail failures within\n" " the failinterval duration as specified in the password policy " "associated\n" " with the user.\n" "\n" " The failed login counter is modified only when a user attempts a log in\n" " so it is possible that an account may appear locked but the last failed\n" " login attempt is older than the lockouttime of the password policy. " "This\n" " means that the user may attempt a login again. " msgstr "" "\n" " Verrouillage de l'état d'un compte utilisateur\n" "\n" " Un compte peut être verrouillé si un mot de passe incorrect est entre à " "plusieurs\n" " reprises pendant une période de temps donnée selon la règle de contrôle " "des mots de\n" " passe. Le verrouillage du compte est un état temporaire ; le compte peut " "être\n" " déverrouillé par un administrateur.\n" "\n" " Ce dernier se connecte sur l'IPA maître et affiche l'état verrouillé de\n" " chacun.\n" "\n" " Pour savoir si un compte est verrouillé sur un serveur donné, vous " "devez\n" " comparer le nombre d'échecs de connexion et l'heure du dernier échec.\n" " Pour qu'un compte soit verrouillé, le nombre d'échecs doit dépasser le " "maximum\n" " autorisé dans le délai voulu tel que défini dans la règle pour le mot de " "passe\n" " correspondant à l'utilisateur.\n" "\n" " Le compteur d'échecs de connexion n'est modifié que lorsqu'un " "utilisateur tente une\n" " connexion, il est donc possible qu'un compte apparaisse bloqué mais que " "la dernière\n" " tentative de connexion soit antérieure à la durée de verrouillage de la " "règle. Cela\n" " signifie que l'utilisateur peut tenter de connecter à nouveau." #, python-format msgid "%(host)s failed: %(error)s" msgstr "%(host)s en échec : %(error)s" #, python-format msgid "%(host)s failed" msgstr "%(host)s en échec" #, python-format msgid "Account disabled: %(disabled)s" msgstr "Compte désactivé : %(disabled)s" msgid "operation not defined" msgstr "opération non définie" msgid "not allowed to perform this command" msgstr "non autorisé à effectuer cette commande" msgid "No such virtual command" msgstr "Commande virtuelle inconnue" msgid "any of the configured servers" msgstr "n'importe lequel des serveurs configurés" msgid "could not allocate unique new session_id" msgstr "impossible d'allouer un unique session_id" msgid "Filename is empty" msgstr "Le nom de fichier est vide" #, python-format msgid "Permission denied: %(file)s" msgstr "Autorisation refusée : %(file)s" msgid "empty DNS label" msgstr "libellé DNS vide" msgid "DNS label cannot be longer that 63 characters" msgstr "un libellé DNS ne peut excéder 63 caractères" #, python-format msgid "" "only letters, numbers,%(underscore)s and - are allowed. DNS label may not " "start or end with -" msgstr "" "seuls des lettres, nombres %(underscore)s et - sont autorisés. Les noms DNS " "ne peuvent commencer ou se terminer par -" msgid "" "mail account may only include letters, numbers, -, _ and a dot. There may " "not be consecutive -, _ and . characters. Its parts may not start or end " "with - or _" msgstr "" "un compte de messagerie ne peut inclure que des lettres, des chiffres, -, _ " "et un point. Il ne peut y avoir de caractères -, _ et . consécutifs. Il ne " "peut démarrer ou finir par - ou _" msgid "cannot be longer that 255 characters" msgstr "ne peut excéder 255 caractères." msgid "too many '@' characters" msgstr "trop de caractères '@'" msgid "missing address domain" msgstr "domaine d'adresse manquant" msgid "missing mail account" msgstr "compte de messagerie manquant" msgid "hostname contains empty label (consecutive dots)" msgstr "" "le nom du système contient un libellé vide (plusieurs points consécutifs)" msgid "not fully qualified" msgstr "pas pleinement qualifié" msgid "invalid SSH public key" msgstr "clé publique SSH invalide" msgid "options are not allowed" msgstr "les options ne sont pas autorisées" msgid "improperly formatted DER-encoded certificate" msgstr "formatage incorrect du certificat encodé DER" #, python-format msgid "Issuer \"%(issuer)s\" does not match the expected issuer" msgstr "L'Émetteur \"%(issuer)s\" ne correspond pas à l'émetteur attendu" #, python-format msgid "Retrieving CA cert chain failed: %s" msgstr "Échec de la récupération de la chaîne de certificat de l'AC : %s" #, python-format msgid "request failed with HTTP status %d" msgstr "échec de la requête avec le code état HTTP %d" #, python-format msgid "Retrieving CA status failed: %s" msgstr "Échec de la récupération de l'état de l'AC : %s" #, python-format msgid "objectclass %s not found" msgstr "classe d'objet %s introuvable" msgid "" "\n" "Classes to manage trust joins using DCE-RPC calls\n" "\n" "The code in this module relies heavily on samba4-python package\n" "and Samba4 python bindings.\n" msgstr "" "\n" "Classes permettant de gérer les insertions d'approbations utilisant les " "appels DCE-RPC\n" "\n" "Le code de ce module s'appuie en majeure partie sur le paquet samba4-python " "package\n" "and Samba4 python bindings.\n" msgid "CIFS server denied your credentials" msgstr "Le serveur CIFS a refusé vos informations d'identification" msgid "communication with CIFS server was unsuccessful" msgstr "la communication avec le serveur CIFS a échoué" msgid "AD domain controller" msgstr "Contrôleur de domaine AD" msgid "unsupported functional level" msgstr "niveau de fonctionnalité non pris en charge" msgid "Cannot find specified domain or server name" msgstr "Impossible de trouver le domaine ou le serveur indiqué" msgid "At least the domain or IP address should be specified" msgstr "Au moins un nom de domaine ou une adresse IP doit être indiquée" #, python-format msgid "" "CIFS server communication error: code \"%(num)s\",\n" " message \"%(message)s\" (both may be \"None\")" msgstr "" "Erreur de communication avec le serveur CIFS : code \"%(num)s\",\n" " message \"%(message)s\" (les deux pouvant être vides)" msgid "" "communication with trusted domains is allowed for Trusts administrator group " "members only" msgstr "" "la communication avec les domaines approuvé n'est autorisée que pour les " "membres du groupe d'administration des relations d'approbation." msgid "no trusted domain is configured" msgstr "pas de relation d'approbation configurée" msgid "domain is not configured" msgstr "le domaine n'est pas configuré" msgid "SID is not valid" msgstr "Le SID est invalide" msgid "SID does not match exactlywith any trusted domain's SID" msgstr "Le SID ne correspond à aucun SID du domaine approuvé" msgid "SID does not match any trusted domain" msgstr "Le SID ne correspond à aucun domaine approuvé" msgid "Trust setup" msgstr "Configuration des relations d'approbation" msgid "Our domain is not configured" msgstr "Notre domaine n'est pas configuré" msgid "No trusted domain is not configured" msgstr "Aucun domaine approuvé n'est pas configuré" msgid "trusted domain object" msgstr "objet domaine approuvé" msgid "domain is not trusted" msgstr "le domaine n'est pas approuvé" msgid "no trusted domain matched the specified flat name" msgstr "aucun domaine approuvé ne correspond au nom spécifié" msgid "trusted domain object not found" msgstr "objet relation d'approbation introuvable" msgid "Ambiguous search, user domain was not specified" msgstr "Recherche ambigüe, le domaine utilisateur n'a pas été spécifié" msgid "Trusted domain did not return a unique object" msgstr "Le domaine approuvé n'a pas renvoyé un unique objet" msgid "Trusted domain did not return a valid SID for the object" msgstr "Le domaine approuvé n'a pas renvoyé un SID valide pour l'objet" msgid "trusted domain user not found" msgstr "utilisateur de domaine approuvé introuvable" #, python-format msgid "" "KDC for %(domain)s denied trust account for IPA domain with a message " "'%(message)s'" msgstr "" "Le KDC pour %(domain)s a refusé le compte approuvé pour le domaine IPA avec " "le message « %(message)s »" msgid "Cannot retrieve trusted domain GC list" msgstr "Impossible de récupérer la liste de GC pour le domaine approuvé" msgid "CIFS credentials object" msgstr "Objet identification CIFS" #, python-format msgid "CIFS server %(host)s denied your credentials" msgstr "Le serveur CIFS %(host)s a refusé vos informations d'identification" #, python-format msgid "Cannot establish LSA connection to %(host)s. Is CIFS server running?" msgstr "" "Impossible d'établir la connexion LSA vers %(host)s. Le serveur CIFS est-il " "en fonction ?" #, python-format msgid "" "the IPA server and the remote domain cannot share the same NetBIOS name: %s" msgstr "" "le serveur IPA et le domaine distant ne peuvent partager le même nom " "NetBIOS : %s" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "Impossible de communiquer avec le CMS (%s)" msgid "Unable to communicate with CMS" msgstr "Impossible de communiquer avec le CMS" msgid "find not supported on CAs upgraded from 9 to 10" msgstr "" "la recherche n'est pas prise en charge sur les AC mises à jour de la version " "9 à la version 10" msgid "The hostname to register as" msgstr "Le nom de système sous lequel s'enregistrer" msgid "The IPA realm" msgstr "Le domaine IPA" msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "Plate-forme matérielle du système (par ex. Lenovo T61)" msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "Système d'exploitation et version du système (par ex. Fedora 9)" #, python-format msgid "" "Insufficient 'write' privilege to the 'krbLastPwdChange' attribute of entry " "'%s'." msgstr "" "Privilège en écriture insuffisant sur l'attribut « krbLastPwdChange »de " "l'entrée « %s »." msgid "Request must be a dict" msgstr "La requête doit être un dictionnaire" msgid "Request is missing \"method\"" msgstr "Il manque le paramètre « method » à la requête" msgid "Request is missing \"params\"" msgstr "Il manque le paramètre « params » à la requête" msgid "params must be a list" msgstr "params doit être une liste" msgid "params must contain [args, options]" msgstr "params doit contenir [args, options]" msgid "params[0] (aka args) must be a list" msgstr "params[0] (args) doit être une liste" msgid "params[1] (aka options) must be a dict" msgstr "params[1] (options) doit être un dictionnaire " #, c-format msgid "cannot open configuration file %s\n" msgstr "impossible d'ouvrir le fichier de configuration %s\n" #, c-format msgid "cannot stat() configuration file %s\n" msgstr "impossible d'utiliser stat() sur le fichier de configuration %s\n" #, c-format msgid "out of memory\n" msgstr "mémoire saturée\n" #, c-format msgid "read error\n" msgstr "erreur en lecture\n" #, c-format msgid "Kerberos context initialization failed: %1$s (%2$d)\n" msgstr "Échec de l'initialisation du contexte Kerberos : %1$s (%2$d)\n" #, c-format msgid "Unable to parse principal: %1$s (%2$d)\n" msgstr "Impossible d'analyser le principal : %1$s (%2$d)\n" #, c-format msgid "No keys accepted by KDC\n" msgstr "Aucune clé acceptée par le KDC\n" #, c-format msgid "Out of memory \n" msgstr "Mémoire saturée\n" #, c-format msgid "Out of Memory!\n" msgstr "Mémoire saturée !\n" #, c-format msgid "Failed to create control!\n" msgstr "Échec à la création du contrôle !\n" #, c-format msgid "Unable to initialize ldap library!\n" msgstr "Impossible d'initialiser la bibliothèque LDAP !\n" #, c-format msgid "Unable to set LDAP_OPT_X_SASL_NOCANON\n" msgstr "Impossible de positionner LDAP_OPT_X_SASL_NOCANON\n" #, c-format msgid "Unable to set ldap options!\n" msgstr "Impossible de définir les options LDAP !\n" #, c-format msgid "Simple bind failed\n" msgstr "Échec de la connexion simple\n" #, c-format msgid "Operation failed! %s\n" msgstr "Échec de l'opération %s !\n" #, c-format msgid "Missing reply control!\n" msgstr "Absence de contrôle dans la réponse !\n" #, c-format msgid "ber_init() failed, Invalid control ?!\n" msgstr "Échec de ber_init(), contrôle invalide ?!\n" #, c-format msgid "ber_scanf() failed, unable to find kvno ?!\n" msgstr "échec de ber_scanf() failed, kvno introuvable ?!\n" #, c-format msgid "Failed to retrieve encryption type type #%d\n" msgstr "Échec lors de la récupération du type de chiffrement #%d\n" #, c-format msgid "Failed to retrieve encryption type %1$s (#%2$d)\n" msgstr "Échec lors de la récupération du type de chiffrement %1$s (#%2$d)\n" #, c-format msgid "Failed to retrieve any keys" msgstr "Échec lors de la récupération des clés" msgid "New Principal Password" msgstr "Nouveau mot de passe du principal" msgid "Verify Principal Password" msgstr "Vérfier le mot de passe du principal" msgid "Print as little as possible" msgstr "Affiche aussi peu que possible" msgid "Output only on errors" msgstr "N'affiche que les erreurs" msgid "Contact this specific KDC Server" msgstr "Contacter ce serveur KDC spécifique" msgid "Server Name" msgstr "Nom de serveur" msgid "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)" msgstr "" "Le principal pour lequel obtenir le (par ex: ftp/ftp.example.com@EXAMPLE.COM)" msgid "Kerberos Service Principal Name" msgstr "Nom de principal de service Kerberos" msgid "File were to store the keytab information" msgstr "Fichier dans lequel stocker l'information de keytab" msgid "Keytab File Name" msgstr "Nom de fichier keytab" msgid "Encryption types to request" msgstr "Type de chiffrement à demander" msgid "Comma separated encryption types list" msgstr "Liste séparée par des virgules des types de chiffrement" msgid "Show the list of permitted encryption types and exit" msgstr "Affiche la liste des types de chiffrement autorisés, et sort." msgid "Permitted Encryption Types" msgstr "Type de chiffrements autorisés" msgid "Asks for a non-random password to use for the principal" msgstr "Demande un mot de passe non aléatoire à utiliser pour le principal" msgid "LDAP DN" msgstr "DN LDAP" msgid "DN to bind as if not using kerberos" msgstr "DN à utiliser pour la connexion en cas de non-utilisation de kerberos" msgid "LDAP password" msgstr "Mot de passe LDAP" msgid "password to use if not using kerberos" msgstr "" "mot de passe à utiliser pour la connexion en cas de non-utilisation de " "kerberos" #, c-format msgid "Kerberos context initialization failed\n" msgstr "Échec de l'initialisation du contexte Kerberos\n" #, c-format msgid "No system preferred enctypes ?!\n" msgstr "Pas d'enctypes préféré sur le système ?!\n" #, c-format msgid "Supported encryption types:\n" msgstr "Type de chiffrements supportés :\n" #, c-format msgid "Warning: failed to convert type (#%d)\n" msgstr "Avertissement : échec de conversion de type (#%d)\n" #, c-format msgid "Bind password required when using a bind DN.\n" msgstr "" "Mot de passe de connexion requis lors de l'utilisation d'un DN de " "connexion.\n" #, c-format msgid "" "Warning: salt types are not honored with randomized passwords (see opt. -P)\n" msgstr "" "Avertissement : les types de sels ne sont pas utilisés avec les mots de " "passe aléatoires (cf. option -P)\n" #, c-format msgid "Invalid Service Principal Name\n" msgstr "Nom de principal de service invalide\n" #, c-format msgid "Kerberos Credential Cache not found. Do you have a Kerberos Ticket?\n" msgstr "" "Cache de crédits Kerberos introuvable. Possédez-vous un ticket Kerberos ?\n" #, c-format msgid "" "Kerberos User Principal not found. Do you have a valid Credential Cache?\n" msgstr "" "Principal d'utilisateur Kerberos introuvable. Possédez-vous un cache de " "crédits Kerberos ?\n" #, c-format msgid "Failed to open Keytab\n" msgstr "Échec à l'ouverture du keytab\n" #, c-format msgid "Failed to create key material\n" msgstr "Échec de création du contenu de la clé\n" #, c-format msgid "Failed to add key to the keytab\n" msgstr "Échec lors de l'ajout de la clé au keytab\n" #, c-format msgid "Failed to close the keytab\n" msgstr "Échec à la fermeture du keytab\n" #, c-format msgid "Keytab successfully retrieved and stored in: %s\n" msgstr "Récupération du keytab et stockage avec succès dans : %s\n" #, c-format msgid "No permission to join this host to the IPA domain.\n" msgstr "Inscription de ce système au domaine IPA interdite.\n" #, c-format msgid "No write permissions on keytab file '%s'\n" msgstr "Pas de permissions en écriture sur le fichier keytab '%s'\n" #, c-format msgid "access() on %1$s failed: errno = %2$d\n" msgstr "Échec de access() sur %1$s : errno = %2$d\n" #, c-format msgid "Out of memory!" msgstr "Mémoire saturée !" #, c-format msgid "Unable to initialize connection to ldap server: %s" msgstr "Impossible d'établir la connexion au serveur LDAP : %s" #, c-format msgid "Unable to enable SSL in LDAP\n" msgstr "Impossible d'activer SSL dans LDAP\n" #, c-format msgid "Unable to set LDAP version\n" msgstr "Impossible de positionner la version LDAP\n" #, c-format msgid "Bind failed: %s\n" msgstr "Échec de bind : %s\n" #, c-format msgid "Search for %1$s on rootdse failed with error %2$d\n" msgstr "La recherche de %1$s sur rootdse a échoué avec l'erreur %2$d\n" #, c-format msgid "No values for %s" msgstr "Pas de valeurs pour %s" #, c-format msgid "Search for IPA namingContext failed with error %d\n" msgstr "La recherche du namingContext d'IPA a échoué avec l'erreur %d\n" #, c-format msgid "IPA namingContext not found\n" msgstr "namingContext IPA introuvable\n" #, c-format msgid "Out of memory!\n" msgstr "Mémoire saturée !\n" #, c-format msgid "Search for ipaCertificateSubjectBase failed with error %d" msgstr "Échec de la recherche de ipaCertificateSubjectBase avec une erreur %d" #, c-format msgid "Unable to determine root DN of %s\n" msgstr "Impossible de déterminer le DN racine de %s\n" #, c-format msgid "Incorrect password.\n" msgstr "Mot de passe incorrect.\n" #, c-format msgid "Unable to determine certificate subject of %s\n" msgstr "Impossible de déterminer le sujet du certificat de %s\n" #, c-format msgid "Enrollment failed. %s\n" msgstr "Échec de l'enregistrement. %s\n" #, c-format msgid "principal not found in XML-RPC response\n" msgstr "principal introuvable dans la réponse XML-RPC\n" #, c-format msgid "Host is already joined.\n" msgstr "Système déjà inscrit.\n" #, c-format msgid "Unable to determine IPA server from %s\n" msgstr "Impossible de déterminer le serveur IPA depuis %s\n" #, c-format msgid "The hostname must be fully-qualified: %s\n" msgstr "Le nom du système doit être pleinement qualifié : %s\n" #, c-format msgid "Unable to join host: Kerberos context initialization failed\n" msgstr "" "Impossible d'inscrire le système : échec à l'initialisation du contexte " "Kerberos\n" #, c-format msgid "Error resolving keytab: %s.\n" msgstr "Erreur à la résolution du keytab : %s.\n" #, c-format msgid "Error getting default Kerberos realm: %s.\n" msgstr "Erreur lors de l'obtention du domaine Kerberos par défaut : %s.\n" #, c-format msgid "Error parsing \"%1$s\": %2$s.\n" msgstr "Erreur à l'analyse de « %1$s » : %2$s.\n" #, c-format msgid "Error obtaining initial credentials: %s.\n" msgstr "Impossible d'obtenir les crédits initiaux : %s.\n" #, c-format msgid "Unable to generate Kerberos Credential Cache\n" msgstr "Impossible de créer le cache de crédits Kerberos\n" #, c-format msgid "Error storing creds in credential cache: %s.\n" msgstr "Erreur lors du stockage des crédits dans le cache : %s.\n" #, c-format msgid "Unenrollment successful.\n" msgstr "Désinscription réussie.\n" #, c-format msgid "Unenrollment failed.\n" msgstr "Échec de la désinscription.\n" #, c-format msgid "result not found in XML-RPC response\n" msgstr "résultat de la réponse XML-RPC introuvable\n" #, c-format msgid "The hostname must not be: %s\n" msgstr "Le nom de système ne peut être : %s\n" #, c-format msgid "Unable to join host: Kerberos Credential Cache not found\n" msgstr "" "Impossible d'inscrire le système : cache de crédit Kerberos introuvable\n" #, c-format msgid "" "Unable to join host: Kerberos User Principal not found and host password not " "provided.\n" msgstr "" "Impossible d'inscrire le système : Principal d'utilisateur Kerberos " "introuvable et mot de passe non fourni.\n" #, c-format msgid "fork() failed\n" msgstr "echec de fork()\n" #, c-format msgid "ipa-getkeytab not found\n" msgstr "ipa-getkeytab introuvable\n" #, c-format msgid "ipa-getkeytab has bad permissions?\n" msgstr "ipa-getkeytab a des permissions incorrectes ?\n" #, c-format msgid "executing ipa-getkeytab failed, errno %d\n" msgstr "échec de l'exécution de ipa-getkeytab, errno %d\n" #, c-format msgid "child exited with %d\n" msgstr "processus fils terminé avec %d\n" #, c-format msgid "Certificate subject base is: %s\n" msgstr "Le sujet de base du certificat est : %s\n" msgid "Print the raw XML-RPC output in GSSAPI mode" msgstr "Affiche la sortie XML-RPC brute en mode GSSAPI" msgid "Quiet mode. Only errors are displayed." msgstr "Mode silencieux. Seules les erreurs sont affichées." msgid "Unenroll this host from IPA server" msgstr "Désinscrire ce système du serveur IPA" msgid "Hostname of this server" msgstr "Nom de système de ce serveur" msgid "hostname" msgstr "nom de système" msgid "IPA Server to use" msgstr "Serveur IPA à utiliser" msgid "Specifies where to store keytab information." msgstr "Spécifie où stocker l'information keytab." msgid "filename" msgstr "nom de fichier" msgid "Force the host join. Rejoin even if already joined." msgstr "" "Forcer l'hôte à rejoindre le domaine. Rejoindre à nouveau même s'il a déjà " "rejoint le domaine." msgid "LDAP password (if not using Kerberos)" msgstr "Mot de passe LDAP (hors utilisation de Kerberos)" msgid "password" msgstr "mot de passe" msgid "LDAP basedn" msgstr "basedn LDAP" msgid "basedn" msgstr "basedn" #, c-format msgid "Unable to parse principal name\n" msgstr "Impossible d'analyser le nom du principal\n" #, c-format msgid "krb5_parse_name %1$d: %2$s\n" msgstr "krb5_parse_name %1$d : %2$s\n" #, c-format msgid "Removing principal %s\n" msgstr "Suppression du principal %s\n" #, c-format msgid "Failed to open keytab\n" msgstr "Impossible d'ouvrir le keytab\n" #, c-format msgid "principal not found\n" msgstr "principal introuvable\n" #, c-format msgid "krb5_kt_get_entry %1$d: %2$s\n" msgstr "krb5_kt_get_entry %1$d : %2$s\n" #, c-format msgid "Unable to remove entry\n" msgstr "Impossible de supprimer l'entrée\n" #, c-format msgid "kvno %d\n" msgstr "kvno %d\n" #, c-format msgid "krb5_kt_remove_entry %1$d: %2$s\n" msgstr "krb5_kt_remove_entry %1$d : %2$s\n" #, c-format msgid "Unable to parse principal\n" msgstr "Impossible d'analyser le principal\n" #, c-format msgid "krb5_unparse_name %1$d: %2$s\n" msgstr "krb5_unparse_name %1$d : %2$s\n" #, c-format msgid "realm not found\n" msgstr "domaine introuvable\n" msgid "Print debugging information" msgstr "Affiche les informations de débogage" msgid "Debugging output" msgstr "Sortie de débogage" msgid "Remove all principals in this realm" msgstr "Retirer tous les principals de ce royaume" #, c-format msgid "Failed to open keytab '%1$s': %2$s\n" msgstr "Échec lors de l'ouverture de la keytab « %1$s » : %2$s\n" #, c-format msgid "Closing keytab failed\n" msgstr "La fermeture du tableau des clés a échoué\n" #, c-format msgid "krb5_kt_close %1$d: %2$s\n" msgstr "krb5_kt_close %1$d : %2$s\n" msgid "Out of memory!?\n" msgstr "Mémoire saturée !?\n" msgid "Out of memory\n" msgstr "Mémoire saturée\n" msgid "Warning unrecognized encryption type.\n" msgstr "Avertissement, type de chiffrement inconnu.\n" msgid "Warning unrecognized salt type.\n" msgstr "Avertissement, type de sel inconnu.\n" msgid "Enctype comparison failed!\n" msgstr "Échec de comparaison enctype !\n" msgid "Failed to create random key!\n" msgstr "Échec à la création de la clé aléatoire !\n" msgid "Failed to create key!\n" msgstr "Échec à la création de la clé !\n" msgid "Bad or unsupported salt type.\n" msgstr "Type de sel non-conforme ou non pris en compte.\n" freeipa-3.3.4/install/po/ja.po0000664000175000017500000002477512271663206015544 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Tomoyuki KATO , 2012 # é«˜ä¸€äººå‚ @欠陥éºä¼å­ , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Japanese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ja\n" "Plural-Forms: nplurals=1; plural=0;\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "確èªã®ãŸã‚å†ã³ %(label)s を入力ã—ã¦ãã ã•ã„: " #, c-format msgid "Passwords do not match!" msgstr "パスワードãŒé•ã„ã¾ã™ã€‚" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "%(server)s ã‹ã‚‰æœªçŸ¥ã®ã‚¨ãƒ©ãƒ¼ %(code)d: %(error)s" msgid "an internal error has occurred" msgstr "内部エラーãŒç™ºç”Ÿã—ã¾ã—ãŸ" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "無効㪠JSON-RPC リクエスト: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Kerberos エラー: %(major)s/%(minor)s" msgid "Passwords do not match" msgstr "パスワードãŒé•ã„ã¾ã™" msgid "Command not implemented" msgstr "コマンドãŒå®Ÿè£…ã•れã¦ã„ã¾ã›ã‚“" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "ã“ã®ã‚¨ãƒ³ãƒˆãƒªãƒ¼ã¯ã™ã§ã«å­˜åœ¨ã—ã¾ã™" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Base64 å½¢å¼ã®ãƒ‡ã‚³ãƒ¼ãƒ‰ã«å¤±æ•—: %(reason)s" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s: %(info)s" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "must be an integer" msgstr "æ•´æ•°ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must be at least %(minvalue)d" msgstr "å°‘ãªãã¨ã‚‚ %(minvalue)d ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "パターン \"%(pattern)s\" ãŒä¸€è‡´ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™" msgid "must be binary data" msgstr "ãƒã‚¤ãƒŠãƒªãƒ¼ãƒ‡ãƒ¼ã‚¿ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "å°‘ãªãã¨ã‚‚ %(minlength)d ãƒã‚¤ãƒˆã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "大ããã¦ã‚‚ %(maxlength)d ãƒã‚¤ãƒˆã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must be exactly %(length)d bytes" msgstr "ã¡ã‚‡ã†ã© %(length)d ãƒã‚¤ãƒˆã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" msgid "must be Unicode text" msgstr "Unicode テキストã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must be at least %(minlength)d characters" msgstr "å°‘ãªãã¨ã‚‚ %(minlength)d 文字ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" #, python-format msgid "must be exactly %(length)d characters" msgstr "ã¡ã‚‡ã†ã© %(length)d 文字ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™" msgid "A list of ACI values" msgstr "ACI 値ã®ä¸€è¦§" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "å°‘ãªãã¨ã‚‚ type, filter, subtree, targetgroup, attrs ã¾ãŸã¯ memberof ã®ã©ã‚Œã‹" "ãŒå¿…è¦ã§ã™" #, python-format msgid "Group '%s' does not exist" msgstr "グループ '%s' ãŒå­˜åœ¨ã—ã¾ã›ã‚“" #, python-format msgid "ACI with name \"%s\" not found" msgstr "åå‰ \"%s\" ã® ACI ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "ACI å" msgid "User group" msgstr "ユーザーグループ" msgid "Permissions" msgstr "権é™" msgid "Member of a group" msgstr "グループã®ãƒ¡ãƒ³ãƒãƒ¼" msgid "Filter" msgstr "フィルター" msgid "Fingerprint (MD5)" msgstr "フィンガープリント (MD5)" msgid "Fingerprint (SHA1)" msgstr "フィンガープリント (SHA1)" #, python-format msgid "invalid domain-name: %s" msgstr "無効ãªãƒ‰ãƒ¡ã‚¤ãƒ³å: %s" #, python-format msgid "%s record" msgstr "%s レコード" #, python-format msgid "%s Record" msgstr "%s レコード" msgid "IP Address" msgstr "IP アドレス" msgid "Port" msgstr "ãƒãƒ¼ãƒˆ" msgid "Labels" msgstr "ラベル" msgid "Fingerprint" msgstr "フィンガープリント" msgid "Text Data" msgstr "テキストデータ" msgid "group" msgstr "グループ" msgid "groups" msgstr "グループ" msgid "User Group" msgstr "ユーザーグループ" msgid "Create a new group." msgstr "æ–°ã—ã„グループを作æˆã—ã¾ã™ã€‚" msgid "Delete group." msgstr "グループを削除ã—ã¾ã™ã€‚" msgid "Modify a group." msgstr "グループを変更ã—ã¾ã™ã€‚" msgid "Search for groups." msgstr "グループを検索ã—ã¾ã™ã€‚" msgid "Create a new HBAC rule." msgstr "æ–°ã—ã„ HBAC ルールを作æˆã—ã¾ã™ã€‚" msgid "Delete an HBAC rule." msgstr "HBAC ルールを削除ã—ã¾ã™ã€‚" msgid "Modify an HBAC rule." msgstr "HBAC ルールを変更ã—ã¾ã™ã€‚" msgid "Search for HBAC rules." msgstr "HBAC ルールを検索ã—ã¾ã™ã€‚" msgid "Display the properties of an HBAC rule." msgstr "HBAC ルールã®ãƒ—ロパティーを表示ã—ã¾ã™ã€‚" msgid "Enable an HBAC rule." msgstr "HBAC ルールを有効化ã—ã¾ã™ã€‚" msgid "Disable an HBAC rule." msgstr "HBAC ルールを無効化ã—ã¾ã™ã€‚" msgid "HBAC services" msgstr "HBAC サービス" msgid "HBAC Service" msgstr "HBAC サービス" msgid "Add a new HBAC service." msgstr "æ–°ã—ã„ HBAC サービスを追加ã—ã¾ã™ã€‚" msgid "Delete an existing HBAC service." msgstr "既存㮠HBAC サービスを削除ã—ã¾ã™ã€‚" msgid "Modify an HBAC service." msgstr "HBAC サービスを変更ã—ã¾ã™ã€‚" msgid "Search for HBAC services." msgstr "HBAC サービスを検索ã—ã¾ã™ã€‚" msgid "Display information about an HBAC service." msgstr "HBAC サービスã«é–¢ã™ã‚‹æƒ…報を表示ã—ã¾ã™ã€‚" msgid "HBAC service group" msgstr "HBAC サービスグループ" msgid "HBAC service groups" msgstr "HBAC サービスグループ" msgid "HBAC Service Groups" msgstr "HBAC サービスグループ" msgid "HBAC Service Group" msgstr "HBAC サービスグループ" msgid "Add a new HBAC service group." msgstr "æ–°ã—ã„ HBAC サービスグループを追加ã—ã¾ã™ã€‚" msgid "Delete an HBAC service group." msgstr "HBAC サービスグループを削除ã—ã¾ã™ã€‚" msgid "Modify an HBAC service group." msgstr "HBAC サービスグループを変更ã—ã¾ã™ã€‚" msgid "Search for an HBAC service group." msgstr "HBAC サービスグループを検索ã—ã¾ã™ã€‚" msgid "Display information about an HBAC service group." msgstr "HBAC サービスグループã«é–¢ã™ã‚‹æƒ…報を表示ã—ã¾ã™ã€‚" msgid "Add members to an HBAC service group." msgstr "HBAC サービスグループã«ãƒ¡ãƒ³ãƒãƒ¼ã‚’追加ã—ã¾ã™ã€‚" msgid "Remove members from an HBAC service group." msgstr "HBAC サービスグループã‹ã‚‰ãƒ¡ãƒ³ãƒãƒ¼ã‚’削除ã—ã¾ã™ã€‚" msgid "host" msgstr "ホスト" msgid "hosts" msgstr "ホスト" msgid "Host" msgstr "ホスト" msgid "Add a new host." msgstr "æ–°ã—ã„ホストを追加ã—ã¾ã™ã€‚" msgid "Delete a host." msgstr "ホストを削除ã—ã¾ã™ã€‚" msgid "Search for hosts." msgstr "ホストを検索ã—ã¾ã™ã€‚" msgid "host group" msgstr "ホストグループ" msgid "host groups" msgstr "ホストグループ" msgid "Host Group" msgstr "ホストグループ" msgid "Refresh" msgstr "æ›´æ–°" msgid "Set" msgstr "設定" msgid "Edit ${entity}" msgstr "${entity} ã®ç·¨é›†" msgid "Validation error" msgstr "検証エラー" msgid "HTTP Error" msgstr "HTTP エラー" msgid "Internal Error" msgstr "内部エラー" msgid "IPA Error" msgstr "IPA エラー" msgid "Unknown Error" msgstr "未知ã®ã‚¨ãƒ©ãƒ¼" msgid "URL" msgstr "URL" msgid "Add Rule" msgstr "ルールã®è¿½åŠ " msgid "Default host group" msgstr "標準ã®ãƒ›ã‚¹ãƒˆã‚°ãƒ«ãƒ¼ãƒ—" msgid "Default user group" msgstr "標準ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚°ãƒ«ãƒ¼ãƒ—" msgid "Certificates" msgstr "証明書" msgid "Group Options" msgstr "グループオプション" msgid "Search Options" msgstr "検索オプション" msgid "User Options" msgstr "ユーザーオプション" msgid "Options" msgstr "オプション" msgid "Rules" msgstr "ルール" msgid "Kerberos Key" msgstr "Kerberos キー" msgid "One-Time-Password" msgstr "ワンタイムパスワード" msgid "One-Time-Password Not Present" msgstr "ワンタイムパスワードãŒå­˜åœ¨ã—ã¾ã›ã‚“" msgid "One-Time-Password Present" msgstr "ワンタイムパスワードãŒå­˜åœ¨ã—ã¾ã™" msgid "Reset OTP" msgstr "OTP ã®ãƒªã‚»ãƒƒãƒˆ" msgid "Reset One-Time-Password" msgstr "ワンタイムパスワードをリセットã—ã¾ã™" msgid "Set One-Time-Password" msgstr "ワンタイムパスワードを設定ã—ã¾ã™" msgid "Account" msgstr "アカウント" msgid "Account Status" msgstr "アカウント状態" msgid "password policy" msgstr "パスワードãƒãƒªã‚·ãƒ¼" msgid "password policies" msgstr "パスワードãƒãƒªã‚·ãƒ¼" msgid "Password Policies" msgstr "パスワードãƒãƒªã‚·ãƒ¼" msgid "role" msgstr "役割" msgid "roles" msgstr "役割" msgid "Add a new role." msgstr "æ–°ã—ã„役割を追加ã—ã¾ã™ã€‚" msgid "Delete a role." msgstr "役割を削除ã—ã¾ã™ã€‚" msgid "Modify a role." msgstr "役割を変更ã—ã¾ã™ã€‚" msgid "Search for roles." msgstr "役割を検索ã—ã¾ã™ã€‚" msgid "Display information about a role." msgstr "役割ã«é–¢ã™ã‚‹æƒ…報を表示ã—ã¾ã™ã€‚" msgid "sudo command" msgstr "sudo コマンド" msgid "sudo commands" msgstr "sudo コマンド" msgid "Sudo Commands" msgstr "sudo コマンド" msgid "Sudo Command" msgstr "sudo コマンド" msgid "sudo rule" msgstr "sudo ルール" msgid "sudo rules" msgstr "sudo ルール" msgid "Sudo Rules" msgstr "sudo ルール" msgid "Sudo Rule" msgstr "sudo ルール" msgid "user" msgstr "ユーザー" msgid "users" msgstr "ユーザー" msgid "Add a new user." msgstr "æ–°ã—ã„ユーザーを追加ã—ã¾ã™ã€‚" msgid "Delete a user." msgstr "ユーザーを削除ã—ã¾ã™ã€‚" msgid "Modify a user." msgstr "ユーザーを変更ã—ã¾ã™ã€‚" msgid "Disable a user account." msgstr "ユーザーアカウントを無効化ã—ã¾ã™ã€‚" msgid "Enable a user account." msgstr "ユーザーアカウントを有効化ã—ã¾ã™ã€‚" msgid "invalid SSH public key" msgstr "無効㪠SSH 公開éµ" msgid "Out of memory!?\n" msgstr "メモリーä¸è¶³!?\n" msgid "Out of memory\n" msgstr "メモリーä¸è¶³\n" freeipa-3.3.4/install/po/ru.po0000664000175000017500000007212412271663206015567 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Alexander Ivanov , 2011 # Andrew Martynov , 2010 # Azamat Hackimov , 2012 # jdennis , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ru\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Повторно введите %(label)s Ð´Ð»Ñ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸: " #, c-format msgid "Passwords do not match!" msgstr "Пароли не Ñовпадают!" msgid "Command name" msgstr "Ð˜Ð¼Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ‹" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "получена неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ° %(code)d от %(server)s: %(error)s" msgid "an internal error has occurred" msgstr "произошла внутреннÑÑ Ð¾ÑˆÐ¸Ð±ÐºÐ°" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "Ðеверный JSON-RPC запроÑ: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Ошибка Kerberos: %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "не получены региÑтрационные данные Kerberos" msgid "No credentials cache found" msgstr "КÑш региÑтрационных данных не найден" msgid "Ticket expired" msgstr "Срок дейÑÑ‚Ð²Ð¸Ñ Ð±Ð¸Ð»ÐµÑ‚Ð° иÑтек" msgid "Credentials cache permissions incorrect" msgstr "Права доÑтупа на кÑш региÑтрационных данных неверны" msgid "Bad format in credentials cache" msgstr "Ошибочный формат в кÑше региÑтрационных данных " msgid "Cannot resolve KDC for requested realm" msgstr "Ðе могу определить KDC Ð´Ð»Ñ Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ð¾Ð¹ облаÑти (realm)" msgid "Session error" msgstr "СеанÑÐ¾Ð²Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°" #, python-format msgid "Insufficient access: %(info)s" msgstr "ÐедоÑтаточно прав Ð´Ð»Ñ Ð´Ð¾Ñтупа: %(info)s" msgid "Passwords do not match" msgstr "Пароли не Ñовпадают" msgid "Command not implemented" msgstr "Команда пока не реализована" msgid "Client is not configured. Run ipa-client-install." msgstr "Клиент не наÑтроен. ЗапуÑтите ipa-client-install." #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Ð¢Ð°ÐºÐ°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ уже ÑущеÑтвует" msgid "You must enroll a host in order to create a host service" msgstr "" "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, чтобы Ñоздать Ñлужбу узла, необходимо Ñперва зарегиÑтрировать Ñтот " "узел" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ Ñлужбы не предÑтавлена в форме: Ñлужба/полноÑтью-определенное-" "имÑ: %(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "ОблаÑть (realm) Ð´Ð»Ñ ÑƒÑ‡ÐµÑ‚Ð½Ð¾Ð¹ запиÑи не Ñовпадает Ñ Ð¾Ð±Ð»Ð°Ñтью IPA-Ñервера" msgid "This command requires root access" msgstr "Этой команде требуютÑÑ Ð¿Ñ€Ð°Ð²Ð° админиÑтратора" msgid "This is already a posix group" msgstr "Уже ÑвлÑетÑÑ posix группой" msgid "A group may not be a member of itself" msgstr "Группа не может входить в ÑоÑтав Ñамой ÑебÑ" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Декодирование Base64 прошло Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ¾Ð¹: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "Группа не может быть добавлена Ñама в ÑебÑ" msgid "The default users group cannot be removed" msgstr "Группа по умолчанию Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ может быть удалена" msgid "Host does not have corresponding DNS A record" msgstr "Узел не имеет ÑоответÑтвующей A-запиÑи в DNS" msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "" "Удаление управлÑемой группы не разрешено. Сначала ее необходимо отключить." #, python-format msgid "Unable to create private group. A group '%(group)s' already exists." msgstr "Ðе удалоÑÑŒ Ñоздать личную группу. Группа «%(group)s» уже ÑущеÑтвует." msgid "change collided with another change" msgstr "изменение противоречит другому Ñделанному изменению" msgid "no modifications to be performed" msgstr "Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð½Ðµ внеÑены" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s: %(info)s" msgid "limits exceeded for this query" msgstr "Ð´Ð»Ñ Ñтого запроÑа превышены ограничениÑ" #, python-format msgid "%(info)s" msgstr "%(info)s" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ñ Ñертификатом не может быть завершена: %(error)s" #, python-format msgid "Certificate format error: %(error)s" msgstr "Ошибка формата Ñертификата: %(error)s" msgid "Results are truncated, try a more specific search" msgstr "Результаты уÑечены. Попробуйте задать более точные уÑÐ»Ð¾Ð²Ð¸Ñ Ð¿Ð¾Ð¸Ñка" msgid "A list of LDAP entries" msgstr "СпиÑок запиÑей LDAP" msgid "incorrect type" msgstr "неверный тип" msgid "Only one value is allowed" msgstr "ДопуÑкаетÑÑ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ одно значение" msgid "must be True or False" msgstr "должно быть либо True, либо False" msgid "must be an integer" msgstr "должно быть целое" #, python-format msgid "must be at least %(minvalue)d" msgstr "должно быть не менее %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "может быть не более %(maxvalue)d" msgid "must be a decimal number" msgstr "должно быть деÑÑтичным чиÑлом" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "должно Ñовпадать Ñ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð¾Ð¼ «%(pattern)s»" msgid "must be binary data" msgstr "должно ÑвлÑтьÑÑ Ð´Ð²Ð¾Ð¸Ñ‡Ð½Ñ‹Ð¼Ð¸ данными" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "должно Ñодержать не менее %(minlength)d байт" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "может Ñодержать не более %(maxlength)d байт" #, python-format msgid "must be exactly %(length)d bytes" msgstr "должно Ñодержать точно %(length)d байт" msgid "must be Unicode text" msgstr "должно ÑвлÑтьÑÑ Ð®Ð½Ð¸ÐºÐ¾Ð´-текÑтом" #, python-format msgid "must be at least %(minlength)d characters" msgstr "должно быть не короче %(minlength)d Ñимволов" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "может быть не длиннее %(maxlength)d Ñимволов" #, python-format msgid "must be exactly %(length)d characters" msgstr "должно быть точно %(length)d Ñимволов длинной" msgid "A list of ACI values" msgstr "СпиÑок значений ACI" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "type, filter, subtree и targetgroup ÑвлÑÑŽÑ‚ÑÑ Ð²Ð·Ð°Ð¸Ð¼Ð¾Ð¸Ñключающими" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "требуетÑÑ ÐºÐ°Ðº минимум одно из: type, filter, subtree, targetgroup, attrs или " "memberof" #, python-format msgid "Group '%s' does not exist" msgstr "Группа «%s» не ÑущеÑтвует" #, python-format msgid "Syntax Error: %(error)s" msgstr "Ошибка ÑинтакÑиÑа: %(error)s" #, python-format msgid "ACI with name \"%s\" not found" msgstr "ACI Ñ Ð¸Ð¼ÐµÐ½ÐµÐ¼ «%s» не найдена" msgid "ACI prefix" msgstr "ÐŸÑ€ÐµÑ„Ð¸ÐºÑ ACI" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "Ð˜Ð¼Ñ ACI" msgid "User group" msgstr "Группа пользователей" msgid "Permissions" msgstr "РазрешениÑ" msgid "Attributes" msgstr "Ðтрибуты" msgid "Type" msgstr "Тип" msgid "Member of" msgstr "Член" msgid "Member of a group" msgstr "Член группы" msgid "Filter" msgstr "Фильтр" msgid "Subtree" msgstr "Поддерево" msgid "Target group" msgstr "Ð¦ÐµÐ»ÐµÐ²Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "Создана ACI «%(value)s»" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "Удалена ACI «%(value)s»" msgid "ACI" msgstr "ACI" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "Изменена ACI «%(value)s»" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "Ðайдено %(count)d ACI" msgstr[1] "Ðайдено %(count)d ACI" msgstr[2] "Ðайдено %(count)d ACI" msgid "Description" msgstr "ОпиÑание" msgid "Location" msgstr "РаÑположение" msgid "Key" msgstr "Ключ" msgid "description" msgstr "опиÑание" msgid "Mount point" msgstr "Точка монтированиÑ" msgid "Password" msgstr "Пароль" msgid "Roles" msgstr "Роли" msgid "External host" msgstr "Внешний узел" msgid "entry" msgstr "запиÑÑŒ" msgid "entries" msgstr "запиÑи" msgid "Entry" msgstr "ЗапиÑÑŒ" msgid "Rights" msgstr "Права" msgid "Time Limit" msgstr "Ограничение по времени" msgid "Time limit of search in seconds" msgstr "Ограничение времени поиÑка в Ñекундах" msgid "Size Limit" msgstr "Ограничение по размеру" msgid "Failure decoding Certificate Signing Request:" msgstr "Сбой при декодировании запроÑа на Ñоздание Ñертификата:" msgid "Failure decoding Certificate Signing Request" msgstr "Сбой при декодировании запроÑа на Ñоздание Ñертификата" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "Сбой при декодировании запроÑа на Ñоздание Ñертификата: %s" msgid "CSR" msgstr "CSR" msgid "Certificate" msgstr "Сертификат" msgid "Issuer" msgstr "Издатель" msgid "Not Before" msgstr "ÐедейÑтвителен до" msgid "Not After" msgstr "ÐедейÑтвителен поÑле" msgid "Fingerprint (MD5)" msgstr "Отпечаток (MD5)" msgid "Fingerprint (SHA1)" msgstr "Отпечаток (SHA1)" msgid "Serial number" msgstr "Серийный номер" msgid "Request id" msgstr "ID запроÑа" msgid "Request status" msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð·Ð°Ð¿Ñ€Ð¾Ñа" msgid "Retrieve an existing certificate." msgstr "Получить ÑущеÑтвующий Ñертификат." msgid "Revocation reason" msgstr "Причина отзыва" msgid "Revoke a certificate." msgstr "Отозвать Ñертификат" msgid "Revoked" msgstr "Отозван" msgid "Reason" msgstr "Причина" msgid "Reason for revoking the certificate (0-10)" msgstr "Причина Ð´Ð»Ñ Ð¾Ñ‚Ð·Ñ‹Ð²Ð° Ñертификата (0-10)" msgid "Error" msgstr "Ошибка" msgid "Configuration" msgstr "ÐаÑтройка" msgid "Maximum username length" msgstr "МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð´Ð»Ð¸Ð½Ð° имени пользователÑ" msgid "Default location of home directories" msgstr "РаÑположение домашних каталогов по умолчанию" msgid "Default shell" msgstr "Оболочка по умолчанию" msgid "Default shell for new users" msgstr "Оболочка по умолчанию Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… пользователей" msgid "Default users group" msgstr "Группа пользователей по умолчанию" msgid "Default group for new users" msgstr "Группа по умолчанию Ð´Ð»Ñ Ð½Ð¾Ð²Ñ‹Ñ… пользователей" msgid "Default e-mail domain" msgstr "Почтовый домен по умолчанию" msgid "Default group objectclasses" msgstr "КлаÑÑÑ‹ объектов Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¿ по умолчанию" msgid "Default group objectclasses (comma-separated list)" msgstr "КлаÑÑÑ‹ объектов Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¿ по умолчанию (через запÑтую)" msgid "Default user objectclasses" msgstr "КлаÑÑÑ‹ объектов Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹ по умолчанию" msgid "Default user objectclasses (comma-separated list)" msgstr "КлаÑÑÑ‹ объектов Ð´Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¹ по умолчанию (через запÑтую)" msgid "Password Expiration Notification (days)" msgstr "Оповещение об иÑтечении Ð¿Ð°Ñ€Ð¾Ð»Ñ (в днÑ)" msgid "delegation" msgstr "делегирование" msgid "delegations" msgstr "делегированиÑ" msgid "Delegations" msgstr "ДелегированиÑ" msgid "Delegation" msgstr "Делегирование" msgid "invalid IP address format" msgstr "неправильный формат IP-адреÑа" msgid "invalid IP network format" msgstr "неправильный формат подÑети" #, python-format msgid "invalid domain-name: %s" msgstr "неправильное доменное имÑ: %s" #, python-format msgid "(see RFC %s for details)" msgstr "(Ñм. RFC %s Ð´Ð»Ñ Ð´ÐµÑ‚Ð°Ð»ÐµÐ¹)" #, python-format msgid "'%s' is a required part of DNS record" msgstr "\"%s\" ÑвлÑетÑÑ Ð¾Ð±Ñзательной чаÑтью DNS-запиÑи" msgid "IP Address" msgstr "IP-адреÑ" msgid "Hostname" msgstr "Ð˜Ð¼Ñ ÑƒÐ·Ð»Ð°" msgid "Algorithm" msgstr "Ðлгоритм" msgid "Certificate/CRL" msgstr "Сертификат/СОС" msgid "Protocol" msgstr "Протокол" msgid "Public Key" msgstr "Открытый ключ" msgid "Altitude" msgstr "Ð’Ñ‹Ñота над уровнем морÑ" msgid "Size" msgstr "Размер" msgid "Regular Expression" msgstr "РегулÑрное выражение" msgid "Priority" msgstr "Приоритет" msgid "Weight" msgstr "ВеÑ" msgid "Port" msgstr "Порт" msgid "the value does not follow \"YYYYMMDDHHMMSS\" time format" msgstr "значение не подходит под формат времени «ГГГГММДДЧЧММСС»" msgid "Records" msgstr "ЗапиÑи" msgid "Record type" msgstr "Тип запиÑи" #, python-format msgid "Nameserver '%(host)s' does not have a corresponding A/AAAA record" msgstr "У Ñервера имен «%(host)s» не ÑоответÑтвующей A/AAAA-запиÑи" msgid "DNS zone" msgstr "зона DNS" msgid "DNS zones" msgstr "зоны DNS" msgid "DNS Zones" msgstr "Зоны DNS" msgid "DNS Zone" msgstr "Зона DNS" msgid "Zone name" msgstr "Ð˜Ð¼Ñ Ð·Ð¾Ð½Ñ‹" msgid "Zone name (FQDN)" msgstr "Ð˜Ð¼Ñ Ð·Ð¾Ð½Ñ‹ (FQDN)" msgid "Reverse zone IP network" msgstr "Зона обратных адреÑов" msgid "SOA serial" msgstr "Ðомер SOA" msgid "Dynamic update" msgstr "ДинамичеÑкое обновление" msgid "Allow dynamic updates." msgstr "Разрешить динамичеÑкие обновлениÑ." msgid "Create new DNS zone (SOA record)." msgstr "Создать новую зону DNS (SOA-запиÑÑŒ)" msgid "Force" msgstr "Принудительно" msgid "Time to live" msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð¶Ð¸Ð·Ð½Ð¸" msgid "Class" msgstr "КлаÑÑ" msgid "Delete all?" msgstr "Удалить вÑе?" #, python-format msgid "Host '%(host)s' not found" msgstr "Узел \"%(host)s\" не найден" msgid "group" msgstr "группа" msgid "groups" msgstr "группы" msgid "User Groups" msgstr "Группы пользователей" msgid "Group name" msgstr "Ð˜Ð¼Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ñ‹" msgid "Group description" msgstr "ОпиÑание группы" msgid "GID" msgstr "ID группы" msgid "Create a new group." msgstr "Создать новую группу." #, python-format msgid "Added group \"%(value)s\"" msgstr "Добавлена группа «%(value)s»" msgid "Delete group." msgstr "Удалить группу." #, python-format msgid "Deleted group \"%(value)s\"" msgstr "Удалена группа «%(value)s»" msgid "Modify a group." msgstr "Изменить группу." #, python-format msgid "Modified group \"%(value)s\"" msgstr "Изменена группа «%(value)s»" msgid "change to a POSIX group" msgstr "изменить на группу POSIX" msgid "Search for groups." msgstr "ПоиÑк групп." #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "Ðайдена %(count)d группа" msgstr[1] "Ðайдено %(count)d группы" msgstr[2] "Ðайдено %(count)d групп" msgid "search for private groups" msgstr "поиÑк личных групп" msgid "not allowed to modify user entries" msgstr "изменение запиÑей Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð½Ðµ разрешено" msgid "not allowed to modify group entries" msgstr "изменение запиÑей группы не разрешено" msgid "Not a managed group" msgstr "Ðет управлÑемой группы" msgid "Rule name" msgstr "Ð˜Ð¼Ñ Ð¿Ñ€Ð°Ð²Ð¸Ð»Ð°" msgid "Rule type" msgstr "Тип правила" msgid "User category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" msgid "Service category" msgstr "ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Ñлужбы" msgid "Enabled" msgstr "Включено" msgid "Users" msgstr "Пользователи" msgid "Hosts" msgstr "Узлы" msgid "Host Groups" msgstr "Группы узлов" msgid "Services" msgstr "Службы" msgid "Service Groups" msgstr "Группы ÑервиÑов" msgid "Access time" msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð´Ð¾Ñтупа" msgid "Service name" msgstr "Ð˜Ð¼Ñ Ñлужбы" msgid "Warning" msgstr "Предупреждение" msgid "host" msgstr "узел" msgid "hosts" msgstr "узлы" msgid "Host" msgstr "Узел" msgid "Platform" msgstr "Платформа" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "ÐÐ¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ð°Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð° узла (например, «Lenovo T61»)" msgid "Operating system" msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема узла и ее верÑÐ¸Ñ (например, «Fedora 9»)" msgid "User password" msgstr "Пароль пользователÑ" msgid "Random password" msgstr "Случайный пароль" msgid "MAC address" msgstr "MAC-адреÑ" msgid "Hardware MAC address(es) on this host" msgstr "MAC-адреÑ(а) данного узла" msgid "Add a new host." msgstr "Добавить новый узел." #, python-format msgid "Added host \"%(value)s\"" msgstr "Добавлен узел «%(value)s»" msgid "Delete a host." msgstr "Удалить узел." #, python-format msgid "Deleted host \"%(value)s\"" msgstr "Удален узел «%(value)s»" msgid "Remove entries from DNS" msgstr "Удалить запиÑи из DNS" msgid "Modify information about a host." msgstr "Изменить информацию об узле." #, python-format msgid "Modified host \"%(value)s\"" msgstr "Изменен узел «%(value)s»" msgid "Update DNS entries" msgstr "Обновить запиÑи DNS" #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "Ðайден %(count)d узел" msgstr[1] "Ðайдено %(count)d узла" msgstr[2] "Ðайдено %(count)d узлов" msgid "host group" msgstr "группа узлов" msgid "host groups" msgstr "группы узлов" msgid "Host Group" msgstr "Группа узлов" msgid "Host-group" msgstr "Группа узлов" #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "Добавлена группа узлов «%(value)s»" #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "Удалена группа узлов «%(value)s»" #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "Изменена группа узлов «%(value)s»" #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "Ðайдена %(count)d группа узлов" msgstr[1] "Ðайдено %(count)d группы узлов" msgstr[2] "Ðайдено %(count)d групп узлов" msgid "Add" msgstr "Добавить" msgid "Add and Close" msgstr "Добавить и закрыть" msgid "Add and Edit" msgstr "Добавить и редактировать" msgid "Cancel" msgstr "Отменить" msgid "Close" msgstr "Закрыть" msgid "OK" msgstr "OK" msgid "Refresh" msgstr "Обновить" msgid "Delete" msgstr "Удалить" msgid "Reset" msgstr "СброÑить" msgid "Restore" msgstr "ВоÑÑтановить" msgid "Retry" msgstr "Получить" msgid "Revoke" msgstr "Отозвать" msgid "Set" msgstr "УÑтавновить" msgid "Update" msgstr "Обновить" msgid "Collapse All" msgstr "Свернуть вÑе" msgid "Expand All" msgstr "Развернуть вÑе" msgid "Hide details" msgstr "Скрыть детали" msgid "URL" msgstr "URL" msgid "Username" msgstr "Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ" msgid "Organization" msgstr "ОрганизациÑ" msgid "Organizational Unit" msgstr "Организационное подразделение" msgid "Reason for Revocation" msgstr "Причина отзыва" msgid "User Options" msgstr "Параметры пользователÑ" msgid "Data" msgstr "Данные" msgid "DNS Zone Settings" msgstr "ÐаÑтройки зоны DNS" msgid "Rules" msgstr "Правила" msgid "Host Certificate" msgstr "Сертификат узла" msgid "Host Name" msgstr "Ð˜Ð¼Ñ ÑƒÐ·Ð»Ð°" msgid "Kerberos Key" msgstr "Ключ Kerberos" msgid "One-Time-Password" msgstr "Одноразовый пароль" msgid "Reset OTP" msgstr "СброÑить ОРП" msgid "Reset One-Time-Password" msgstr "СброÑить одноразовый пароль" msgid "Set OTP" msgstr "УÑтановить ОРП" msgid "Set One-Time-Password" msgstr "УÑтановить одноразовый пароль" msgid "User" msgstr "Пользователь" msgid "SSH public keys" msgstr "Открытые ключи SSH" msgid "Audit" msgstr "Ðудит" msgid "DNS" msgstr "DNS" msgid "Sudo" msgstr "Sudo" msgid "Next" msgstr "Далее" msgid "Page" msgstr "Страница" msgid "Prev" msgstr "Ðазад" msgid "undo" msgstr "отменить" msgid "undo all" msgstr "отменить вÑÑ‘" msgid "Bind DN" msgstr "Bind DN" msgid "LDAP schema" msgstr "Схема LDAP" #, python-format msgid "%(count)d variables" msgstr "%(count)d переменных" #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "Загружен %(count)d подключаемый модуль" msgstr[1] "Загружено %(count)d подключаемых модулÑ" msgstr[2] "Загружено %(count)d подключаемых модулей" msgid "permission" msgstr "разрешение" msgid "permissions" msgstr "разрешениÑ" msgid "PKINIT" msgstr "PKINIT" msgid "priority cannot be set on global policy" msgstr "приоритет не может быть задан Ð´Ð»Ñ Ð³Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð¾Ð¹ политики" msgid "role" msgstr "роль" msgid "roles" msgstr "роли" msgid "Role" msgstr "Роль" #, python-format msgid "Added service \"%(value)s\"" msgstr "Добавлена Ñлужба «%(value)s»" #, python-format msgid "Deleted service \"%(value)s\"" msgstr "Удалена Ñлужба «%(value)s»" msgid "user" msgstr "пользователь" msgid "users" msgstr "пользователи" msgid "First name" msgstr "ИмÑ" msgid "Last name" msgstr "ФамилиÑ" msgid "Full name" msgstr "Полное имÑ" msgid "Display name" msgstr "Отображаемое имÑ" msgid "Initials" msgstr "Инициалы" msgid "Home directory" msgstr "Домашний каталог" msgid "Email address" msgstr "Электронный адреÑ" msgid "Prompt to set the user password" msgstr "ЗапроÑить пароль у пользователÑ" msgid "Generate a random user password" msgstr "Сгенерировать Ñлучайный пользовательÑкий пароль" msgid "UID" msgstr "UID" msgid "User ID Number (system will assign one if not provided)" msgstr "ID Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ (еÑли не указан, ÑиÑтема назначит его ÑамоÑтоÑтельно)" msgid "Group ID Number" msgstr "ID группы" msgid "Street address" msgstr "ÐдреÑ" msgid "City" msgstr "Город" msgid "State/Province" msgstr "ОблаÑть/реÑпублика" msgid "ZIP" msgstr "ИндекÑ" msgid "Telephone Number" msgstr "Телефонный номер" msgid "Mobile Telephone Number" msgstr "Мобильный телефонный номер" msgid "Pager Number" msgstr "Ðомер пейджера" msgid "Fax Number" msgstr "Ðомер факÑа" msgid "Org. Unit" msgstr "Отдел" msgid "Job Title" msgstr "ДолжноÑть" msgid "Manager" msgstr "Руководитель" msgid "Car License" msgstr "Ðомер автомобилÑ" msgid "Account disabled" msgstr "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ отключена" #, python-format msgid "manager %(manager)s not found" msgstr "руководитель %(manager)s не найден" msgid "Add a new user." msgstr "Добавить нового пользователÑ." #, python-format msgid "Added user \"%(value)s\"" msgstr "Добавлен пользователь «%(value)s»" msgid "Don't create user private group" msgstr "Ðевозможно Ñоздать ÑобÑтвенную группу пользователÑ" msgid "Delete a user." msgstr "Удалить пользователÑ." #, python-format msgid "Deleted user \"%(value)s\"" msgstr "Удален пользователь «%(value)s»" msgid "Modify a user." msgstr "Изменить пользователÑ." #, python-format msgid "Modified user \"%(value)s\"" msgstr "Изменен пользователь «%(value)s»" msgid "Search for users." msgstr "ПоиÑк пользователей." #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "Ðайден %(count)d пользователь" msgstr[1] "Ðайдено %(count)d пользователÑ" msgstr[2] "Ðайдено %(count)d пользователей" msgid "Disable a user account." msgstr "Отключить учетную запиÑÑŒ пользователÑ." #, python-format msgid "Disabled user account \"%(value)s\"" msgstr "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Â«%(value)s» отключена" msgid "Enable a user account." msgstr "Включить учетную запиÑÑŒ пользователÑ." #, python-format msgid "Enabled user account \"%(value)s\"" msgstr "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Â«%(value)s» включена" #, python-format msgid "Unlocked account \"%(value)s\"" msgstr "Ð£Ñ‡ÐµÑ‚Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ «%(value)s» разблокирована" msgid "too many '@' characters" msgstr "Ñлишком много Ñимволов @" msgid "invalid SSH public key" msgstr "неверный открытый ключ SSH" #, python-format msgid "objectclass %s not found" msgstr "клаÑÑ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¾Ð² %s не найден" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "Ðевозможно ÑвÑзатьÑÑ Ñ CMS (%s)" msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "ÐÐ¿Ð¿Ð°Ñ€Ð°Ñ‚Ð½Ð°Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð° узла (например, Lenovo T61)" msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема и верÑÐ¸Ñ ÑƒÐ·Ð»Ð° (например, Fedora 9)" #, c-format msgid "cannot open configuration file %s\n" msgstr "невозможно открыть конфигурационный файл %s\n" msgid "LDAP DN" msgstr "LDAP DN" msgid "LDAP password" msgstr "Пароль LDAP" msgid "hostname" msgstr "Ð˜Ð¼Ñ ÑƒÐ·Ð»Ð°" msgid "LDAP basedn" msgstr "LDAP basedn" msgid "basedn" msgstr "basedn" #, c-format msgid "kvno %d\n" msgstr "kvno %d\n" freeipa-3.3.4/install/po/es.po0000664000175000017500000040711712271663206015554 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Adolfo Jayme Barrientos , 2013 # Eduardo Villagrán M , 2012 # vareli , 2013 # Gladys Guerrero , 2011 # Daniel Cabrera , 2011 # Hugo Jiménez Hernández , 2011 # jdennis , 2011 # Petr Viktorin , 2012 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-09-20 06:46+0000\n" "Last-Translator: Adolfo Jayme Barrientos \n" "Language-Team: Spanish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: es\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Ingrese %(label)s nuevamente para verificar: " #, c-format msgid "Passwords do not match!" msgstr "¡Las contraseñas no coinciden!" msgid "Topic commands:" msgstr "Tema comandos:" msgid "Command name" msgstr "Nombre del comando" msgid "Positional arguments" msgstr "Argumentos posicionales" msgid "No file to read" msgstr "No existe el fichero para leer" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "error %(code)d desconocido de %(server)s: %(error)s" msgid "an internal error has occurred" msgstr "ha ocurrido un error interno" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "Petición JSON-RPC no válida: %(error)s" #, python-format msgid "error marshalling data for XML-RPC transport: %(error)s" msgstr "error de clasificación para el transporte de datos XML-RPC: %(error)s " #, python-format msgid "Missing or invalid HTTP Referer, %(referer)s" msgstr "Arbitro HTTP desaparecido o no válido, %(referer)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Error de kerberos: %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "no se ha recibido ninguna credencial de Kerberos" msgid "No credentials cache found" msgstr "No se han encontrado credenciales de cache" msgid "Ticket expired" msgstr "El ticket ha expirado" msgid "Credentials cache permissions incorrect" msgstr "Los permisos de credenciales de caché son incorrectos" msgid "Bad format in credentials cache" msgstr "Las credenciales de caché están mal formadas" msgid "Cannot resolve KDC for requested realm" msgstr "No es posible resolver KDC para el reinado solicitado" msgid "Session error" msgstr "Error de sesión" #, python-format msgid "Insufficient access: %(info)s" msgstr "Acceso insuficiente: %(info)s" msgid "Passwords do not match" msgstr "Las contraseñas no coinciden" msgid "Command not implemented" msgstr "El comando no se ha implementado" msgid "Client is not configured. Run ipa-client-install." msgstr "El cliente no está configurado. Ejecutar la API de cliente a instalar." #, python-format msgid "Could not get %(name)s interactively" msgstr "No se pudo obtener %(name)s interactivamente" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Esta entrada ya existe" msgid "You must enroll a host in order to create a host service" msgstr "Debe registrar el equipo para poder generar un servicio de host" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "El servicio principal no tiene la forma de servicio/nombre de equipo " "totalmente calificado: %(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "" "El reinado para el principal no coincide con el reinado para este servidor " "IPA" msgid "This command requires root access" msgstr "Este comando necesita acceso de usuario root" msgid "This is already a posix group" msgstr "Este ya es un grupo posix" msgid "This entry is already enabled" msgstr "Esta entrada ya está habilitada" msgid "This entry is already disabled" msgstr "Esta entrada ya está desactivada" msgid "This entry cannot be enabled or disabled" msgstr "Esta entrada no puede ser activada o desactivada" msgid "This entry is not a member" msgstr "Esta entrada no es miembro" msgid "A group may not be a member of itself" msgstr "Un grupo no puede ser miembro de sí mismo" msgid "This entry is already a member" msgstr "Esta entrada ya es un miembro" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Falló la decodificación base64: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "Un grupo no puede ser agregado como miembro de sí mismo" msgid "The default users group cannot be removed" msgstr "El grupo de usuarios predeterminado no puede ser eliminado" msgid "Host does not have corresponding DNS A record" msgstr "El equipo no posee un registro DNS A con el que se corresponda " msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "" "No se permite eliminar un grupo administrado. Primero debe ser desasociado. " msgid "A managed group cannot have a password policy." msgstr "Un grupo administrado no puede tener una política de contraseñas." #, python-format msgid "'%(entry)s' doesn't have a certificate." msgstr "'%(entry)s' no tiene certificado" #, python-format msgid "Unable to create private group. A group '%(group)s' already exists." msgstr "No se puede crear un grupo privado. Un grupo de '%(group)s' ya existe." #, python-format msgid "" "A problem was encountered when verifying that all members were %(verb)s: " "%(exc)s" msgstr "" "Se encontró un problema al verificar si todos los miembros eran %(verb)s: " "%(exc)s" #, python-format msgid "%(attr)s does not contain '%(value)s'" msgstr "%(attr)s no contiene '%(value)s'" #, python-format msgid "" "The search criteria was not specific enough. Expected 1 and found %(found)d." msgstr "" "El criterio de búsqueda no fue bastante específico. Se esperaba 1 y se " "encontró %(found)d." msgid "change collided with another change" msgstr "la modificación choca con otra modificación diferente" msgid "no modifications to be performed" msgstr "no existen modificaciones a ser realizadas" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s:%(info)s" msgid "limits exceeded for this query" msgstr "han sido excedidos los límites para esta consulta" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "modifying primary key is not allowed" msgstr "modificar la clave principal no está permitido" #, python-format msgid "%(attr)s: Only one value allowed." msgstr " %(attr)s : Solamente un valor permitido." #, python-format msgid "%(attr)s: Invalid syntax." msgstr "%(attr)s: sintaxis inválida." #, python-format msgid "Bad search filter %(info)s" msgstr "%(info)s de filtro de búsqueda errado" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "La operación certificada no puede ser completada: %(error)s" #, python-format msgid "Certificate format error: %(error)s" msgstr "Error de certificado de formato: %(error)s " msgid "Already registered" msgstr "Ya está registrado" msgid "Not registered yet" msgstr "Aún no está registrado" msgid "Results are truncated, try a more specific search" msgstr "" "Los resultados se encuentran truncados, intente realizar una búsqueda más " "específica" msgid "" "Retrieve and print all attributes from the server. Affects command output." msgstr "" "Recuperar e imprimir todos los atributos del servidor. Afecta a la salida " "del comando." msgid "Print entries as stored on the server. Only affects output format." msgstr "" "Imprimir entradas como almacenadas en el servidor. Solamente afecta formato " "de salida." msgid "Client version. Used to determine if server will accept request." msgstr "" "Versión de cliente. Se utiliza para determinar si el servidor va a aceptar " "la solicitud." msgid "Forward to server instead of running locally" msgstr "Reenvía al servidor en lugar de ejecutarse localmente" msgid "A dictionary representing an LDAP entry" msgstr "Un diccionario representando una entrada LDAP" msgid "A list of LDAP entries" msgstr "Una lista de entradas LDAP" msgid "All commands should at least have a result" msgstr "Todos los comandos deberían por lo menos tener un resultado" msgid "Number of entries returned" msgstr "Cantidad de entradas devueltas" msgid "List of deletions that failed" msgstr "Lista de eliminaciones fallidas" msgid "True means the operation was successful" msgstr "«Verdadero» significa que la operación fue exitosa" msgid "incorrect type" msgstr "tipo incorrecto" msgid "Only one value is allowed" msgstr "Sólo se permite un valor" msgid "must be True or False" msgstr "debe ser True o False" msgid "must be an integer" msgstr "debe ser un entero" #, python-format msgid "must be at least %(minvalue)d" msgstr "debe ser como mínimo %(minvalue)d" #, python-format msgid "can be at most %(maxvalue)d" msgstr "puede ser como máximo %(maxvalue)d" msgid "must be a decimal number" msgstr "debe ser un número decimal" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "debe coincidir con el modelo \"%(pattern)s" msgid "must be binary data" msgstr "debe ser un dato binario" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "debe ser como mínimo de %(minlength)d bytes" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "puede ser a lo sumo de %(maxlength)d bytes" #, python-format msgid "must be exactly %(length)d bytes" msgstr "debe ser exactamente de %(length)d bytes" msgid "must be Unicode text" msgstr "debe ser texto Unicode" msgid "Leading and trailing spaces are not allowed" msgstr "No están permitidos espacios iniciales ni finales" #, python-format msgid "must be at least %(minlength)d characters" msgstr "debe tener como mínimo %(minlength)d caracteres" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "puede tener a lo sumo %(maxlength)d caracteres" #, python-format msgid "must be exactly %(length)d characters" msgstr "debe tener exactamente %(length)d caracteres" msgid "A list of ACI values" msgstr "Una lista de valores ACI" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "tipo, filtro, subárbol y grupo de destino, se excluyen mutuamente" msgid "ACI prefix is required" msgstr "Se requiere prefijo de ACI " msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "es necesario como mínimo alguno de: tipo, filtro, subárbol, grupo de " "destino, atributos, o miembro de " msgid "filter and memberof are mutually exclusive" msgstr "filtro y memberof son mutuamente excluyentes" msgid "group, permission and self are mutually exclusive" msgstr "grupo, permisos y auto son mutuamente excluyentes" msgid "One of group, permission or self is required" msgstr "Uno de grupo, permiso o self es necesario" #, python-format msgid "Group '%s' does not exist" msgstr "El grupo '%s' no existe" msgid "empty filter" msgstr "Vaciar filtro" #, python-format msgid "Syntax Error: %(error)s" msgstr "Error de sintaxis:%(error)s " #, python-format msgid "ACI with name \"%s\" not found" msgstr "No se encuentra un ACI cuyo nombre sea \"%s\"" msgid "ACI prefix" msgstr "Prefijo ACI" msgid "" "Prefix used to distinguish ACI types (permission, delegation, selfservice, " "none)" msgstr "" "Prefijo utilizado para distinguir los tipos de ACI (permiso,delegación, " "autoservicio, ninguno)" msgid "ACIs" msgstr "ACI" msgid "ACI name" msgstr "Nombre de ACI" msgid "Permission" msgstr "Permiso" msgid "Permission ACI grants access to" msgstr "El permiso ACI permite el acceso a" msgid "User group" msgstr "Grupo de usuarios" msgid "User group ACI grants access to" msgstr "El grupo de usuarios ACI permite el acceso a" msgid "Permissions" msgstr "Permisos" msgid "Attributes" msgstr "Atributos" msgid "Type" msgstr "Tipo" msgid "type of IPA object (user, group, host, hostgroup, service, netgroup)" msgstr "" "Objeto de tipo IPA (usuario, grupo, grupo de host, servicio, grupo de red)" msgid "Member of" msgstr "Miembro de" msgid "Member of a group" msgstr "Miembro de un grupo" msgid "Filter" msgstr "Filtro" msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "Filtro legal LDAP (p.ej. ou=Ingeniería)" msgid "Subtree" msgstr "Subárbol" msgid "Subtree to apply ACI to" msgstr "Subárbol al que aplicar ACI" msgid "Target group" msgstr "Grupo elegido" msgid "Group to apply ACI to" msgstr "Grupo al que aplicar API" msgid "Target your own entry (self)" msgstr "Dirija su propia entrada (usted)" msgid "Apply ACI to your own entry (self)" msgstr "Aplique ACI a su propia entrada (usted)" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "Ha sido creado ACI \"%(value)s\"" msgid "Test the ACI syntax but don't write anything" msgstr "Probar la sintaxis pero no escribir nada" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "Ha sido eliminado ACI \"%(value)s\"" msgid "ACI" msgstr "ACI" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "Ha sido modificado ACI \"%(value)s\"" #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "%(count)d ACI coincidente" msgstr[1] "%(count)d ACIs coincidentes" msgid "New ACI name" msgstr " Nuevo nombre de ACI" #, python-format msgid "Renamed ACI to \"%(value)s\"" msgstr "ACI renombrado a \"%(value)s\"" msgid "Inclusive Regex" msgstr "Regex inclusivo" msgid "Exclusive Regex" msgstr "Regex exclusivo" msgid "Attribute Key" msgstr "Atributo Clave" msgid "" "Attribute to filter via regex. For example fqdn for a host, or manager for a " "user" msgstr "" "Atributo a filtrar por medio de regex. Por ejemplo fqdn para un host o " "gestor para un usuario" msgid "Grouping Type" msgstr "Tipo de Agrupamiento" msgid "Grouping to which the rule applies" msgstr "Agrupamiento al cual se aplican las reglas" msgid "Automember Rule" msgstr "Regla Automiembro" msgid "Auto Membership Rule" msgstr "Regla Auto Afiliación" msgid "Description" msgstr "Descripción" msgid "A description of this auto member rule" msgstr "Una descripción de esta regla auto miembro" #, python-format msgid "Group: %s not found!" msgstr "Grupo: %s no encontrado!" #, python-format msgid "%s is not a valid attribute." msgstr "%s no es un atributo válido." msgid "" "\n" " Add an automember rule.\n" " " msgstr "" "\n" " Añadir una regla automiembro.\n" " " #, python-format msgid "Added automember rule \"%(value)s\"" msgstr "Regla automiembro añadida \"%(value)s\"" msgid "Auto Membership is not configured" msgstr "Auto Afiliación no está configurada" msgid "" "\n" " Add conditions to an automember rule.\n" " " msgstr "" "\n" " Añadir condiciones a una regla automiembro.\n" " " msgid "Failed to add" msgstr "Fallo al añadir" #, python-format msgid "Added condition(s) to \"%(value)s\"" msgstr "Añadida condición(es) a \"%(value)s\"" msgid "Conditions that could not be added" msgstr "Condiciones que no pueden ser agregadas" msgid "Number of conditions added" msgstr "Número de condiciones agregadas" #, python-format msgid "Auto member rule: %s not found!" msgstr "Regla auto miembro: %s no encontrada!" msgid "" "\n" " Override this so we can add completed and failed to the return " "result.\n" " " msgstr "" "\n" " Anula esto de modo que podamos añadir completados y fallados al " "resultado devuelto.\n" " " msgid "" "\n" " Remove conditions from an automember rule.\n" " " msgstr "" "\n" " Borrar condiciones de una regla automiembro.\n" " " msgid "Conditions that could not be removed" msgstr "Condiciones que no pueden ser eliminadas" msgid "Number of conditions removed" msgstr "Número de condiciones eliminadas" msgid "" "\n" " Override this so we can set completed and failed.\n" " " msgstr "" "\n" " Anula esto de modo que podamos fijar completados y fallados.\n" " " msgid "" "\n" " Modify an automember rule.\n" " " msgstr "" "\n" " Modificar una regla automiembro.\n" " " #, python-format msgid "Modified automember rule \"%(value)s\"" msgstr "Modificada regla de automiembro \"%(value)s\"" msgid "" "\n" " Delete an automember rule.\n" " " msgstr "" "\n" " Borra una regla automiembro.\n" " " #, python-format msgid "Deleted automember rule \"%(value)s\"" msgstr "Borrada regla automiembro \"%(value)s\"" msgid "" "\n" " Search for automember rules.\n" " " msgstr "" "\n" " Búsqueda reglas automiembro.\n" " " #, python-format msgid "%(count)d rules matched" msgid_plural "%(count)d rules matched" msgstr[0] "%(count)d reglas coincidentes" msgstr[1] "%(count)d reglas coincidentes" msgid "" "\n" " Display information about an automember rule.\n" " " msgstr "" "\n" " Muestra información sobre una regla automiembro.\n" " " msgid "automount location" msgstr "localización automontaje" msgid "automount locations" msgstr "localizaciones de automontaje" msgid "Automount Locations" msgstr "Ubicaciones de automontado" msgid "Automount Location" msgstr "Localización de Automontaje" msgid "Location" msgstr "Ubicación" msgid "Automount location name." msgstr "Nombre de la ubicación de montaje automático." msgid "Create a new automount location." msgstr "Crear una nueva localización de automontaje." #, python-format msgid "Added automount location \"%(value)s\"" msgstr "Añadida localización de automontaje \"%(value)s\"" msgid "Delete an automount location." msgstr "Borrar una localización de automontaje." #, python-format msgid "Deleted automount location \"%(value)s\"" msgstr "Borrada una localización de automontaje \"%(value)s\"" msgid "Display an automount location." msgstr "Mostrar una localización de automontaje" msgid "Search for an automount location." msgstr "Buscar una localización de automontaje." #, python-format msgid "%(count)d automount location matched" msgid_plural "%(count)d automount locations matched" msgstr[0] "%(count)d localización de automontaje coincidente" msgstr[1] "%(count)d localizaciones de automontaje coincidentes" msgid "Generate automount files for a specific location." msgstr "Generar ficheros de automontaje para una localización específica." msgid "Import automount files for a specific location." msgstr "Importar ficheros de automontaje para una localización específica." msgid "Master file" msgstr " Archivo maestro" msgid "Automount master file." msgstr " Archivo maestro automount." msgid "" "Continuous operation mode. Errors are reported but the process continues." msgstr "" " Modo de funcionamiento continuo. Reporta los errores, pero el proceso " "continúa." #, python-format msgid "File %(file)s not found" msgstr "No se encontró el archivo %(file)s " msgid "automount map" msgstr "mapa de automontaje" msgid "automount maps" msgstr "mapas de automontaje" msgid "Map" msgstr "Mapa" msgid "Automount map name." msgstr " Nombre del mapa automount." msgid "Automount Maps" msgstr "Mapas de montaje automático" msgid "Automount Map" msgstr "Mapa de Automontaje" msgid "Create a new automount map." msgstr "Crear un nuevo mapa de automontaje" #, python-format msgid "Added automount map \"%(value)s\"" msgstr "Añadido mapa de automontaje \"%(value)s\"" msgid "Delete an automount map." msgstr "Borrar un mapa de automontaje." #, python-format msgid "Deleted automount map \"%(value)s\"" msgstr "Borrado un mapa de automontaje \"%(value)s\"" msgid "Modify an automount map." msgstr "Modificar un mapa de automontaje" #, python-format msgid "Modified automount map \"%(value)s\"" msgstr "Modificado un mapa de automontaje \"%(value)s\"" msgid "Search for an automount map." msgstr "Buscar un mapa de automontaje." #, python-format msgid "%(count)d automount map matched" msgid_plural "%(count)d automount maps matched" msgstr[0] "%(count)d mapa de automontaje coincidente" msgstr[1] "%(count)d mapas de automontaje coincidentes" msgid "Display an automount map." msgstr "Mostrar un mapa de automontaje" msgid "Automount key object." msgstr "Objeto clave de automontaje" msgid "automount key" msgstr "clave de automontaje" msgid "automount keys" msgstr "claves de automontaje" msgid "Key" msgstr "Llave" msgid "Automount key name." msgstr " Nombre de clave de montaje automático" msgid "Mount information" msgstr "Información de montaje" msgid "description" msgstr "descripción" msgid "Automount Keys" msgstr "Llaves de montaje automático" msgid "Automount Key" msgstr "Clave de Automontaje" #, python-format msgid "" "The key,info pair must be unique. A key named %(key)s with info %(info)s " "already exists" msgstr "" "El par de claves, la información debe ser único. Un nombre clave %(key)s " "con información %(info)s ya existe" #, python-format msgid "key named %(key)s already exists" msgstr "ya existe una llave denominada %(key)s" #, python-format msgid "The automount key %(key)s with info %(info)s does not exist" msgstr "La clave de montaje automático %(key)s con info %(info)s no existe" #, python-format msgid "" "More than one entry with key %(key)s found, use --info to select specific " "entry." msgstr "" "Se ha encontrado más de una entrada con la llave %(key)s, utilice --info " "para seleccionar una entrada específica." msgid "Create a new automount key." msgstr "Crear una nueva clave de automontaje." #, python-format msgid "Added automount key \"%(value)s\"" msgstr "Añadida clave de automontaje \"%(value)s\"" msgid "Create a new indirect mount point." msgstr "Crear un nuevo punto de montaje indirecto." #, python-format msgid "Added automount indirect map \"%(value)s\"" msgstr "Añadido mapa de automontaje indirecto \"%(value)s\"" msgid "Mount point" msgstr "Punto de montaje" msgid "Parent map" msgstr "Mapa del padre" msgid "Name of parent automount map (default: auto.master)." msgstr "" "Nombre del mapa de montaje automático de padre (por defecto: auto.master)." msgid "Delete an automount key." msgstr "Borrar una clave de automontaje." #, python-format msgid "Deleted automount key \"%(value)s\"" msgstr "Borrada clave de automontaje \"%(value)s\"" msgid "Modify an automount key." msgstr "Modificar una clave de automontaje." #, python-format msgid "Modified automount key \"%(value)s\"" msgstr "Modificada clave de automontaje \"%(value)s\"" msgid "New mount information" msgstr "Nueva información de montaje" msgid "Search for an automount key." msgstr "Buscar una clave de automontaje." #, python-format msgid "%(count)d automount key matched" msgid_plural "%(count)d automount keys matched" msgstr[0] "%(count)d clave de automontaje coincidente" msgstr[1] "%(count)d claves de automontaje coincidentes" msgid "Display an automount key." msgstr "Mostrar una clave de automontaje." msgid "Password" msgstr "Contraseña" msgid "Failed members" msgstr "Miembros fallidos" msgid "Member users" msgstr "Usuarios miembros" msgid "Member groups" msgstr "Grupos de miembros" msgid "Member of groups" msgstr "Miembros de los grupos" msgid "Member hosts" msgstr "Equipos miembro" msgid "Member host-groups" msgstr "Grupos de equipo miembro" msgid "Member of host-groups" msgstr "Miembro de los grupos de equipo" msgid "Roles" msgstr " Roles" msgid "Sudo Command Groups" msgstr "Grupos de comando sudo" msgid "Granting privilege to roles" msgstr "Concesión de privilegios a los roles" msgid "Member netgroups" msgstr " Miembros de netgroups" msgid "Member of netgroups" msgstr "Miembros de netgroups" msgid "Member services" msgstr "Servicios de miembros" msgid "Member service groups" msgstr "" "\\n\n" "Servicios\\n\n" "\\n\n" "Un servicio IPA representa un servicio que se ejecuta en un host. El " "registro del servicio IPA\\n\n" "puede almacenar la principal de kerberos, un certificado SSL, o ambos.\\n\n" "\\n\n" "Un servicio IPA puede administrarse directamente desde una máquina, siempre " "y cuando\\n\n" "la máquina tenga el permiso correcto. Esto es cierto, incluso para\\n\n" "máquinas que no están asociadas con el servicio. Por ejemplo,\\n\n" "solicitando un certificado SSL mediante credenciales principales de servicio " "de host.\\n\n" "Para administrar un servicio mediante credenciales de host necesita\\n\n" "ejecutar kinit como el host:\\n\n" "\\n\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\\n\n" "\\n\n" "Añadir un servicio IPA le permite al servicio asociado solicitar un " "certificado o una tabla de claves\\n\n" "SSL, pero esto se realiza como un paso independiente; no se producen como" "\\n\n" "como resultado de añadir un servicio\\n\n" "Solamente el aspecto público de un certificado es almacenado en un registro " "de servicio;\\n\n" "la clave privada no es almacenada.\\n\n" "\\n\n" "EJEMPLOS:\\n\n" "\\n\n" " Añadir un nuevo servicio IPA:\\n\n" " ipa service-add HTTP/web.example.com\\n\n" "\\n\n" " Permitir a un host administrar un certificado de servicio IPA:\\n\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\\n\n" " ipa role-add-member --hosts=web.example.com certadmin\\n\n" "\\n\n" " Borra un servicio IPA:\\n\n" " ipa service-del HTTP/web.example.com\\n\n" "\\n\n" " Buscar todos los servicio IPA asociados con un host:\\n\n" " ipa service-find web.example.com\\n\n" "\\n\n" " Buscar todos los servicios HTTP:\\n\n" " ipa service-find HTTP\\n\n" "\\n\n" " Desactivar la clave del servicio de kerberos y certificado SSL:\\n\n" " ipa service-disable HTTP/web.example.com\\n\n" "\\n\n" " Solicitar un certificado para un servicio IPA:\\n\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\\n\n" "\\n\n" " Generar y recuperar una tabla de claves para un servicio IPA:\\n\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\\n\n" "\\n" msgid "Member HBAC service" msgstr "Miembro del servicio HBAC" msgid "Member HBAC service groups" msgstr "Grupos de servicio de Miembros HBAC" msgid "Indirect Member users" msgstr "Usuarios indirectos miembros" msgid "Indirect Member groups" msgstr "Grupos de miembros indirectos" msgid "Indirect Member hosts" msgstr "Hosts de miembros indirectos" msgid "Indirect Member host-groups" msgstr "Miembros indirectos de host-groups" msgid "Indirect Member of roles" msgstr "Roles de miembros indirectos" msgid "Indirect Member permissions" msgstr "" "\\n\n" "Permisos indirectos de miembro " msgid "Indirect Member HBAC service" msgstr "Servicio HBAC de miembro indirecto" msgid "Indirect Member HBAC service group" msgstr "Grupo de servicio HBAC de miembros indirectos " msgid "Indirect Member netgroups" msgstr "Miembros indirectos netgroups" msgid "Failed source hosts/hostgroups" msgstr "Fallada fuente hosts/grupos de hosts" msgid "Failed hosts/hostgroups" msgstr "Falló host/hostgroups" msgid "Failed users/groups" msgstr "Falló usuarios/grupos" msgid "Failed service/service groups" msgstr "Fallado servicio/servicio grupos" msgid "Failed to remove" msgstr "No se ha podido quitar" msgid "External host" msgstr "Equipo externo" msgid "entry" msgstr "entrada" msgid "entries" msgstr "entradas" msgid "Entry" msgstr "Entrada" #, python-format msgid "container entry (%(container)s) not found" msgstr "no se encuentra la entrada (%(container)s) de contenedor" #, python-format msgid "%(parent)s: %(oname)s not found" msgstr "%(parent)s: no se encuentra %(oname)s" #, python-format msgid "%(pkey)s: %(oname)s not found" msgstr "%(pkey)s: no se encuentra %(oname)s" #, python-format msgid "%(oname)s with name \"%(pkey)s\" already exists" msgstr " %(oname)s con el nombre \"%(pkey)s\" ya existe" msgid "" "Set an attribute to a name/value pair. Format is attr=value.\n" "For multi-valued attributes, the command replaces the values already present." msgstr "" "Establecer un atributo a un par nombre y valor. El formato es attr=value. \n" "Para los atributos de valor múltiple, el comando sustituye los valores ya " "presentes." msgid "" "Add an attribute/value pair. Format is attr=value. The attribute\n" "must be part of the schema." msgstr "" "Añadir un par atributo/valor. El formato es attr=value. El atributo debe ser " "parte del esquema." msgid "" "Delete an attribute/value pair. The option will be evaluated\n" "last, after all sets and adds." msgstr "" "Borrar un par atributo/valor. La opción será evaluada al final, después de " "todos los ajustes y añadidos." msgid "Continuous mode: Don't stop on errors." msgstr "Modo continuo: No se detenga en los errores." msgid "Rights" msgstr "Derechos" msgid "" "Display the access rights of this entry (requires --all). See ipa man page " "for details." msgstr "" "Mostrar los derechos de acceso de esta entrada (requiere --all). Consulte la " "página man de IPA para más detalles." msgid "Rename" msgstr "Cambiar el nombre de" #, python-format msgid "Rename the %(ldap_obj_name)s object" msgstr "Cambie el nombre del %(ldap_obj_name)s objeto" msgid "the entry was deleted while being modified" msgstr "la entrada fue eliminada mientras estaba siendo modificada" #, python-format msgid "member %s" msgstr "miembro %s" msgid "Members that could not be added" msgstr "Miembros que no han podido ser añadidos" msgid "Number of members added" msgstr "Cantidad de miembros añadidos" msgid "Members that could not be removed" msgstr "Miembros que no han podido ser eliminados" msgid "Number of members removed" msgstr "Cantidad de miembros eliminados" msgid "Primary key only" msgstr "Sólo clave primaria" #, python-format msgid "Results should contain primary key attribute only (\"%s\")" msgstr "" "Los resultados deberían contener sólo atributo de clave primaria (“%sâ€)" msgid "Time Limit" msgstr "Tiempo límite" msgid "Time limit of search in seconds" msgstr "Tiempo máximo de búsqueda en segundos" msgid "Size Limit" msgstr "Tamaño límite" msgid "Maximum number of entries returned" msgstr "Cantidad máxima de entradas obtenidas" msgid "Nested Methods to execute" msgstr "Métodos anidados para ejecutar" msgid "Failure decoding Certificate Signing Request:" msgstr "" "Falla al intentar decodificar la petición de identificación de certificado" msgid "Failure decoding Certificate Signing Request" msgstr "" "Falla al intentar decodificar la petición de identificación de certificado" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "" "Falla al intentar decodificar la petición de identificación de certificado: " "%s" msgid "Submit a certificate signing request." msgstr "Enviar una petición de firma de certificado." msgid "CSR" msgstr "CSR" msgid "Principal" msgstr "Principal" msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "" "Principal del servicio para este certificado (p.ej. HTTP/prueba.ejemplo.com)" msgid "automatically add the principal if it doesn't exist" msgstr "si no existe, agregar automáticamente el principal" msgid "Certificate" msgstr "Certificado" msgid "Subject" msgstr "Asunto" msgid "Issuer" msgstr "Emisor" msgid "Not Before" msgstr "No antes de" msgid "Not After" msgstr "No luego de" msgid "Fingerprint (MD5)" msgstr "Huella digital (MD5)" msgid "Fingerprint (SHA1)" msgstr "Huella digital (SHA1)" msgid "Serial number" msgstr "Número de serie" msgid "Dictionary mapping variable name to value" msgstr "Nombre de la variable de mapeo de dicionario a valorizar " msgid "Check the status of a certificate signing request." msgstr "Verificar el estado de una solicitud de firma de certificado." msgid "Request id" msgstr "Id de la petición" msgid "Request status" msgstr "Estado de la petición" msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "Número de serie en decimales, o hexadecimales, si tiene un prefijo 0x" msgid "Retrieve an existing certificate." msgstr "Recuperar un certificado existente." msgid "Revocation reason" msgstr "Motivo de la revocación" msgid "Output filename" msgstr "Nombre de archivo de salida" msgid "File to store the certificate in." msgstr "Archivo para almacenar el certificado" msgid "Revoke a certificate." msgstr "Revocar un certificado." msgid "Revoked" msgstr "Revocado" msgid "Reason" msgstr "Motivo" msgid "Reason for revoking the certificate (0-10)" msgstr "Motivo por el cual el certificado ha sido revocado (0-10)" msgid "7 is not a valid revocation reason" msgstr "7 no es una razón válida de revocación" msgid "Take a revoked certificate off hold." msgstr "Tomar un certificado revocado de espera." msgid "Unrevoked" msgstr "No revocado" msgid "Error" msgstr "Error" msgid "Status" msgstr "Estatus" msgid "searchtimelimit must be -1 or > 1." msgstr "searchtimelimit debe ser -1 o> 1." msgid "configuration options" msgstr "opciones de configuración" msgid "Configuration" msgstr "Configuración" msgid "Maximum username length" msgstr "Largo máximo para nombre de usuario" msgid "Home directory base" msgstr "Base del directorio principal" msgid "Default location of home directories" msgstr "Localización por defecto de los directorios home" msgid "Default shell" msgstr "Shell predeterminada" msgid "Default shell for new users" msgstr "Shell predeterminada para usuarios nuevos" msgid "Default users group" msgstr "Grupo de usuarios predeterminado" msgid "Default group for new users" msgstr "Grupo predeterminado para usuarios nuevos" msgid "Default e-mail domain" msgstr "Dominio de correo electrónico por defecto" msgid "Search time limit" msgstr "Buscar límite de tiempo" msgid "" "Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)" msgstr "" "Máxima cantidad de tiempo (segundos) parab una búsqueda (> 0, o -1 para " "ilimitado)" msgid "Search size limit" msgstr "Límite del tamaño de la búsqueda" msgid "Maximum number of records to search (-1 is unlimited)" msgstr "Máximo número de registros a buscar (-1 es ilimitado)" msgid "User search fields" msgstr "Campos de búsqueda de usuario" msgid "A comma-separated list of fields to search in when searching for users" msgstr "" "Una lista separada por comas de los campos a buscar cuando se está buscando " "usuarios" msgid "A comma-separated list of fields to search in when searching for groups" msgstr "" "Una lista separada por comas de los campos a buscar cuando se está buscando " "grupos" msgid "Enable migration mode" msgstr "Habilitar modo migración" msgid "Certificate Subject base" msgstr "Base de certificado de asunto" msgid "Base for certificate subjects (OU=Test,O=Example)" msgstr "Base para sujetos certificados (OU=Prueba,O=Ejemplo)" msgid "Default group objectclasses" msgstr "Grupo predeterminado objectclass" msgid "Default group objectclasses (comma-separated list)" msgstr "Clases de objeto grupo por defecto (lista separada por comas)" msgid "Default user objectclasses" msgstr "Usuario predeterminado objectclasses" msgid "Default user objectclasses (comma-separated list)" msgstr "Clases de objeto usuario por defecto (lista separada por comas)" msgid "Password Expiration Notification (days)" msgstr "Notificación de Expiración de Contraseña (días)" msgid "Number of days's notice of impending password expiration" msgstr "Aviso de número de días de expiración inminente de contraseña" msgid "Password plugin features" msgstr "Funciones del complemento de contraseña" msgid "Extra hashes to generate in password plug-in" msgstr "Hashes extra para generar en el plugin de contraseña" msgid "Modify configuration options." msgstr "Modificar opciones de configuración." msgid "The group doesn't exist" msgstr "El grupo no existe" #, python-format msgid "attribute \"%s\" not allowed" msgstr "atributo \"%s\" no permitido" msgid "May not be empty" msgstr "Puede no estar vacío" msgid "Show the current configuration." msgstr "Muestra la configuración actual" msgid "delegation" msgstr "delegación" msgid "delegations" msgstr "delegaciones" msgid "Delegations" msgstr "Delegaciones" msgid "Delegation" msgstr "Delegación" msgid "Delegation name" msgstr "Nombre de delegación" msgid "Member user group" msgstr "Miembro del grupo de usuarios" msgid "User group to apply delegation to" msgstr "Grupo de usuarios para solicitar a la delegación" msgid "Add a new delegation." msgstr "Añadir una nueva delegación." #, python-format msgid "Added delegation \"%(value)s\"" msgstr "Delegación añadida \"%(value)s\"" msgid "Delete a delegation." msgstr "Borrar una delegación." #, python-format msgid "Deleted delegation \"%(value)s\"" msgstr "Delegación eliminada \"%(value)s\"" msgid "Modify a delegation." msgstr "Modificar una delegación." #, python-format msgid "Modified delegation \"%(value)s\"" msgstr "Delegación modificada \"%(value)s\"" msgid "Search for delegations." msgstr "Buscar delegaciones." #, python-format msgid "%(count)d delegation matched" msgid_plural "%(count)d delegations matched" msgstr[0] "%(count)d delegación coincidente" msgstr[1] "%(count)d delegaciones coincidentes" msgid "Display information about a delegation." msgstr "Mostrar información sobre una delegación." msgid "invalid IP address format" msgstr "formato no válido de dirección IP" msgid "invalid IP network format" msgstr "formato no válido de red IP" #, python-format msgid "invalid domain-name: %s" msgstr "nombre de dominio no válido: %s" #, python-format msgid "DNS reverse zone for IP address %(addr)s not found" msgstr "Zona invertida DNS para dirección IP %(addr)s no encontrada" #, python-format msgid "DNS zone %(zone)s not found" msgstr "Zona DNS %(zone)s no encontrado" msgid "Invalid number of parts!" msgstr "El número de partes no es válido." msgid "IP Address" msgstr "Dirección IP" msgid "Subtype" msgstr "Subtipo" msgid "Hostname" msgstr "Nombre del equipo anfitrión" msgid "Certificate Type" msgstr "Tipo de certificado" msgid "Algorithm" msgstr "Algoritmo" msgid "Certificate/CRL" msgstr "Certificado/CRL" msgid "Target" msgstr "Meta" msgid "Protocol" msgstr "Protocolo" msgid "Public Key" msgstr "Clave pública" msgid "Preference" msgstr "Preferencia" msgid "" "format must be specified as\n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (degrees latitude)\n" " d2: [0 .. 180] (degrees longitude)\n" " m1, m2: [0 .. 59] (minutes latitude/longitude)\n" " s1, s2: [0 .. 59.999] (seconds latitude/longitude)\n" " alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters)\n" " siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)\n" " See RFC 1876 for details" msgstr "" "\"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] [siz[\"m" "\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" "donde:\n" "d1: [0 .. 90] (grados de latitud)\n" "d2: [0 .. 180] (grados de longitud)\n" "m1, m2: [0 .. 59] (minutos de latitud/longitud)\n" "s1, s2: [0 .. 59.999] (segundos de latitud/longitud)\n" "alt: [-100000.00 .. 42849672.95] BY .01 (altitud en metros)\n" "siz, hp, vp: [0 .. 90000000.00] (tamaño/precisión en metros)\n" "Vea RFC 1876 para detalles" msgid "Service" msgstr "Servicio" msgid "Regular Expression" msgstr "Expresión regular" msgid "Priority" msgstr "Prioridad" msgid "Port" msgstr "Puerto" msgid "Labels" msgstr "Etiquetas" msgid "Original TTL" msgstr "TTL original" msgid "Signature Expiration" msgstr "Caducidad de la firma" msgid "Signer's Name" msgstr "Nombre del firmante" msgid "Signature" msgstr "Firma" msgid "Fingerprint Type" msgstr "Tipo de huella digital" msgid "Fingerprint" msgstr "Huella digital" msgid "Text Data" msgstr "Datos de texto" msgid "Records" msgstr "Registros" msgid "Record type" msgstr "Tipo de registro" #, python-format msgid "Nameserver '%(host)s' does not have a corresponding A/AAAA record" msgstr "" "El servidor de nombre '%(host)s' no tiene su correspondiente registro A/AAAA" msgid "DNS zone" msgstr "zona DNS" msgid "DNS zones" msgstr "zonas DNS" msgid "DNS Zones" msgstr "Zonas DNS" msgid "DNS Zone" msgstr "Zona DNS" msgid "Zone name" msgstr "Nombre de la zona" msgid "Zone name (FQDN)" msgstr "Nombre de la zona (FQDN)" msgid "Reverse zone IP network" msgstr "Zona reversa de red IP" msgid "IP network to create reverse zone name from" msgstr "Red IP para crear un nombre de zona reversa desde" msgid "Authoritative nameserver" msgstr "Nombre de servidor autoritativo" msgid "Authoritative nameserver domain name" msgstr "Nombre de dominio servidor de nombre autorizado" msgid "Administrator e-mail address" msgstr "Correo-e de administrador" msgid "SOA serial" msgstr "Serie SOA" msgid "SOA record serial number" msgstr "Número de serie de registro SOA" msgid "SOA refresh" msgstr "Actualizar SOA" msgid "SOA record refresh time" msgstr "registro SOA tiempo de actualización" msgid "SOA retry" msgstr "Reintentar SOA" msgid "SOA record retry time" msgstr "tiempo de reintento de " msgid "SOA expire" msgstr "Expirar SOA" msgid "SOA record expire time" msgstr "tiempo de expiración de registro SOA" msgid "SOA minimum" msgstr "Mínimo SOA" msgid "How long should negative responses be cached" msgstr "¿Por cuánto tiempo las respuestas negativas deben guardarse en cache?" msgid "SOA time to live" msgstr "Tiempo para abandonar SOA" msgid "SOA record time to live" msgstr "tiempo de vida de registro SOA" msgid "SOA class" msgstr "Clase SOA" msgid "SOA record class" msgstr "Clase de registro SOA " msgid "BIND update policy" msgstr "Política de actualización de BIND" msgid "Active zone" msgstr "Activar zona" msgid "Is zone active?" msgstr "¿Está la zona activa?" msgid "Dynamic update" msgstr "Actualización dinámica" msgid "Allow dynamic updates." msgstr "Permitir actualizaciones dinámicas." msgid "Create new DNS zone (SOA record)." msgstr "Crear nueva zona DNS (registro SOA)." msgid "Force" msgstr "Forzar" msgid "DNS is not configured" msgstr "DNS no está configurado" msgid "Delete DNS zone (SOA record)." msgstr "Borrar zona DNS (registro SOA)." msgid "Modify DNS zone (SOA record)." msgstr "Modificar zona DNS (registro SOA)." msgid "Search for DNS zones (SOA records)." msgstr "Buscar zonas DNS (registros SOA)." msgid "Forward zones only" msgstr "Zonas de reenvío sólo" msgid "Search for forward zones only" msgstr "Buscar zonas de reenvío sólo" msgid "Display information about a DNS zone (SOA record)." msgstr "Mostrar información sobre una zona DNS (registro SOA)." msgid "Disable DNS Zone." msgstr "Deshabilitar Zona DNS." #, python-format msgid "Disabled DNS zone \"%(value)s\"" msgstr "Zona de DNS desactivada \"%(value)s\" " msgid "Enable DNS Zone." msgstr "Habilitar Zona DNS." #, python-format msgid "Enabled DNS zone \"%(value)s\"" msgstr "Zona DNS habilitada \" %(value)s \"" msgid "DNS resource record" msgstr "Registro de recursos DNS" msgid "DNS resource records" msgstr "Registros de recurso DNS" msgid "DNS Resource Records" msgstr "Registros de Recursos DNS" msgid "DNS Resource Record" msgstr "Registro de Recurso de DNS" msgid "Record name" msgstr "Nombre de registro" msgid "Time to live" msgstr "Tiempo para abandonar" msgid "Class" msgstr "Clase" msgid "DNS class" msgstr "Clase DNS" msgid "Structured" msgstr "Estructurado" #, python-format msgid "" "Reverse zone for PTR record should be a sub-zone of one the following fully " "qualified domains: %s" msgstr "" "La zona invertida para registro PTR debería ser una sub-zona de uno de los " "siguientes dominios integramente cualificados: %s" msgid "Add new DNS resource record." msgstr "Añadir nuevo registro de recurso DNS." msgid "force NS record creation even if its hostname is not in DNS" msgstr "Forzar la creación del registro DNS, aunque su nombre no sea absoluto" msgid "Modify a DNS resource record." msgstr "Modificar un registro de recurso DNS." msgid "Current DNS record contents:\n" msgstr "Contenidos actuales del registro DNS:\n" #, python-format msgid "Deleted record \"%(value)s\"" msgstr "Registro eliminado \"%(value)s\"" msgid "Delete DNS resource record." msgstr "Borrar un registro de recurso DNS." msgid "" "Neither --del-all nor options to delete a specific record provided.\n" "Command help may be consulted for all supported record types." msgstr "" "Ni --del-all ni opciones para borrar un registro en concreto ha sido " "especificado.\n" "El comando de ayuda puede ser consultado para ver los tipos de registros " "soportados." msgid "Delete all associated records" msgstr "Eliminar todos los registros asociados" #, python-format msgid "Zone record '%s' cannot be deleted" msgstr "No se puede eliminar el registro de zona «%s»" msgid "No option to delete specific record provided." msgstr "Ninguna opción para borrar un registro en concreto especificado." msgid "Delete all?" msgstr "¿Borrar todos?" msgid "Display DNS resource." msgstr "Mostrar un recurso DNS." msgid "Search for DNS resources." msgstr "Buscar recursos DNS." msgid "Resolve a host name in DNS." msgstr "Resolver un nombre de host en DNS." #, python-format msgid "Found '%(value)s'" msgstr "Ha sido encontrado '%(value)s'" #, python-format msgid "Host '%(host)s' not found" msgstr "No ha sido encontrado el equipo anfitrión '%(host)s' " msgid "group" msgstr "grupo" msgid "groups" msgstr "grupos" msgid "User Groups" msgstr "Grupos de usuarios" msgid "User Group" msgstr "Grupo Usuario" msgid "Group name" msgstr "Nombre del grupo" msgid "Group description" msgstr "Descripción del grupo" msgid "GID" msgstr "GID" msgid "GID (use this option to set it manually)" msgstr "GID (utilice esta opción para definirlo manualmente)" msgid "Create a new group." msgstr "Crear un grupo nuevo." #, python-format msgid "Added group \"%(value)s\"" msgstr "Ha sido agregado el grupo \"%(value)s\"" msgid "Create as a non-POSIX group" msgstr " Crear como un grupo no POSIX" msgid "Delete group." msgstr "Eliminar grupo." #, python-format msgid "Deleted group \"%(value)s\"" msgstr "Ha sido eliminado el grupo \"%(value)s\"" msgid "Modify a group." msgstr "Modificar un grupo." #, python-format msgid "Modified group \"%(value)s\"" msgstr "Ha sido modificado el grupo \"%(value)s\"" msgid "change to a POSIX group" msgstr "Cambiar a un grupo POSIX" msgid "Search for groups." msgstr "Buscar grupos." #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "%(count)d grupo coincidente" msgstr[1] "%(count)d grupos coincidentes" msgid "search for private groups" msgstr "Búsqueda de grupos privados" msgid "Display information about a named group." msgstr "Mostrar información sobre un grupo denominado." msgid "Add members to a group." msgstr "Agregar miembro a un grupo." msgid "Remove members from a group." msgstr "Eliminar miembro desde un grupo." msgid "Detach a managed group from a user." msgstr "Desenganchar un grupo gestionado desde un usuario." #, python-format msgid "Detached group \"%(value)s\" from user \"%(value)s\"" msgstr "Ha sido desasociado el grupo \"%(value)s\" del usuario \"%(value)s\"" msgid "not allowed to modify user entries" msgstr "no se permite modificar las entradas de los usuarios" msgid "not allowed to modify group entries" msgstr "no se permite modificar las entradas de los grupos" msgid "Not a managed group" msgstr "No es un grupo administrado" msgid "Host-based access control commands" msgstr "Comandos de control de acceso basado en host" msgid "The deny type has been deprecated." msgstr "El tipo deny ha quedado obsoleto." msgid "HBAC rule" msgstr "Regla HBAC" msgid "HBAC rules" msgstr "Reglas HBAC" msgid "HBAC Rules" msgstr "Reglas HBAC" msgid "HBAC Rule" msgstr "REgla HBAC" msgid "Rule name" msgstr "Nombre de la regla" msgid "Rule type (allow)" msgstr "Tipo de regla (permitir)" msgid "Rule type" msgstr "Tipo de regla" msgid "User category" msgstr "Categoría de usuario" msgid "User category the rule applies to" msgstr "Categoría de usuario al que se aplica la regla" msgid "Host category" msgstr "Categoría del equipo" msgid "Host category the rule applies to" msgstr "Categoría del equipo al que se aplica la regla" msgid "Service category" msgstr " Añadir servicios a una regla de HBAC" msgid "Service category the rule applies to" msgstr "Categoría de servicio a la que se aplica la regla" msgid "Enabled" msgstr "Habilitado" msgid "Users" msgstr "Usuarios" msgid "Hosts" msgstr "Equipos" msgid "Host Groups" msgstr "Grupos de equipo" msgid "Services" msgstr "Sevicios HBAC" msgid "Service Groups" msgstr " Búsqueda de servicios HBAC." msgid "Create a new HBAC rule." msgstr "Crear una nueva regla HBAC." #, python-format msgid "Added HBAC rule \"%(value)s\"" msgstr "Añadida regla HBAC \"%(value)s\"" msgid "Delete an HBAC rule." msgstr "Borrar una regla HBAC." #, python-format msgid "Deleted HBAC rule \"%(value)s\"" msgstr "Suprimida regla HBAC \"%(value)s\"" msgid "Modify an HBAC rule." msgstr "Modificar una regla HBAC." #, python-format msgid "Modified HBAC rule \"%(value)s\"" msgstr "Modificada regla HBAC \"%(value)s\"" msgid "Search for HBAC rules." msgstr "Buscar reglas HBAC." #, python-format msgid "%(count)d HBAC rule matched" msgid_plural "%(count)d HBAC rules matched" msgstr[0] "%(count)d regla coincidente de HBAC" msgstr[1] "%(count)d reglas coincidentes de HBAC " msgid "Display the properties of an HBAC rule." msgstr "Mostrar las propiedades de una regla HBAC." msgid "Enable an HBAC rule." msgstr "Habilitar una regla HBAC." #, python-format msgid "Enabled HBAC rule \"%(value)s\"" msgstr "Habilitada regla HBAC \"%(value)s\"" msgid "Disable an HBAC rule." msgstr "Deshabilitar una regla HBAC." #, python-format msgid "Disabled HBAC rule \"%(value)s\"" msgstr "\"%(value)s\" regla HBAC desactivada " msgid "Access time" msgstr "Hora de acceso" msgid "Add users and groups to an HBAC rule." msgstr "Añadir usuarios y grupos a una regla HBAC." msgid "Remove users and groups from an HBAC rule." msgstr "Borrar usuarios y grupos de una regla HBAC." msgid "Add target hosts and hostgroups to an HBAC rule." msgstr "Añadir hosts objetivos y grupos de host a una regla HBAC." msgid "Remove target hosts and hostgroups from an HBAC rule." msgstr "Borrar hosts objetivos y grupos de host de una regla HBAC." msgid "Add services to an HBAC rule." msgstr "Añadir servicios a una regla HBAC." msgid "Remove service and service groups from an HBAC rule." msgstr "Borrar servicio y grupos de servicio de una regla HBAC." msgid "" "\n" "HBAC Services\n" "\n" "The PAM services that HBAC can control access to. The name used here\n" "must match the service name that PAM is evaluating.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service:\n" " ipa hbacsvc-add tftp\n" "\n" " Modify an existing HBAC service:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Search for HBAC services. This example will return two results, the FTP\n" " service and the newly-added tftp service:\n" " ipa hbacsvc-find ftp\n" "\n" " Delete an HBAC service:\n" " ipa hbacsvc-del tftp\n" "\n" msgstr "" "\n" "Servicios de HBAC\n" "\n" "Los servicios PAM a los que HBAC puede controlar el acceso. El nombre " "utilizado aquí debe coincidir\n" "con el nombre del servicio que PAM está evaluando.\n" "\n" "EJEMPLOS:\n" "\n" " Añadir un nuevo servicio:\n" " ipa hbacsvc-add tftp\n" "\n" " Modificar un servicio de HBAC:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Buscar servicios para HBAC. Este ejemplo retornará dos resultados, el " "servicio FTP\n" " y el servicio recién añadido tftp:\n" " ipa hbacsvc-find ftp\n" "\n" " Borrar un servicio de HBAC:\n" " ipa hbacsvc-del tftp\n" "\n" msgid "Host based access control commands" msgstr "Comandos de control de acceso basado en host" msgid "HBAC service" msgstr "Servicio HBAC" msgid "HBAC services" msgstr "Servicios HBAC" msgid "HBAC Services" msgstr "Servicios HBAC" msgid "HBAC Service" msgstr "Servicio HBAC" msgid "Service name" msgstr "% (Count) d HBAC servicios encontrados" msgid "HBAC service description" msgstr "Descripción de servicio HBAC" msgid "Add a new HBAC service." msgstr "Añadir un nuevo servicio HBAC." #, python-format msgid "Added HBAC service \"%(value)s\"" msgstr "Servicio de HBAC \"%(value)s\" añadido" msgid "Delete an existing HBAC service." msgstr "Borrar un servicio HBAC existente." #, python-format msgid "Deleted HBAC service \"%(value)s\"" msgstr "Suprimido el servicio HBAC \"%(value)s\"" msgid "Modify an HBAC service." msgstr "Modificar un servicio HBAC." #, python-format msgid "Modified HBAC service \"%(value)s\"" msgstr " Servicio modificado HBAC \"%(value)s\"" msgid "Search for HBAC services." msgstr "Buscar un servicio HBAC." #, python-format msgid "%(count)d HBAC service matched" msgid_plural "%(count)d HBAC services matched" msgstr[0] "Servicio HBAC %(count)d coincidente" msgstr[1] "Servicios HBAC %(count)d coincidentes" msgid "Display information about an HBAC service." msgstr "Mostrar información sobre un servicio HBAC." msgid "HBAC service group" msgstr "Grupo de servicio HBAC" msgid "HBAC service groups" msgstr "Grupos de servicio HBAC" msgid "HBAC Service Groups" msgstr "Grupos de Servicios HBAC" msgid "HBAC Service Group" msgstr "Grupo de Servicio HBAC" msgid "Service group name" msgstr "" " Desactivar la tecla de Kerberos, certificado SSL y todos los servicios " "de un host." msgid "HBAC service group description" msgstr "Servicios y grupos especificados" msgid "Add a new HBAC service group." msgstr "Añadir un nuevo grupo de servicio HBAC." #, python-format msgid "Added HBAC service group \"%(value)s\"" msgstr "Agregado servicio de grupo HBAC \"%(value)s\"" msgid "Delete an HBAC service group." msgstr "Borrar un grupo de servicio HBAC." #, python-format msgid "Deleted HBAC service group \"%(value)s\"" msgstr " Suprimido el servicio HBAC grupo \"%(value)s\"" msgid "Modify an HBAC service group." msgstr "Modificar un grupo de servicio HBAC." #, python-format msgid "Modified HBAC service group \"%(value)s\"" msgstr "Servicio modificado HBAC grupo \"%(value)s\"" msgid "Search for an HBAC service group." msgstr "Buscar un grupo de servicio HBAC." #, python-format msgid "%(count)d HBAC service group matched" msgid_plural "%(count)d HBAC service groups matched" msgstr[0] "%(count)d grupo de servicio HBAC coincidente" msgstr[1] "%(count)d grupos de servicio HBAC coincidentes" msgid "Display information about an HBAC service group." msgstr "Mostrar información sobre un grupo de servicio HBAC." msgid "Add members to an HBAC service group." msgstr "Añadir miembros a un grupo de servicio HBAC." msgid "Remove members from an HBAC service group." msgstr "Borrar miembros de un grupo de servicio HBAC." msgid "Simulate use of Host-based access controls" msgstr "Simular el uso de controles de acceso basados en Host" msgid "Warning" msgstr "Aviso" msgid "Matched rules" msgstr "Reglas coincidentes" msgid "Not matched rules" msgstr "Reglas no coincidentes" msgid "Non-existent or invalid rules" msgstr "Reglas no existentes o no válidas" msgid "Result of simulation" msgstr "Resultado de la simulación" msgid "User name" msgstr "Nombre de usuario" msgid "Target host" msgstr "Host objetivo" msgid "Rules to test. If not specified, --enabled is assumed" msgstr "Reglas para probar. Si no se especifica, - se asume que habilitado" msgid "Hide details which rules are matched, not matched, or invalid" msgstr "" "Esconder detalles de que reglas coinciden, no coinciden o son no válidas" msgid "Include all enabled IPA rules into test [default]" msgstr "Incluir todas las reglas IPA habilitadas en la prueba [por defecto]" msgid "Include all disabled IPA rules into test" msgstr "Incluir todas las reglas IPA deshabilitadas en la prueba" msgid "Unresolved rules in --rules" msgstr "Eliminar miembro desde un grupo." #, python-format msgid "Access granted: %s" msgstr "Acceso obtenido: %s" msgid "Keytab" msgstr "Keytab" msgid "Serial Number" msgstr "Número de serie" msgid "Failed managedby" msgstr "Falló managedby" msgid "host" msgstr "host" msgid "hosts" msgstr "hosts" msgid "Host" msgstr "Host" msgid "Host name" msgstr "Nombre del equipo" msgid "A description of this host" msgstr "Una descripción de este equipo" msgid "Locality" msgstr "Localidad" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "Localidad del equipo (p.ej. \"Barrio latino, París\") " msgid "Host location (e.g. \"Lab 2\")" msgstr "Ubicación del equipo (p. ej. \"Laboratorio\")" msgid "Platform" msgstr "Plataforma" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "Plataforma de hardware del equipo (p. ej. \"Lenovo T61\")" msgid "Operating system" msgstr "Sistema operativo" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "" "Sistema operativo que utiliza el equipo y versión (p.ej. \"Fedora 11\")" msgid "User password" msgstr "Contraseña de usuario" msgid "Password used in bulk enrollment" msgstr "Contraseña utilizada en el registro bruto" msgid "Generate a random password to be used in bulk enrollment" msgstr "Generar una contraseña aleatoria que se utilizará en la inscripción " msgid "Random password" msgstr "Contraseña aleatoria" msgid "Base-64 encoded server certificate" msgstr "Certificado del servidor codificado con base-64" msgid "Principal name" msgstr "Nombre principal" msgid "MAC address" msgstr "Dirección MAC" msgid "Add a new host." msgstr "Añadir un n uevo host." #, python-format msgid "Added host \"%(value)s\"" msgstr "Ha sido agregado el equipo \"%(value)s\"" msgid "force host name even if not in DNS" msgstr "" "fuerza el nombre del equipo anfitrión, incluso si no se encuentra en DNS" msgid "skip reverse DNS detection" msgstr "Ignorar la detección inversa de DNS" msgid "Add the host to DNS with this IP address" msgstr "Agregar el host de DNS con esta dirección IP" #, python-format msgid "The host was added but the DNS update failed with: %(exc)s" msgstr "El host fue añadido, pero la actualización de DNS falló con:%(exc)s" msgid "Delete a host." msgstr "Borrar un host." #, python-format msgid "Deleted host \"%(value)s\"" msgstr "Ha sido eliminado el equipo \"%(value)s\"" msgid "Remove entries from DNS" msgstr "Eliminar entradas de DNS" msgid "Modify information about a host." msgstr "Modificar información sobre un host." #, python-format msgid "Modified host \"%(value)s\"" msgstr "Ha sido modificado el equipo \"%(value)s\"" msgid "Kerberos principal name for this host" msgstr "Nombre del prinicpal de Kerberos para este equipo" msgid "Update DNS entries" msgstr "Actualizar las entradas DNS" msgid "Password cannot be set on enrolled host." msgstr "La contraseña no puede ser fijada en el host matriculado." msgid "Search for hosts." msgstr "Buscar hosts." #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "%(count)d equipo coincidente" msgstr[1] "%(count)d equipos coincidentes" msgid "Display information about a host." msgstr "Mostrar información sobre un host." msgid "file to store certificate in" msgstr "archivo para almacenar" #, python-format msgid "Certificate stored in file '%(file)s'" msgstr "Certificado almacenado en el archivo '%(file)s'" msgid "Disable the Kerberos key, SSL certificate and all services of a host." msgstr "" "Deshabilitar la clave Kerberos, el certificado SSL y todos los servicios de " "un host." #, python-format msgid "Disabled host \"%(value)s\"" msgstr "Host desactivado \"%(value)s\"" msgid "Add hosts that can manage this host." msgstr "Añadir hosts que pueda manejar este host." msgid "Remove hosts that can manage this host." msgstr "Borrar hosts que puede manejar este host." msgid "host group" msgstr "grupo de host" msgid "host groups" msgstr "grupos de host" msgid "Host Group" msgstr "Grupo de Host" msgid "Host-group" msgstr "Grupo de equipo" msgid "Name of host-group" msgstr "Nombre del grupo de equipo" msgid "A description of this host-group" msgstr "Una descripción de este grupo de equipo" msgid "Add a new hostgroup." msgstr "Añadir un nuevo grupo de host." #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "Ha sido agregado el grupo de equipo \"%(value)s\"" #, python-format msgid "" "netgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "grupo de red con nombre “%s†ya existe. Los grupos de host y grupos de red " "comparten un espacio de nombre común" msgid "Delete a hostgroup." msgstr "Borrar un grupo de host." #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "Ha sido eliminado el grupo de equipo \"%(value)s\"" msgid "Modify a hostgroup." msgstr "Modificar un grupo de host." #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "Ha sido modificado el grupo de equipo \"%(value)s\"" msgid "Search for hostgroups." msgstr "Buscar grupos de host." #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "%(count)d grupo de equipos coincidente" msgstr[1] "%(count)d grupos de equipos coincidentes" msgid "Display information about a hostgroup." msgstr "Mostrar información sobre un grupo de host." msgid "Add members to a hostgroup." msgstr "Añadir miembros a un grupo de host." msgid "Remove members from a hostgroup." msgstr "Borrar miembros de un grupo de host." msgid "Name of object to export" msgstr "Nombre del objeto a exportar" msgid "Name of method to export" msgstr "Nombre del método para exportación" msgid "Name of command to export" msgstr "Nombre de comando a exportar" msgid "Dict of JSON encoded IPA Objects" msgstr "El dict de JSON ha codificado objetos IPA" msgid "Dict of JSON encoded IPA Methods" msgstr "Métodos IPA codificados de Dict de JSON " msgid "Dict of JSON encoded IPA Commands" msgstr "Dict de JSON comandos codificados IPA" msgid "Add RunAs ${other_entity} into ${entity} ${primary_key}" msgstr "Añadir RunAs ${other_entity} en ${entity} ${primary_key}" msgid "Add RunAs Groups into ${entity} ${primary_key}" msgstr "Añadir RunAs Grupos en ${entity} ${primary_key}" msgid "Add ${other_entity} Managing ${entity} ${primary_key}" msgstr "Añadir ${other_entity} Gestionando ${entity} ${primary_key}" msgid "Add ${other_entity} into ${entity} ${primary_key}" msgstr "Añadir ${other_entity} a ${entity} ${primary_key}" msgid "Add Allow ${other_entity} into ${entity} ${primary_key}" msgstr "Añadir Permitir ${other_entity} en ${entity} ${primary_key}" msgid "Add Deny ${other_entity} into ${entity} ${primary_key}" msgstr "Añadir Denegar ${other_entity} en ${entity} ${primary_key}" msgid "Add ${entity} ${primary_key} into ${other_entity}" msgstr "Añadir ${entity} ${primary_key} en ${other_entity}" msgid "Direct Membership" msgstr "Afiliación Directa" msgid "Indirect Membership" msgstr "Afiliación Indirecta" msgid "No entries." msgstr "Sin entradas." msgid "Showing ${start} to ${end} of ${total} entries." msgstr "Mostrando ${start} a ${end} de ${total} entradas." msgid "Remove RunAs ${other_entity} from ${entity} ${primary_key}" msgstr "Quitar RunAs ${other_entity} de ${entity} ${primary_key}" msgid "Remove RunAs Groups from ${entity} ${primary_key}" msgstr "Quitar Grupos RunAs de ${entity} ${primary_key}" msgid "Remove ${other_entity} Managing ${entity} ${primary_key}" msgstr "Quitar ${other_entity} Gestionando ${entity} ${primary_key}" msgid "Remove ${other_entity} from ${entity} ${primary_key}" msgstr "Retirar ${other_entity} de ${entity} ${primary_key}" msgid "Remove Allow ${other_entity} from ${entity} ${primary_key}" msgstr "Quitar Permitir ${other_entity} de ${entity} ${primary_key}" msgid "Remove Deny ${other_entity} from ${entity} ${primary_key}" msgstr "Quitar Denegar ${other_entity} de ${entity} ${primary_key}" msgid "Remove ${entity} ${primary_key} from ${other_entity}" msgstr "Quitar ${entity} ${primary_key} de ${other_entity}" msgid "Show Results" msgstr "Mostrar Resultados" msgid "Add" msgstr "Agregar" msgid "Add and Add Another" msgstr "Agregar y agregar otro" msgid "Add and Close" msgstr "Añadir y cerrar" msgid "Add and Edit" msgstr "Agregar y Editar" msgid "Add Many" msgstr "Añadir Muchos" msgid "Cancel" msgstr "Cancelar" msgid "Close" msgstr "Cerrar" msgid "Disable" msgstr "Desactivar" msgid "Edit" msgstr "Editar" msgid "Enable" msgstr "Activar" msgid "Find" msgstr "Buscar" msgid "Get" msgstr "Obtener" msgid "Issue" msgstr "Tema" msgid "OK" msgstr "Aceptar" msgid "Refresh" msgstr "Actualizar" msgid "Delete" msgstr "Eliminar" msgid "Reset" msgstr "Resetear" msgid "Restore" msgstr "Restaurar" msgid "Retry" msgstr "Reintentar" msgid "Revoke" msgstr "Revocar" msgid "Set" msgstr "Definir" msgid "Update" msgstr "Actualizar" msgid "View" msgstr "Ver" msgid "Collapse All" msgstr "Cerrar Todo" msgid "Expand All" msgstr "Expandir Todo" msgid "General" msgstr "General" msgid "Identity Settings" msgstr "Configuración de identidad" msgid "${entity} ${primary_key} Settings" msgstr "Configuraciones de ${entity} ${primary_key}" msgid "Back to Top" msgstr "Volver al comienzo" msgid "${entity} successfully added" msgstr "${entity} añadido con éxito" msgid "Add ${entity}" msgstr "Añadir ${entity}" msgid "Available" msgstr "Disponible" msgid "Some operations failed." msgstr "Algunas operaciones fallaron." msgid "Operations Error" msgstr "Error en Operaciones" msgid "Confirmation" msgstr "Confirmación " msgid "This page has unsaved changes. Please save or revert." msgstr "Esta página tiene cambios sin guardar. Por favor, guardar o deshacer." msgid "Unsaved Changes" msgstr "Cambios No Guardados" msgid "Edit ${entity}" msgstr "Editar ${entity}" msgid "Hide details" msgstr "Esconder detalles" msgid "Prospective" msgstr "Prospectivo" msgid "Redirection" msgstr "Redirección " msgid "Select entries to be removed." msgstr "Las entradas seleccionadas han sido quitadas." msgid "Remove ${entity}" msgstr "Quitar ${entity}" msgid "Show details" msgstr "Mostrar detalles" msgid "Validation error" msgstr "Error de validación" msgid "Input form contains invalid or missing values." msgstr "La entrada contiene valores no válidos o desaparecidos." msgid "HTTP Error" msgstr "Error HTTP" msgid "Internal Error" msgstr "Error Interno" msgid "IPA Error" msgstr "Error IPA" msgid "No response" msgstr "Sin respuesta" msgid "Unknown Error" msgstr "Error Desconocido" msgid "URL" msgstr "URL" msgid "${primary_key} is managed by:" msgstr "${primary_key} es gestionada por:" msgid "${primary_key} members:" msgstr "${primary_key} miembros:" msgid "${primary_key} is a member of:" msgstr "${primary_key} es un miembro de:" msgid "Settings" msgstr "Configuración" msgid "Search" msgstr "Búsqueda" msgid "False" msgstr "Falso" msgid "Logged In As" msgstr "Registrado como" msgid "Username" msgstr "Nombre de usuario" msgid "Attribute" msgstr "Atributo" msgid "Add Rule" msgstr "Añadir una regla" msgid "Automount Location Settings" msgstr "Configuración de ubicación de automount" msgid "Map Type" msgstr "Tipo de Mapa" msgid "Direct" msgstr "Directo" msgid "Indirect" msgstr "Indirecto" msgid "AA Compromise" msgstr "AA transacción" msgid "Affiliation Changed" msgstr "Afiliación cambiada" msgid "CA Compromise" msgstr "CA de transacción" msgid "Certificates" msgstr "Certificados" msgid "Certificate Hold" msgstr "Certificado retenido" msgid "Cessation of Operation" msgstr "Cese de operaciones" msgid "Common Name" msgstr "Nombre común" msgid "Expires On" msgstr "Expira el" msgid "Fingerprints" msgstr "Las huellas dactilares" msgid "Issue New Certificate for ${entity} ${primary_key}" msgstr "Enviar Nuevo Certificado para ${entity} ${primary_key}" msgid "Issued By" msgstr "Expedido por" msgid "Issued On" msgstr "Expiración" msgid "Issued To" msgstr "Expedido para" msgid "Key Compromise" msgstr "Clave de transacción" msgid "MD5 Fingerprint" msgstr "Huella digital de MD5" msgid "No Valid Certificate" msgstr "Certificado no válido" msgid "New Certificate" msgstr "Un nuevo certificado" msgid "Note" msgstr "Nota" msgid "Organization" msgstr "Organización" msgid "Organizational Unit" msgstr "Unidad organizativa" msgid "Privilege Withdrawn" msgstr "Retirada de privilegios" msgid "Reason for Revocation" msgstr "Motivo de la revocación" msgid "Remove from CRL" msgstr "Borrar de CRL" msgid "Restore Certificate for ${entity} ${primary_key}" msgstr "Restablecer Certificado para ${entity} ${primary_key}" msgid "" "To confirm your intention to restore this certificate, click the \"Restore\" " "button." msgstr "" "Para confirmar su intención de restaurar este certificado, haga clic en el " "botón \"Restaurar\"." msgid "Revoke Certificate for ${entity} ${primary_key}" msgstr "Revocar certificado por ${entity} ${primary_key}" msgid "" "To confirm your intention to revoke this certificate, select a reason from " "the pull-down list, and click the \"Revoke\" button." msgstr "" "Para confirmar su intención de revocar el certificado, seleccione una razón " "de la lista desplegable y haga clic en el botón \"Revocar\"." msgid "Certificate Revoked" msgstr "Certificado revocado" msgid "SHA1 Fingerprint" msgstr "Huella digital SHA1" msgid "Superseded" msgstr "Obsoleta" msgid "Unspecified" msgstr "No especificada" msgid "Valid Certificate Present" msgstr "Presentar certificado válido" msgid "Validity" msgstr "Validez" msgid "Certificate for ${entity} ${primary_key}" msgstr "Certificado para ${entity} ${primary_key}" msgid "Group Options" msgstr "Opciones de Grupo" msgid "Search Options" msgstr "Opciones de Búsqueda" msgid "User Options" msgstr "Opciones de Usuario" msgid "Options" msgstr "Opciones" msgid "Data" msgstr "Datos" msgid "DNS record was deleted because it contained no data." msgstr "Registro DNS fue borrado porque no contenía datos." msgid "Other Record Types" msgstr "Otros Tipos de Registro" msgid "You will be redirected to DNS Zone." msgstr "Será redirigido a Zona DNS." msgid "Standard Record Types" msgstr "Tipos de Registro Estándar" msgid "Records for DNS Zone" msgstr "Los registros para la zona DNS" msgid "Record Type" msgstr "Tipo de Registro" msgid "DNS Zone Settings" msgstr "Configuración de la Zona DNS" msgid "Group Settings" msgstr "Configuración del grupo" msgid "External" msgstr "Externos" msgid "Any Host" msgstr "Cualquier host" msgid "Any Service" msgstr "Cualquier servicio" msgid "Anyone" msgstr "Cualquiera" msgid "Accessing" msgstr "Acceso" msgid "Rule status" msgstr "Estatus de reglas" msgid "Via Service" msgstr "Vía de servicio" msgid "Specified Hosts and Groups" msgstr "Hosts y grupos especificados" msgid "Specified Services and Groups" msgstr "Servicios y grupos especificados" msgid "Specified Users and Groups" msgstr "Usuarios y grupos específicos" msgid "Who" msgstr "¿Quién?" msgid "Access Denied" msgstr "Acceso Denegado" msgid "Access Granted" msgstr "Acceso Obtenido" msgid "Include Disabled" msgstr "Include Deshabilitado" msgid "Include Enabled" msgstr "Include Habilitado" msgid "HBAC Test" msgstr "Prueba HBAC" msgid "Matched" msgstr "Emparejado" msgid "New Test" msgstr "Nueva Prueba" msgid "Rules" msgstr "Reglas" msgid "Run Test" msgstr "Ejecutar Prueba" msgid "Specify external ${entity}" msgstr "Especificar ${entity} externa" msgid "Unmatched" msgstr "Desemparejado" msgid "Host Certificate" msgstr "Certificado de host" msgid "Host Name" msgstr "Nombre de host" msgid "Delete Key, Unprovision" msgstr "La eliminación de clave, unprovision" msgid "Host Settings" msgstr "Configuración del host" msgid "Enrollment" msgstr "Inscripción" msgid "Fully Qualified Host Name" msgstr "Nombre de host totalmente calificado" msgid "Kerberos Key" msgstr "Clave Kerberos" msgid "Kerberos Key Not Present" msgstr "No hay clave Kerberos Presente" msgid "Kerberos Key Present, Host Provisioned" msgstr "Claves de Kerberos presente, Host aprovisionado" msgid "One-Time-Password" msgstr "Contraseña de Una Vez" msgid "One-Time-Password Not Present" msgstr "Contraseña de Una Vez No Presente" msgid "One-Time-Password Present" msgstr "Contraseña de Una Vez Presente" msgid "Reset OTP" msgstr "Reajustar OTP" msgid "Reset One-Time-Password" msgstr "Reajustar Contraseña de Una Vez" msgid "Set OTP" msgstr "Establecer OTP" msgid "Set One-Time-Password" msgstr "Fijar Contraseña de Una Vez" msgid "Unprovision" msgstr "Unprovision" msgid "Are you sure you want to unprovision this host?" msgstr "¿Está seguro que desea unprovision este equipo?" msgid "Unprovisioning ${entity}" msgstr "Cancelación ${entity}" msgid "Host Group Settings" msgstr "Configuraciones del Grupo de Host" msgid "Kerberos Ticket Policy" msgstr " Política de tiquete de Kerberos" msgid "Netgroup Settings" msgstr "Configuración de Netgroup" msgid "User" msgstr "Usuario" msgid "Identity" msgstr "Identidad" msgid "Permission with invalid target specification" msgstr "Permiso con especificación de destino inválida" msgid "Privilege Settings" msgstr "Configuración de privilegios" msgid "Password Policy" msgstr "Directiva de contraseñas" msgid "Role Settings" msgstr "Configuración de rol" msgid "Service Certificate" msgstr "Certificado de servicio" msgid "Service Settings" msgstr "Configuración del servicio" msgid "Provisioning" msgstr "Aprovisionamiento" msgid "Are you sure you want to unprovision this service?" msgstr "¿Está seguro de que desea no suministrar este servicio?" msgid "Kerberos Key Present, Service Provisioned" msgstr "Claves de Kerberos actuales, Servicio suministrado" msgid "Groups" msgstr "Grupos" msgid "Commands" msgstr "Comandos" msgid "Allow" msgstr "Permitir" msgid "Any Command" msgstr "Cualquier comando" msgid "Any Group" msgstr "Cualquier grupo" msgid "Run Commands" msgstr "Ejecutar comandos" msgid "Deny" msgstr "Negar" msgid "Access this host" msgstr "Acceder a este host" msgid "As Whom" msgstr "Como Whom" msgid "Specified Commands and Groups" msgstr "Comandos especificados y grupos" msgid "Specified Groups" msgstr "Grupos especificados" msgid "Account" msgstr "Cuenta" msgid "Account Settings" msgstr "Configuración de la cuenta" msgid "Account Status" msgstr "Estado de Cuenta" msgid "Contact Settings" msgstr "Configuración de contactos" msgid "Employee Information" msgstr "Información del Empleado" msgid "Error changing account status" msgstr "Error al cambiar el estado de cuenta" msgid "Password expiration" msgstr "Caducidad de la contraseña" msgid "Mailing Address" msgstr "Dirección de correo" msgid "Misc. Information" msgstr "Información diversa" msgid "" "Are you sure you want to ${action} the user?
The change will take effect " "immediately." msgstr "" "¿Está seguro que desea ${action} el usuario?
El cambio tendrá efecto " "inmediatamente." msgid "Click to ${action}" msgstr "Pulse para ${action}" msgid "Current Password" msgstr "Contraseña Actual" msgid "Current password is required" msgstr "Se necesita contraseña actual" msgid "New Password" msgstr "Nueva Contraseña" msgid "Password change complete" msgstr "Cambiar la contraseña completa" msgid "Passwords must match" msgstr "Las contraseñas deben coincidir" msgid "Reset Password" msgstr "Restablecer contraseña" msgid "Verify Password" msgstr "Verificar Contraseña" msgid "Are you sure you want to delete selected entries?" msgstr "¿Está seguro que desea eliminar las entradas seleccionadas?" msgid "Some entries were not deleted" msgstr "Algunas entradas no fueron borradas" msgid "Quick Links" msgstr "Enlaces rápidos" msgid "Select All" msgstr " Seleccionar todo" msgid "" "Query returned more results than the configured size limit. Displaying the " "first ${counter} results." msgstr "" "La solicitud devolvió más resultados que el límite de tamaño configurado. " "Mostrando los primeros resultados ${counter}." msgid "Unselect All" msgstr "Anular selección" msgid "Disabled" msgstr "Desactivado" msgid "Audit" msgstr "Auditoría" msgid "Automount" msgstr "Montaje automático" msgid "DNS" msgstr "DNS" msgid "Host Based Access Control" msgstr "Control de Acceso basado en Host" msgid "IPA Server" msgstr "Servidor IPA" msgid "Policy" msgstr "Política" msgid "Role Based Access Control" msgstr "Control de acceso basado en rol" msgid "Sudo" msgstr "Sudo" msgid "True" msgstr "Verdad" msgid "Next" msgstr "Siguiente" msgid "Page" msgstr "Página" msgid "Prev" msgstr "Anterior" msgid "undo" msgstr "deshacer" msgid "undo all" msgstr "deshacer todo" msgid "Text does not match field pattern" msgstr "El texto no coincide con el patrón de campo" msgid "Must be an integer" msgstr "Debe ser un entero" msgid "Not a valid IP address" msgstr "No es una dirección IP válida" msgid "Not a valid IPv4 address" msgstr "No es una dirección IPv4 válida" msgid "Not a valid IPv6 address" msgstr "No es una dirección IPv6 válida" msgid "Maximum value is ${value}" msgstr "Valor máximo es ${value}" msgid "Minimum value is ${value}" msgstr "Valor mínimo es ${value}" msgid "Required field" msgstr "Campo requerido" msgid "Dict of I18N messages" msgstr "Dictado de los mensajes regionales" msgid "" "\n" "Kerberos ticket policy\n" "\n" "There is a single Kerberos ticket policy. This policy defines the\n" "maximum ticket lifetime and the maximum renewal age, the period during\n" "which the ticket is renewable.\n" "\n" "You can also create a per-user ticket policy by specifying the user login.\n" "\n" "For changes to the global policy to take effect, restarting the KDC service\n" "is required, which can be achieved using:\n" "\n" "service krb5kdc restart\n" "\n" "Changes to per-user policies take effect immediately for newly requested\n" "tickets (e.g. when the user next runs kinit).\n" "\n" "EXAMPLES:\n" "\n" " Display the current Kerberos ticket policy:\n" " ipa krbtpolicy-show\n" "\n" " Reset the policy to the default:\n" " ipa krbtpolicy-reset\n" "\n" " Modify the policy to 8 hours max life, 1-day max renewal:\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Display effective Kerberos ticket policy for user 'admin':\n" " ipa krbtpolicy-show admin\n" "\n" " Reset per-user policy for user 'admin':\n" " ipa krbtpolicy-reset admin\n" "\n" " Modify per-user policy for user 'admin':\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgstr "" "\n" "Funciones \n" "\n" "Un rol se utiliza para la delegación de grano fino. Un permiso otorga la " "capacidad de realizar tareas de bajo nivel (añadir un usuario, modificar un " "grupo, etc.) Un privilegio combina uno o más permisos en una abstracción \n" "de nivel superior tales como useradmin. Un useradmin sería capaz de añadir, " "eliminar y modificar usuarios. \n" "\n" "Los privilegios son asignados a roles.\n" "\n" "Los usuarios, grupos, hosts y hostgroups pueden ser miembros de un Rol. \n" "\n" "Los Roles no pueden contener otros roles.\n" "\n" "EJEMPLOS:\n" "\n" "Añadir un nuevo rol: \n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege=add_user_to_default_group\n" "junioradmin\n" "\n" "Agregar un grupo de usuarios a este rol:\n" " ipa group-add --desc=\"User admins\" useradmins \n" " ipa role-add-member --groups=useradmins junioradmin \n" "\n" "Mostrar información sobre el rol:\n" " ipa role-show junioradmin\n" "\n" "El resultado de esto es que cualquier usuario en el grupo 'useradmins' puede " "agregar usuarios, restablecer contraseñas o añadir un usuario al grupo de " "usuarios predeterminado de la IPA.\n" msgid "kerberos ticket policy settings" msgstr "ajustes de la entrada de política kerberos" msgid "Manage ticket policy for specific user" msgstr "Administra política de ticket para un usuario específico" msgid "Max life" msgstr "Vida máxima" msgid "Maximum ticket life (seconds)" msgstr "Duración máxima del ticket (en segundos)" msgid "Max renew" msgstr "Renovación máxima" msgid "Maximum renewable age (seconds)" msgstr "Duración máxima renovable (en segundos)" msgid "Modify Kerberos ticket policy." msgstr "Modificar entrada de política Kerberos." msgid "Display the current Kerberos ticket policy." msgstr "Mostrar la actual entrada de política Kerberos." msgid "Reset Kerberos ticket policy to the default values." msgstr "Reajustar la entrada de política Kerberos a los valores por defecto." #, python-format msgid "" "Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually." msgstr "" "El principal %s de Kerberos ya existe. Utilice 'ipa user-mod' para definirlo " "manualmente." msgid "" "Failed to add user to the default group. Use 'ipa group-add-member' to add " "manually." msgstr "" "Falló al intenatar agregar al usuario al grupo predeterminado. Utilice 'ipa " "group-add-member' para agregarlo manualmente. " msgid "Migration of LDAP search reference is not supported." msgstr "Migración de búsqueda de referencia LDAP no está soportada." msgid "Malformed DN" msgstr "DN Malformado" msgid "" ". Check GID of the existing group. Use --group-overwrite-gid option to " "overwrite the GID" msgstr "" ". Comprobar GID del grupo existente. Use la opción --group-overwrite-gid " "para anular la GID" msgid "Invalid LDAP URI." msgstr " URI LDAP no válida." msgid "Migrate users and groups from DS to IPA." msgstr "Migrar usuarios y grupos de DS a IPA." msgid "LDAP URI" msgstr "LDAP URI" msgid "LDAP URI of DS server to migrate from" msgstr "LDAP URI del servidor DS desde donde realizar la migración" msgid "bind password" msgstr "asociar contraseña" msgid "Bind DN" msgstr "Asociar DN" msgid "User container" msgstr "Contenedor de usuario" msgid "Group container" msgstr "Contenedor de grupoi" msgid "User object class" msgstr "Clase de objeto de usuario" msgid "Group object class" msgstr "Clase de objeto de grupo" msgid "Ignore user object class" msgstr "Ignorar clase de objeto usuario" msgid "Ignore user attribute" msgstr "Ignorar atributo de usuario" msgid "Ignore group object class" msgstr "Ignorar clase de objeto grupo" msgid "Ignore group attribute" msgstr "Ignorar atributo de grupo" msgid "Overwrite GID" msgstr "Sobrescribir GID" msgid "" "When migrating a group already existing in IPA domain overwrite the group " "GID and report as success" msgstr "" "Cuando se migra un grupo que ya existe en el dominio IPA se sobrescribe el " "GID de grupo e informa como conseguido" msgid "LDAP schema" msgstr "Esquema LDAP" msgid "" "The schema used on the LDAP server. Supported values are RFC2307 and " "RFC2307bis. The default is RFC2307bis" msgstr "" "El esquema utilizado en el servidor LDAP. Los valores admitidos son RFC2307 " "y RFC2307bis. El valor predeterminado es RFC2307bis" msgid "Continue" msgstr "Continuar" msgid "" "Continuous operation mode. Errors are reported but the process continues" msgstr "" "Modo de funcionamiento continuo. Se reportan errores, pero el proceso " "continúa" msgid "Lists of objects migrated; categorized by type." msgstr "Lista de objetos migrados; clasificados por tipo." msgid "Lists of objects that could not be migrated; categorized by type." msgstr "Lista de objetos que no pueden ser migrados; categorizados por tipo." msgid "False if migration mode was disabled." msgstr "\"False\", si el modo de migración fue inhabilitado." msgid "" "search results for objects to be migrated\n" "have been truncated by the server;\n" "migration process might be incomplete\n" msgstr "" "los resultados de la búsqueda de los objetos que se van a migrar se han " "truncado por el servidor; el proceso de migración puede estar incompleto\n" msgid "Migration mode is disabled. Use 'ipa config-mod' to enable it." msgstr "" "El modo de migración se encuentra inhabilitado. Utilice 'ipa config-mod' " "para habilitarlo." msgid "" "Passwords have been migrated in pre-hashed format.\n" "IPA is unable to generate Kerberos keys unless provided\n" "with clear text passwords. All migrated users need to\n" "login at https://your.domain/ipa/migration/ before they\n" "can use their Kerberos accounts." msgstr "" "Las contraseñas han sido migradas en formato pre-hashed.\n" "IPA es incapaz de generar claves de Kerberos a menos que le sean\n" "provistas contraseñas de texto claras. Todos los usuarios migrados\n" "necesitan registrarse en https://your.domain/ipa/migration/ antes de\n" "poder utilizar sus respectivas cuentas Kerberos." msgid "" "\n" "Misc plug-ins\n" msgstr "" "\n" "Misc plug-ins\n" msgid "Show environment variables." msgstr "Mostrar variables de entorno." #, python-format msgid "%(count)d variables" msgstr "%(count)d variables" msgid "" "retrieve and print all attributes from the server. Affects command output." msgstr "" " Determinar si la ACI es un autoservicio de ACI y hacer una excepción " "si\n" " no lo es.\n" " Devolver el resultado si se trata de un autoservicio de ACI." msgid "Total number of variables env (>= count)" msgstr "Cantidad total de variables env (>= count)" msgid "Number of variables returned (<= total)" msgstr "Cantidad de variables devueltas (<= total)" msgid "Show all loaded plugins." msgstr "Mostrar todos los plugins cargados." #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "%(count)d complemento cargado" msgstr[1] "%(count)d complementos cargados" msgid "Number of plugins loaded" msgstr "Cantidad de complementos cargados" msgid "Member Host" msgstr "Miembro del equipo anfitrión" msgid "netgroup" msgstr "grupo de red" msgid "netgroups" msgstr "grupos de red" msgid "Netgroups" msgstr "Grupos de red" msgid "Netgroup" msgstr "Grupo de red" msgid "Netgroup name" msgstr "Nombre de grupo de red" msgid "Netgroup description" msgstr "Descripción del grupo de red" msgid "NIS domain name" msgstr "Nombre del dominio NIS" msgid "IPA unique ID" msgstr "ID unico de IPA" msgid "Add a new netgroup." msgstr "Añadir un nuevo grupo de red." #, python-format msgid "Added netgroup \"%(value)s\"" msgstr "\"%(value)s\"netgroup añadido" #, python-format msgid "" "hostgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" "grupo de host con nombre “%s†ya existe. Los grupos de nombres y los grupos " "de red comparten un espacio de nombre común" msgid "Delete a netgroup." msgstr "Borrar un grupo de red." #, python-format msgid "Deleted netgroup \"%(value)s\"" msgstr "%(value)s\" de netgroup eliminados" msgid "Modify a netgroup." msgstr "Modificar un grupo de red." #, python-format msgid "Modified netgroup \"%(value)s\"" msgstr "netgroup modificado \"%(value)s\"" msgid "Search for a netgroup." msgstr "Buscar un grupo de red." #, python-format msgid "%(count)d netgroup matched" msgid_plural "%(count)d netgroups matched" msgstr[0] "%(count)d autoservicio coincidente" msgstr[1] "%(count)d autoservicios coincidentes" msgid "search for managed groups" msgstr "buscar grupos gestionados" msgid "Display information about a netgroup." msgstr "Mostrar información sobre un grupo de red." msgid "Add members to a netgroup." msgstr "Añadir miembros a un grupo de red." msgid "Remove members from a netgroup." msgstr "Borrar miembros de un grupo de red." msgid "" "\n" "Set a user's password\n" "\n" "If someone other than a user changes that user's password (e.g., Helpdesk\n" "resets it) then the password will need to be changed the first time it\n" "is used. This is so the end-user is the only one who knows the password.\n" "\n" "The IPA password policy controls how often a password may be changed,\n" "what strength requirements exist, and the length of the password history.\n" "\n" "EXAMPLES:\n" "\n" " To reset your own password:\n" " ipa passwd\n" "\n" " To change another user's password:\n" " ipa passwd tuser1\n" msgstr "" "\n" "Establecer contraseña de un usuario\n" "\n" "Si alguien que no sea un usuario cambia la contraseña del usuario (por " "ejemplo, Servicio de Ayuda la restablece), entonces la contraseña tendrá que " "ser cambiada la primera vez que se utiliza. Esto es para que el usuario " "final sea el único que conoce la contraseña.\n" "La directiva de contraseñas IPA controla la frecuencia de cambio de una " "contraseña, los requisitos de fortaleza y longitud del historial de " "contraseñas. EJEMPLOS:\n" "Para restablecer su contraseña:\n" " ipa passwd tuser1\n" "\n" " Para cambiar la contraseña de otro usuario:\n" " ipa passwd tuser1\n" msgid "Set a user's password." msgstr "Fijar una contraseña de usuario." #, python-format msgid "Changed password for \"%(value)s\"" msgstr "Cambio de contraseña para \"%(value)s\"" msgid "" "\n" "Permissions\n" "\n" "A permission enables fine-grained delegation of rights. A permission is\n" "a human-readable form of a 389-ds Access Control Rule, or instruction " "(ACI).\n" "A permission grants the right to perform a specific task such as adding a\n" "user, modifying a group, etc.\n" "\n" "A permission may not contain other permissions.\n" "\n" "* A permission grants access to read, write, add or delete.\n" "* A privilege combines similar permissions (for example all the permissions\n" " needed to add a user).\n" "* A role grants a set of privileges to users, groups, hosts or hostgroups.\n" "\n" "A permission is made up of a number of different parts:\n" "\n" "1. The name of the permission.\n" "2. The target of the permission.\n" "3. The rights granted by the permission.\n" "\n" "Rights define what operations are allowed, and may be one or more\n" "of the following:\n" "1. write - write one or more attributes\n" "2. read - read one or more attributes\n" "3. add - add a new entry to the tree\n" "4. delete - delete an existing entry\n" "5. all - all permissions are granted\n" "\n" "Read permission is granted for most attributes by default so the read\n" "permission is not expected to be used very often.\n" "\n" "Note the distinction between attributes and entries. The permissions are\n" "independent, so being able to add a user does not mean that the user will\n" "be editable.\n" "\n" "There are a number of allowed targets:\n" "1. type: a type of object (user, group, etc).\n" "2. memberof: a member of a group or hostgroup\n" "3. filter: an LDAP filter\n" "4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a\n" " super-set of the \"type\" target.\n" "5. targetgroup: grant access to modify a specific group (such as granting\n" " the rights to manage group membership)\n" "\n" "EXAMPLES:\n" "\n" " Add a permission that grants the creation of users:\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Add a permission that grants the ability to manage group membership:\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgstr "" "\n" "Permisos\n" "\n" "Un permiso permite delegación de grano fino de derechos. Un permiso es una " "regla de control de acceso 389-ds o de instrucción (ACI).\n" "\n" "Un permiso otorga el derecho de realizar tareas tales como añadir un " "usuario, modificar un grupo, etc.\n" "Un permiso no puede contener otros permisos.\n" "Un permiso otorga acceso de lectura, escritura, agregar o borrar.\n" "Un privilegio combina permisos similares (por ejemplo, todos los permisos \n" " necesarios para agregar un usuario).\n" "Un rol otorga un set de privilegios para usuarios, grupos, hosts o " "hostgroups.\n" "Un permiso está compuesto de varias partes:\n" "\n" "1. El nombre del permiso.\n" "2. El destino del permiso.\n" "3. Los derechos otorgados por permiso.\n" "\n" "Los derechos definen las operaciones permitidas y pueden ser una o más de " "las siguientes.\n" "\n" "1. write - escribir uno o más atributos\n" "2. read - leer uno o más atributos\n" "3. add - agregar una nueva entrada al árbol\n" "4. delete - borrar una entrada existente\n" "5. all- todos los permisos son otorgados\n" "\n" "El permiso de lectura se otorga a la mayoría de los atributos y entradas. " "Los permisos son independientes, por lo tanto, poder agregar un usuario no " "significa que el usuario sea editable.\n" "Hay un número de destinos permitidos:\n" "1. type: un tipo de objeto (usuario, grupo, etc).\n" "2. memberof: un miembro de grupo o hostgroup\n" "3. filter: un filtro de LDAP \n" "4. subtree: un filtro LDAP que especifica parte del LDAP DIT. Es un\n" " super-set del \"type\" target.\n" "5. targetgroup: otorga acceso para modificar un grupo específico (tal como " "otorgar\n" " los derechos para administrar la membresía de grupo)\n" "EJEMPLOS:\n" "Añadir un permiso que otogue la creación de usuarios:\n" "\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "Añadir un permiso que otorgue la capacidad de administrar una membresía de " "grupo:\n" "\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group \n" "Members\"\n" msgid "Permission Type" msgstr "Tipo de permiso" msgid "permission" msgstr "permiso" msgid "permissions" msgstr "permisos" msgid "Permission name" msgstr "Nombre de permiso" msgid "" "Type of IPA object (user, group, host, hostgroup, service, netgroup, dns)" msgstr "" "Tipo de objeto del IPA (usuario, host, hostgroup, servicio, netgroup, dns)" msgid "Member of group" msgstr "Miembro del grupo" msgid "Target members of a group" msgstr "Objetivo para los miembros de un grupo" msgid "Subtree to apply permissions to" msgstr "Subárbol para aplicar permisos" msgid "User group to apply permissions to" msgstr "Grupo de usuario para aplicar permisos" msgid "Add a new permission." msgstr "Añadir un nuevo permiso." #, python-format msgid "Added permission \"%(value)s\"" msgstr "Permiso agregado \"%(value)s\"" msgid "Delete a permission." msgstr "Borrar un permiso." #, python-format msgid "Deleted permission \"%(value)s\"" msgstr "Permiso borrado \"%(value)s\"" msgid "Modify a permission." msgstr "Modificar un permiso." #, python-format msgid "Modified permission \"%(value)s\"" msgstr "Modificado el permiso \"%(value)s\"" msgid "Search for permissions." msgstr "Buscar permisos." #, python-format msgid "%(count)d permission matched" msgid_plural "%(count)d permissions matched" msgstr[0] "%(count)d permiso coincidente" msgstr[1] " %(count)d permisos coincidentes" msgid "Display information about a permission." msgstr "Mostrar información sobre un permiso." msgid "Ping a remote server." msgstr "Hacer ping a un servidor remoto." msgid "" "\n" "Kerberos pkinit options\n" "\n" "Enable or disable anonymous pkinit using the principal\n" "WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with\n" "pkinit support.\n" "\n" "EXAMPLES:\n" "\n" " Enable anonymous pkinit:\n" " ipa pkinit-anonymous enable\n" "\n" " Disable anonymous pkinit:\n" " ipa pkinit-anonymous disable\n" "\n" "For more information on anonymous pkinit see:\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgstr "" "\n" "Opciones de kerberos pkinit\n" "Activan o desactivan pkinit anónimo mediante el principal\n" "WELLKNOWN/ANONYMOUS@REALM. El servidor debe haber sido instalado con soporte " "pkinit.\n" "EJEMPLOS:\n" "Activar pkinit anónimo\n" " ipa pkinit-anonymous enable\n" "Desactivar pkinit anónimo:\n" " ipa pkinit-anonymous disable\n" "Para obtener mayor información sobre pkinit anónimo, por favor consulte: \n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" "\n" msgid "pkinit" msgstr "pkinit" msgid "PKINIT" msgstr "" " Los certificados de entrada deben estar codificados en DER. \n" " Tenga en cuenta que no puede ser un normalizador en la Param, ya que " "solamente las variables de \n" " Unicode se normalizan.\n" " " msgid "Enable or Disable Anonymous PKINIT." msgstr "Habilitar o Deshabilitar PKINIT Anónimo." msgid "" "\n" "Privileges\n" "\n" "A privilege combines permissions into a logical task. A permission provides\n" "the rights to do a single task. There are some IPA operations that require\n" "multiple permissions to succeed. A privilege is where permissions are\n" "combined in order to perform a specific task.\n" "\n" "For example, adding a user requires the following permissions:\n" " * Creating a new user entry\n" " * Resetting a user password\n" " * Adding the new user to the default IPA users group\n" "\n" "Combining these three low-level tasks into a higher level task in the\n" "form of a privilege named \"Add User\" makes it easier to manage Roles.\n" "\n" "A privilege may not contain other privileges.\n" "\n" "See role and permission for additional information.\n" msgstr "" "\n" "Privilegios\n" "Un privilegio combina permisos dentro de una tarea lógica. Un permiso " "proporciona\n" "los derechos para realizar una tarea específica.\n" "Por ejemplo, añadir un usuario requiere los siguientes permisos:\n" "Crear una nueva entradasd de usuario\n" "Restablecer una contraseña de usuario\n" "Añadir el nuevo usuario al grupo de usuario predeterminado de IPA\n" "Combinar estos tres niveles inferiores dentro de una tarea de nivel superior " "en forma de un privilegio \n" "denominado \"Add User\" facilita el manejo de roles.\n" "\n" "Un privilegio no puede contener otros privilegios.\n" "\n" "Ver el rol y el permiso para información adicional. \n" "\n" " \n" "\n" "\n" msgid "privilege" msgstr "privilegio" msgid "privileges" msgstr "privilegios" msgid "Privileges" msgstr " Objeto de servicio." msgid "Privilege" msgstr "Privilegio" msgid "Privilege name" msgstr " Añadir un nuevo servicio de la nueva IPA." msgid "Privilege description" msgstr "" " \n" " Eliminar un servicio de la IPA." msgid "Add a new privilege." msgstr "Añadir un nuevo privilegio." #, python-format msgid "Added privilege \"%(value)s\"" msgstr "Privilegio añadido \"%(value)s\"" msgid "Delete a privilege." msgstr "Borrar un privilegio." #, python-format msgid "Deleted privilege \"%(value)s\"" msgstr "Privilegio eliminado \"%(value)s \"" msgid "Modify a privilege." msgstr "Modificar un privilegio." #, python-format msgid "Modified privilege \"%(value)s\"" msgstr "Privilegio modificado \"%(value)s \"" msgid "Search for privileges." msgstr "Buscar privilegios." #, python-format msgid "%(count)d privilege matched" msgid_plural "%(count)d privileges matched" msgstr[0] "%(count)d privilegio coincidente" msgstr[1] "%(count)d privilegios coincidentes" msgid "Display information about a privilege." msgstr "Mostrar información sobre un privilegio." msgid "Add members to a privilege." msgstr "Añadir miembros a un privilegio." msgid "Add permissions to a privilege." msgstr "Añadir permisos a un privilegio." msgid "Number of permissions added" msgstr "Número de permisos añadidos" msgid "Remove permissions from a privilege." msgstr "Borrar permisos de un privilegio." msgid "Number of permissions removed" msgstr "Número de permisos eliminados" msgid "" "\n" "Password policy\n" "\n" "A password policy sets limitations on IPA passwords, including maximum\n" "lifetime, minimum lifetime, the number of passwords to save in\n" "history, the number of character classes required (for stronger passwords)\n" "and the minimum password length.\n" "\n" "By default there is a single, global policy for all users. You can also\n" "create a password policy to apply to a group. Each user is only subject\n" "to one password policy, either the group policy or the global policy. A\n" "group policy stands alone; it is not a super-set of the global policy plus\n" "custom settings.\n" "\n" "Each group password policy requires a unique priority setting. If a user\n" "is in multiple groups that have password policies, this priority determines\n" "which password policy is applied. A lower value indicates a higher priority\n" "policy.\n" "\n" "Group password policies are automatically removed when the groups they\n" "are associated with are removed.\n" "\n" "EXAMPLES:\n" "\n" " Modify the global policy:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Add a new group password policy:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Display the global password policy:\n" " ipa pwpolicy-show\n" "\n" " Display a group password policy:\n" " ipa pwpolicy-show localadmins\n" "\n" " Display the policy that would be applied to a given user:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modify a group password policy:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" msgstr "" "\n" "Política de contraseñas\n" "\n" "Una contraseña establece límites en contraseñas de IPA, incluyendo máxima y " "mínima duración, el número de contraseñas a guardar en historial, el número " "de clases de caracteresrequeridos (para contraseñas ás fuertes)\n" "y el mínimo de longitud de una contraseña.\n" "\n" "Por defecto es una única política global para todos los usuarios. También " "puede crear una política de contraseña para aplicar a un grupo. Cada usuario " "está sujeto solamente a una política de contraseña, ya sea de grupo o " "global. Una política de grupo es autónoma; no es uper-set de la política " "global mas los parámetros personalizados.\n" "Cada política de contraseña requiere una configuración única . Si un usuario " "está en varios grupos que tienen políticas de contraseñas, esta prioridad " "determina qué política de contraseña aplica. Un valor inferior indica una " "política de prioridad superior.\n" "\n" "Las políticas de contraseña de grupo se eliminan automáticamente cuando se " "eliminan los grupos a los cuales están asociados.\n" "\n" "EJEMPLOS:\n" "\n" " Modificar la política global:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Agregar una política de contraseña de nuevo grupo:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Mostrar una política de contraseña global:\n" " ipa pwpolicy-show\n" "\n" " Mostrar una política de contraseña de grupo:\n" " ipa pwpolicy-show localadmins\n" "\n" " Mostrar la política que sería aplicada al usuario dado:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modificar una polítca de contraseña de grupo:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" #, python-format msgid "priority must be a unique value (%(prio)d already used by %(gname)s)" msgstr "" "la prioridad debe ser un valor único (%(prio)d que ya esté siendo utilizado " "por %(gname)s)" msgid "password policy" msgstr "política de contraseña" msgid "password policies" msgstr "políticas de contraseña" msgid "Max failures" msgstr "Número máximo de fallas" msgid "Consecutive failures before lockout" msgstr "Fallos consecutivos antes del bloqueo" msgid "Failure reset interval" msgstr "Falló reajuste de intervalo" msgid "Period after which failure count will be reset (seconds)" msgstr "Período tras el cual se restablecerá (segundos) el conteo de errores" msgid "Lockout duration" msgstr "Duración de bloqueo" msgid "Period for which lockout is enforced (seconds)" msgstr "Período durante el cual se fuerza el bloqueo (segundos)" msgid "Password Policies" msgstr "Políticas de Contraseña" msgid "Group" msgstr "Grupo" msgid "Manage password policy for specific group" msgstr "Administra la política de contraseña de un grupo específico" msgid "Max lifetime (days)" msgstr "Vida máxima (días)" msgid "Maximum password lifetime (in days)" msgstr "Vida máxima de la contraseña (días)" msgid "Min lifetime (hours)" msgstr "Vida mínima (horas)" msgid "Minimum password lifetime (in hours)" msgstr "Vida mínima de la contraseña (en horas)" msgid "History size" msgstr "Tamaño del historial" msgid "Password history size" msgstr "Tamaño del historial de la contraseña" msgid "Character classes" msgstr "Clases de caracteres" msgid "Minimum number of character classes" msgstr "Cantidad mínima de clases de caracteres" msgid "Min length" msgstr "Longitud mínima" msgid "Minimum length of password" msgstr "Longitud mínima de la contraseña" msgid "Priority of the policy (higher number means lower priority" msgstr "" "Prioridad de la política (a mayor número corresponde una política menor)" msgid "Maximum password life must be greater than minimum." msgstr "La duración máxima de la contraseña debe ser mayor que la mínima." msgid "Add a new group password policy." msgstr "Añadir un nuevo grupo de política de contraseña." msgid "Delete a group password policy." msgstr "Borrar un grupo de política de contraseña." msgid "cannot delete global password policy" msgstr "no puede borrar la Política global de contraseña" msgid "Modify a group password policy." msgstr "Modificar un grupo de política de contraseña." msgid "priority cannot be set on global policy" msgstr "la prioridad no puede ser definida en una plítica global" msgid "Display information about password policy." msgstr "Mostrar información sobre la política de contraseña." msgid "Display effective policy for a specific user" msgstr "Ofrece la política efectiva para un determinado usuario" msgid "Search for group password policies." msgstr "Buscar grupo de políticas de contraseña." msgid "role" msgstr "rol" msgid "roles" msgstr "roles" msgid "Role" msgstr "Rol" msgid "Role name" msgstr "Nombre de rol" msgid "A description of this role-group" msgstr "Una descripción de este grupo de roles" msgid "Add a new role." msgstr "Añadir un nuevo rol." #, python-format msgid "Added role \"%(value)s\"" msgstr "Rol agregado \"%(value)s\"" msgid "Delete a role." msgstr "Borrar un rol." #, python-format msgid "Deleted role \"%(value)s\"" msgstr "Rol eliminado \"%(value)s\"" msgid "Modify a role." msgstr "Modificar un rol." #, python-format msgid "Modified role \"%(value)s\"" msgstr "Rol modificado \"%(value)s\"" msgid "Search for roles." msgstr "Buscar roles." #, python-format msgid "%(count)d role matched" msgid_plural "%(count)d roles matched" msgstr[0] "%(count)d rol coincidente" msgstr[1] "%(count)d roles coincidentes" msgid "Display information about a role." msgstr "Mostrar información sobre un rol." msgid "Add members to a role." msgstr "Añadir miembros a un rol." msgid "Remove members from a role." msgstr "Borrar miembros de un rol." msgid "Add privileges to a role." msgstr "Añadir privilegios a un rol." msgid "Number of privileges added" msgstr "Número de privilegios agregados" msgid "Remove privileges from a role." msgstr "Borrar privilegios de un rol." msgid "Number of privileges removed" msgstr "Número de privilegios eliminados" msgid "self service permission" msgstr "auto servicio de permiso" msgid "self service permissions" msgstr "auto servicio de permisos" msgid "Self Service Permissions" msgstr "Permisos de autoservicio" msgid "Self Service Permission" msgstr "Auto Servicio de Permiso" msgid "Self-service name" msgstr "Auto-servicio de nombres" msgid "Add a new self-service permission." msgstr "Añadir un nuevo auto servicio de permiso." #, python-format msgid "Added selfservice \"%(value)s\"" msgstr "Añadido autoservicio \"%(value)s\"" msgid "Delete a self-service permission." msgstr "Borrar un auto servicio de permiso." #, python-format msgid "Deleted selfservice \"%(value)s\"" msgstr "autoservicio eliminados \"%(value)s\"" msgid "Modify a self-service permission." msgstr "Modificar un auto servicio de permiso." #, python-format msgid "Modified selfservice \"%(value)s\"" msgstr "Autoservicio modificado \"%(value)s\"" msgid "Search for a self-service permission." msgstr "Buscar un auto servicio de permiso." #, python-format msgid "%(count)d selfservice matched" msgid_plural "%(count)d selfservices matched" msgstr[0] "%(count)d autoservicio coincidente" msgstr[1] "%(count)d autoservicios coincidentes" msgid "Display information about a self-service permission." msgstr "Mostrar información sobre un auto servicio de permiso." msgid "service" msgstr "servicio" msgid "services" msgstr "servicios" msgid "Service principal" msgstr " Búsqueda de servicios IPA" msgid "Add a new IPA new service." msgstr "Añadir un nuevo servicio nuevo IPA." #, python-format msgid "Added service \"%(value)s\"" msgstr "Ha sido agregado el servicio \"%(value)s\"" msgid "force principal name even if not in DNS" msgstr "fuerza el nombre del prinicpal, aún si no se encuentra en DNS" msgid "Delete an IPA service." msgstr "Borrar un servicio IPA." #, python-format msgid "Deleted service \"%(value)s\"" msgstr "Ha sido eliminado el servicio \"%(value)s\"" msgid "Modify an existing IPA service." msgstr "Modificar un servicio IPA existente." #, python-format msgid "Modified service \"%(value)s\"" msgstr "Ha sido modificado el servicio \"%(value)s\"" msgid "Search for IPA services." msgstr "Buscar servicios IPA." #, python-format msgid "%(count)d service matched" msgid_plural "%(count)d services matched" msgstr[0] "%(count)d servicio coincidente" msgstr[1] "%(count)d servicios coincidentes\t\t\t" msgid "Display information about an IPA service." msgstr "Mostrar información sobre un servicio IPA." msgid "Add hosts that can manage this service." msgstr "Añadir hosts que pueden gestionar este servicio." msgid "Remove hosts that can manage this service." msgstr "Borrar hosts que puedan gestionar este servicio." msgid "Disable the Kerberos key and SSL certificate of a service." msgstr "Deshabilitar la clave Kerberos y el certificado SSL de un servicio." #, python-format msgid "Disabled service \"%(value)s\"" msgstr "Servicio inhabilitado \"%(value)s\"" msgid "" "\n" "Sudo Commands\n" "\n" "Commands used as building blocks for sudo\n" "\n" "EXAMPLES:\n" "\n" " Create a new command\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Remove a command\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgstr "" "\n" "Comandos de Sudo\n" "\n" "Comandos usados como partes integrantes de sudo\n" "\n" "EJEMPLOS:\n" "\n" " Crear un comando nuevo\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Eliminar un comando\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgid "commands for controlling sudo configuration" msgstr "comandos para controlar la configuración sudo" msgid "sudo command" msgstr "comando sudo" msgid "sudo commands" msgstr "comandos sudo" msgid "Sudo Commands" msgstr "Comandos de sudo" msgid "Sudo Command" msgstr "Comando sudo " msgid "A description of this command" msgstr "Una descripción de este comando " msgid "Create new Sudo Command." msgstr "Crear un nuevo Comando Sudo." #, python-format msgid "Added Sudo Command \"%(value)s\"" msgstr "Añadido Comando Sudo “%(value)sâ€" msgid "Delete Sudo Command." msgstr "Borrar Comando Sudo." #, python-format msgid "Deleted Sudo Command \"%(value)s\"" msgstr "Borrado Comando Sudo “%(value)sâ€" msgid "Modify Sudo Command." msgstr "Modificar Comando Sudo." #, python-format msgid "Modified Sudo Command \"%(value)s\"" msgstr "Modificado Comando Sudo “%(value)sâ€" msgid "Search for Sudo Commands." msgstr "Buscar Comandos Sudo." #, python-format msgid "%(count)d Sudo Command matched" msgid_plural "%(count)d Sudo Commands matched" msgstr[0] "%(count)d Comando Sudo emparejado" msgstr[1] "%(count)d Comandos Sudo emparejados" msgid "Display Sudo Command." msgstr "Mostrar Comando Sudo." msgid "sudo command group" msgstr "grupo de comando sudo" msgid "sudo command groups" msgstr "grupos de comando sudo" msgid "Sudo Command Group" msgstr "Grupo de comando sudo" msgid "Create new Sudo Command Group." msgstr "Crear un nuevo Grupo de Comando Sudo." #, python-format msgid "Added Sudo Command Group \"%(value)s\"" msgstr "Añadido Grupo de Comando Sudo “%(value)sâ€" msgid "Delete Sudo Command Group." msgstr "Borrado Grupo de Comando Sudo." #, python-format msgid "Deleted Sudo Command Group \"%(value)s\"" msgstr "Borrado Grupo de Comando Sudo “%(value)sâ€" msgid "Modify Sudo Command Group." msgstr "Modificar Grupo de Comando Sudo." #, python-format msgid "Modified Sudo Command Group \"%(value)s\"" msgstr "Modificado Grupo de Comando Sudo “%(value)sâ€" msgid "Search for Sudo Command Groups." msgstr "Buscar Grupos de Comando Sudo." #, python-format msgid "%(count)d Sudo Command Group matched" msgid_plural "%(count)d Sudo Command Groups matched" msgstr[0] "%(count)d Grupo de Comando Sudo emparejado" msgstr[1] "%(count)d Grupos de Comando Sudo emparejados" msgid "Display Sudo Command Group." msgstr "Mostrar Grupo de Comando Sudo." msgid "Add members to Sudo Command Group." msgstr "Añadir miembros a Grupo de Comando Sudo." msgid "Remove members from Sudo Command Group." msgstr "Quitar miembros de un Grupo de Comando Sudo." msgid "Commands for controlling sudo configuration" msgstr "Comandos para controlar la configuración sudo" msgid "this option has been deprecated." msgstr "esta opción ha quedado obsoleta." msgid "sudo rule" msgstr "regla sudo" msgid "sudo rules" msgstr "reglas sudo" msgid "Sudo Rules" msgstr "Reglas Sudo" msgid "Sudo Rule" msgstr "Regla Sudo" msgid "Command category" msgstr "Categoría de comandos" msgid "Command category the rule applies to" msgstr "Categoría de comandos la regla se aplica a" msgid "RunAs User category" msgstr "Categoría de Usuario RunAs" msgid "RunAs User category the rule applies to" msgstr "RunAs Usuario categoría la regla aplica a " msgid "RunAs Group category" msgstr "RunAs Grupo categoría" msgid "RunAs Group category the rule applies to" msgstr "RunAs Grupo categoría la regla aplica a" msgid "Sudo Allow Commands" msgstr "Comandos Allow de sudo" msgid "Sudo Deny Commands" msgstr "Comandos Deny de sudo" msgid "Sudo Allow Command Groups" msgstr "Sudo Permitir Grupos de Comando" msgid "Sudo Deny Command Groups" msgstr "Sudo Denegar Grupos de Comandos" msgid "RunAs Users" msgstr "RunAs Usuarios" msgid "Run as a user" msgstr "Ejecutar como un usuario" msgid "Groups of RunAs Users" msgstr "Grupos de Usuarios RunAs" msgid "Run as any user within a specified group" msgstr "Ejecutar como cualquier usuario dentro de un grupo especificado" msgid "External User" msgstr "De usuarios externos" msgid "External User the rule applies to (sudorule-find only)" msgstr "Usuario Externo la regla aplica a (sudorule-find sólo)" msgid "RunAs External User" msgstr "RunAs de usuarios externos" msgid "External User the commands can run as (sudorule-find only)" msgstr "Usuario Externo los comandos pueden correr como (sudorule-find sólo)" msgid "RunAs External Group" msgstr "Grupo externo RunAs" msgid "External Group the commands can run as (sudorule-find only)" msgstr "Grupo Externo los comandos pueden correr como (sudorule-find sólo)" msgid "Sudo Option" msgstr "Opción de sudo" msgid "RunAs Groups" msgstr "Grupos RunAs" msgid "Run with the gid of a specified POSIX group" msgstr "Ejecutar con la gid de un grupo POSIX especificado" msgid "Create new Sudo Rule." msgstr "Crear nueva Regla Sudo." #, python-format msgid "Added Sudo Rule \"%(value)s\"" msgstr "Añadida Regla Sudo “%(value)sâ€" msgid "Delete Sudo Rule." msgstr "Borrar Regla Sudo." #, python-format msgid "Deleted Sudo Rule \"%(value)s\"" msgstr "Borrada Regla Sudo “%(value)sâ€" msgid "Modify Sudo Rule." msgstr "Modificar Regla Sudo." #, python-format msgid "Modified Sudo Rule \"%(value)s\"" msgstr "Regla Sudo Modificada “%(value)sâ€" msgid "Search for Sudo Rule." msgstr "Buscar Regla Sudo." #, python-format msgid "%(count)d Sudo Rule matched" msgid_plural "%(count)d Sudo Rules matched" msgstr[0] "%(count)d Regla Sudo emparejada" msgstr[1] "%(count)d Reglas Sudo emparejadas" msgid "Display Sudo Rule." msgstr "Mostrar Regla Sudo." msgid "Enable a Sudo Rule." msgstr "Habilitar Regla Sudo." #, python-format msgid "Enabled Sudo Rule \"%s\"" msgstr "Regla Sudo Habilitada “%sâ€" msgid "Disable a Sudo Rule." msgstr "Deshabilitar Regla Sudo." #, python-format msgid "Disabled Sudo Rule \"%s\"" msgstr "Regla Sudo Deshabilitada “%sâ€" msgid "Add commands and sudo command groups affected by Sudo Rule." msgstr "Añadir comandos y grupos de comando sudo afectados por Regla Sudo." msgid "Remove commands and sudo command groups affected by Sudo Rule." msgstr "Quitar comandos y grupos de comando sudo afectados por Regla Sudo." msgid "Add users and groups affected by Sudo Rule." msgstr "Añadir usuarios y grupos afectados por Regla Sudo." msgid "Remove users and groups affected by Sudo Rule." msgstr "Quitar usuarios y grupos afectados por Regla Sudo." msgid "Add hosts and hostgroups affected by Sudo Rule." msgstr "Añadir hosts y grupos de hosts afectados por Regla Sudo." msgid "Remove hosts and hostgroups affected by Sudo Rule." msgstr "Quitar hosts y grupos de hosts afectados por Regla Sudo." msgid "Add users and groups for Sudo to execute as." msgstr "Añadir usuarios y grupos para Sudo a ejecutar como." msgid "Remove users and groups for Sudo to execute as." msgstr "Quitar usuarios y grupos para Sudo a ejecutar como." msgid "Add group for Sudo to execute as." msgstr "Añadir grupo para Sudo a ejecutar como." msgid "Remove group for Sudo to execute as." msgstr "Quitar grupo para Sudo a ejecutar como." msgid "Add an option to the Sudo Rule." msgstr "Añadir una opción a la Regla Sudo." msgid "Remove an option from Sudo Rule." msgstr "Quitar una opción de la Regla Sudo." msgid "Realm name" msgstr "Nombre de reino " msgid "Kerberos keys available" msgstr "Claves Kerberos disponibles" msgid "user" msgstr "usuario" msgid "users" msgstr "usuarios" msgid "User login" msgstr "Ingreso de usuario" msgid "First name" msgstr "Nombre" msgid "Last name" msgstr "Apellido" msgid "Full name" msgstr "Nombre y apellidos" msgid "Display name" msgstr "Mostrar nombre" msgid "Initials" msgstr "Iniciales" msgid "Home directory" msgstr "Directorio principal" msgid "Login shell" msgstr "Shell de ingreso" msgid "Kerberos principal" msgstr "Principal kerberos" msgid "Email address" msgstr "Dirección de correo electrónico" msgid "Prompt to set the user password" msgstr "Solicita establecer la contraseña de usuario" msgid "UID" msgstr "UID" msgid "User ID Number (system will assign one if not provided)" msgstr "" "Número de ID de usuario (el sistema le asignará uno si no se indica ninguno)" msgid "Group ID Number" msgstr "Número de Identificación de Grupo" msgid "Street address" msgstr "Dirección postal" msgid "City" msgstr "Ciudad" msgid "State/Province" msgstr "Estado / Provincia" msgid "ZIP" msgstr "Zona " msgid "Telephone Number" msgstr "Número de teléfono" msgid "Mobile Telephone Number" msgstr "Número de teléfono celular" msgid "Pager Number" msgstr "Número de página" msgid "Fax Number" msgstr "Número de fx" msgid "Org. Unit" msgstr "Unidad. org" msgid "Job Title" msgstr "Cargo" msgid "Manager" msgstr "Manager" msgid "Car License" msgstr "Licencia de conducción" msgid "Account disabled" msgstr "Cuenta inhabilitada " #, python-format msgid "manager %(manager)s not found" msgstr "Administrador %(manager)s no encontrado" msgid "Add a new user." msgstr "Añadir un nuevo usuario." #, python-format msgid "Added user \"%(value)s\"" msgstr "Ha sido agregado el usuario \"%(value)s\"" msgid "Don't create user private group" msgstr "No crear grupo privado de usuario" #, python-format msgid "can be at most %(len)d characters" msgstr "puede ser a lo sumo%(len)d caracteres" msgid "Delete a user." msgstr "Borrar un usuario." #, python-format msgid "Deleted user \"%(value)s\"" msgstr "Ha sido eliminado el usuario \"%(value)s\"" msgid "Modify a user." msgstr "Modificar un usuario." #, python-format msgid "Modified user \"%(value)s\"" msgstr "Ha sido modificado el usuario \"%(value)s\"" msgid "Search for users." msgstr "Buscar usuarios." msgid "Self" msgstr "Self" msgid "Display user record for current Kerberos principal" msgstr "Muestra el registro del usuario para el principal de Kerberos actual" #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "%(count)d usuario coincidente" msgstr[1] "%(count)d usuarios coincidentes" msgid "Display information about a user." msgstr "Mostrar información sobre un usuario." msgid "Disable a user account." msgstr "Deshabilitar una cuenta de usuario." #, python-format msgid "Disabled user account \"%(value)s\"" msgstr " \"%(value)s\" de cuenta de usuario desactivada" msgid "Enable a user account." msgstr "Habilitar una cuenta de usuario." #, python-format msgid "Enabled user account \"%(value)s\"" msgstr " \"%(value)s\" de cuenta de usuario activada" msgid "" "\n" " Unlock a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator." msgstr "" "\n" "Desbloquear una cuenta de usuario\n" "\n" " Una cuenta de usuario puede llegar a bloquearse si la contraseña se ha " "introducido incorrectamente demasiadas\n" "veces dentro de un período de tiempo controlado por la política de\n" "contraseña. Una cuenta bloqueada es una condición temporal y puede ser " "desbloqueada por\n" "un administrador." #, python-format msgid "Unlocked account \"%(value)s\"" msgstr "Cuenta desbloqueada \" %(value)s \"" #, python-format msgid "Permission denied: %(file)s" msgstr "Permiso denegado:%(file)s " msgid "cannot be longer that 255 characters" msgstr "no puede ser más larga de 255 caracteres" msgid "too many '@' characters" msgstr "demasiados ‘@’ caracteres" #, python-format msgid "Issuer \"%(issuer)s\" does not match the expected issuer" msgstr "Emisor \"%(issuer)s\" no coincide con el emisor esperado " #, python-format msgid "objectclass %s not found" msgstr "clase objeto %s no encontrada" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "No es posible comunicarse con CMS (%s)" msgid "The hostname to register as" msgstr "El nombre del equipo a ser registrado como" msgid "The IPA realm" msgstr "El reinado IPA" msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "Plataforma de hardware del equipo (p. ej. Lenovo T61)" msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "Sistema operativo que utiliza el equipo y versión (p.ej. Fedora 9)" #, c-format msgid "cannot open configuration file %s\n" msgstr "no se puede abrir archivo de configuración %s\\n\n" #, c-format msgid "cannot stat() configuration file %s\n" msgstr "no puede stat () del archivo de configuración%s\n" #, c-format msgid "out of memory\n" msgstr "sin Memoria\n" #, c-format msgid "read error\n" msgstr "Error de lectura\n" #, c-format msgid "No keys accepted by KDC\n" msgstr "No hay claves aceptadas por KDC\n" #, c-format msgid "Out of memory \n" msgstr "¡Memoria insuficiente!\n" #, c-format msgid "Out of Memory!\n" msgstr "¡Memoria insuficiente!\n" #, c-format msgid "Failed to create control!\n" msgstr "¡Falló crear control!\n" #, c-format msgid "Unable to initialize ldap library!\n" msgstr "¡No puede iniciar biblioteca IDAP!\n" #, c-format msgid "Unable to set LDAP_OPT_X_SASL_NOCANON\n" msgstr "Incapaz de fijar LDAP_OPT_X_SASL_NOCANON \n" #, c-format msgid "Unable to set ldap options!\n" msgstr "¡No puede establecer opciones IDAP!\n" #, c-format msgid "Simple bind failed\n" msgstr "¡Falló vinculación sencilla!\n" #, c-format msgid "Operation failed! %s\n" msgstr "¡Falló operación! %s\n" #, c-format msgid "Missing reply control!\n" msgstr "¡Falta control de respuesta!\n" #, c-format msgid "ber_init() failed, Invalid control ?!\n" msgstr "Falló ber_init(), ¿control inválido?\n" msgid "New Principal Password" msgstr "Nueva contraseña principal" msgid "Verify Principal Password" msgstr "Verificar contraseña principal" msgid "Print as little as possible" msgstr "Imprimir lo mínimo posible" msgid "Output only on errors" msgstr "Solamente salida sobre errores" msgid "Contact this specific KDC Server" msgstr "Contactar este servidor KDC específico" msgid "Server Name" msgstr "Nombre de servidor" msgid "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)" msgstr "" "La principal para obtener una tabla de claves para (ex: ftp/ftp.example." "com@EXAMPLE.COM)" msgid "Kerberos Service Principal Name" msgstr "Nombre principal del servicio de kerberos" msgid "File were to store the keytab information" msgstr "Archivo para almacenar la información de tabla de claves" msgid "Keytab File Name" msgstr "Nombre de archivo de tabla de claves" msgid "Encryption types to request" msgstr "Solicitud de tipos de cifrado" msgid "Comma separated encryption types list" msgstr "Lista de tipos de cifrado separados por coma" msgid "Show the list of permitted encryption types and exit" msgstr "Mostrar la lista de los tipos cifrados permitidos y salir" msgid "Permitted Encryption Types" msgstr "Tipos de cifrado permitidos" msgid "Asks for a non-random password to use for the principal" msgstr "Pregunta por una contraseña no aleatoria para la principal" msgid "LDAP DN" msgstr "LDAP DN" msgid "DN to bind as if not using kerberos" msgstr "DN a vincular como si no usara kerberos" msgid "LDAP password" msgstr "Contraseña LDAP" msgid "password to use if not using kerberos" msgstr "Contraseña a usar si no usa kerberos" #, c-format msgid "Kerberos context initialization failed\n" msgstr "Inicio de contexto de kerberos falló\n" #, c-format msgid "No system preferred enctypes ?!\n" msgstr "¿Ningún sistema enctypes preferido?\n" #, c-format msgid "Supported encryption types:\n" msgstr "Tipos de cifrado suportado\n" #, c-format msgid "Warning: failed to convert type (#%d)\n" msgstr "Advertencia: Tipo para convertir falló (#%d)âŽ\n" #, c-format msgid "Bind password required when using a bind DN.\n" msgstr "Vincular contraseña requerida mediante un enlace DN.\n" #, c-format msgid "" "Warning: salt types are not honored with randomized passwords (see opt. -P)\n" msgstr "" "Advertencia: tipos salt no se aceptan con contraseñas aleatorias (ver opt.\n" #, c-format msgid "Invalid Service Principal Name\n" msgstr "Nombre de servicio principal inválido\n" #, c-format msgid "Kerberos Credential Cache not found. Do you have a Kerberos Ticket?\n" msgstr "" "No se encontró la cache de credencial kerberos. ¿Tiene un tiquete de " "kerberos?\n" #, c-format msgid "" "Kerberos User Principal not found. Do you have a valid Credential Cache?\n" msgstr "" "No se encontró usuario principal de kerberos. ¿Tiene una cache de credencial " "válida?\n" #, c-format msgid "Failed to open Keytab\n" msgstr "Fallo abrir clave de tablas.\n" #, c-format msgid "Failed to create key material\n" msgstr "Error al crear el material de clave\n" #, c-format msgid "Failed to add key to the keytab\n" msgstr "No se pudo agregar clave de la tabla de claves\n" #, c-format msgid "Failed to close the keytab\n" msgstr "No se pudo cerrar la tabla de claves\n" #, c-format msgid "Keytab successfully retrieved and stored in: %s\n" msgstr "Tabla de claves recuperada y almacenada correctamente en:%s\n" #, c-format msgid "No permission to join this host to the IPA domain.\n" msgstr "No tiene permiso para vincular este equipo al dominio de la API.\n" #, c-format msgid "No write permissions on keytab file '%s'\n" msgstr "No escribir permisos en archivo de tabla de claves'%s\n" #, c-format msgid "Out of memory!" msgstr "¡Memoria insuficiente!" #, c-format msgid "Unable to initialize connection to ldap server: %s" msgstr "No se puede iniciar con servidor IDAP:%s" #, c-format msgid "Unable to enable SSL in LDAP\n" msgstr "No se puede habilitar SSL en LDAP\n" #, c-format msgid "Unable to set LDAP version\n" msgstr "No se puede establecer la versión de LDAP\n" #, c-format msgid "Bind failed: %s\n" msgstr "Falló enlace:%s\n" #, c-format msgid "No values for %s" msgstr "No hay valores para %s" #, c-format msgid "Search for IPA namingContext failed with error %d\n" msgstr "Búsqueda de IPA namingContext fallada con error %d \n" #, c-format msgid "IPA namingContext not found\n" msgstr "IPA namingContext no encontrado \n" #, c-format msgid "Out of memory!\n" msgstr "¡Memoria insuficiente!\n" #, c-format msgid "Search for ipaCertificateSubjectBase failed with error %d" msgstr "Búsqueda de ipaCertificateSubjectBase falló con error %d" #, c-format msgid "Unable to determine root DN of %s\n" msgstr "No se puede determinar DN de root de%s\n" #, c-format msgid "Incorrect password.\n" msgstr "Contraseña incorrecta.\n" #, c-format msgid "Unable to determine certificate subject of %s\n" msgstr "No se puede determinar asunto del certificado de%s\n" #, c-format msgid "Enrollment failed. %s\n" msgstr "Inscripción fallada. %s\n" #, c-format msgid "principal not found in XML-RPC response\n" msgstr "principales no se encuentran en respuesta XML-RPC\n" #, c-format msgid "Host is already joined.\n" msgstr "Host ya está vinculado\n" #, c-format msgid "Unable to determine IPA server from %s\n" msgstr "No se puede determinar servidor de la IPA de%s\n" #, c-format msgid "The hostname must be fully-qualified: %s\n" msgstr "El nombre de host debe ser totalmente calificado:%s\n" #, c-format msgid "Unable to join host: Kerberos context initialization failed\n" msgstr "" "No se puede unir host: la inicialización de contexto de Kerberos falló\n" #, c-format msgid "Error resolving keytab: %s.\n" msgstr "Error al resolver tabla de claves:%s.\n" #, c-format msgid "Error getting default Kerberos realm: %s.\n" msgstr "Error al obtener el dominio predeterminado Kerberos:%s.\n" #, c-format msgid "Error obtaining initial credentials: %s.\n" msgstr "Error al obtener credenciales de iniciales:%s.\n" #, c-format msgid "Unable to generate Kerberos Credential Cache\n" msgstr "No se puede generar la cache de credenciales de Kerberos\n" #, c-format msgid "Error storing creds in credential cache: %s.\n" msgstr "Error de almacenamiento de credenciales en cache de credenciales:%s.\n" #, c-format msgid "Unenrollment successful.\n" msgstr "Cancelación de registro exitoso.\n" #, c-format msgid "Unenrollment failed.\n" msgstr "Cancelación falló.\n" #, c-format msgid "result not found in XML-RPC response\n" msgstr "resultado no se encuentra en respuesta XML-RPC\n" #, c-format msgid "Unable to join host: Kerberos Credential Cache not found\n" msgstr "" "No se puede unir host: cache de credenciales de Kerberos no se encuentra\n" #, c-format msgid "" "Unable to join host: Kerberos User Principal not found and host password not " "provided.\n" msgstr "" "No se puede unir host: principal de usuario no se encuentra y contraseña de " "host no se proporciona.\n" #, c-format msgid "fork() failed\n" msgstr "bifurcación () falló\n" #, c-format msgid "ipa-getkeytab not found\n" msgstr "ipa-getkeytab no se encuentra\n" #, c-format msgid "ipa-getkeytab has bad permissions?\n" msgstr "¿Tiene ipa-getkeytab permisos errados?\n" #, c-format msgid "executing ipa-getkeytab failed, errno %d\n" msgstr "la ejecución de ipa-getkeytab falló, errno %d\n" #, c-format msgid "child exited with %d\n" msgstr "hijo terminó con %d\n" #, c-format msgid "Certificate subject base is: %s\n" msgstr "Asunto de certificado es:%s\n" msgid "Print the raw XML-RPC output in GSSAPI mode" msgstr "Imprimir la salida cruda de XML-RPC en modo de GSSAPI" msgid "Quiet mode. Only errors are displayed." msgstr "Modo silencioso. Sólo se muestran los errores." msgid "Unenroll this host from IPA server" msgstr "Cancelar registro de host de servidor IPA" msgid "Hostname of this server" msgstr "Nombre de host de este servidor" msgid "hostname" msgstr "nombre de host" msgid "IPA Server to use" msgstr "Servidor de IPA a utilizar" msgid "Specifies where to store keytab information." msgstr "Especifica dónde almacenar la información de tabla de claves." msgid "filename" msgstr "nombre de archivo" msgid "LDAP password (if not using Kerberos)" msgstr "contraseña de LDAP (si no usa Kerberos)" msgid "password" msgstr "contraseña" msgid "LDAP basedn" msgstr "LDAP basedn" msgid "basedn" msgstr "basedn" #, c-format msgid "Unable to parse principal name\n" msgstr "No se puede analizar nombre principal\n" #, c-format msgid "Removing principal %s\n" msgstr "Eliminando %s principales\n" #, c-format msgid "Failed to open keytab\n" msgstr "No pudo abrir la tabla de claves\n" #, c-format msgid "principal not found\n" msgstr "principal no se encuentra\n" #, c-format msgid "Unable to remove entry\n" msgstr "No se puede eliminar la entrada\n" #, c-format msgid "kvno %d\n" msgstr "kvno %d\n" #, c-format msgid "Unable to parse principal\n" msgstr "No es posible analizar los principales\n" #, c-format msgid "realm not found\n" msgstr "reino no encontrado\n" msgid "Print debugging information" msgstr "Imprimir la información de depuración" msgid "Debugging output" msgstr "Salida de depuración" msgid "Remove all principals in this realm" msgstr "Quite todos los principales en este ámbito" #, c-format msgid "Closing keytab failed\n" msgstr "Cierre de tabla de claves falló\n" msgid "Out of memory!?\n" msgstr "" "¡Memoria insuficiente!\n" "\n" msgid "Out of memory\n" msgstr "¡Memoria insuficiente!\n" msgid "Enctype comparison failed!\n" msgstr "¡Falló comparación de Enctype!\n" msgid "Failed to create random key!\n" msgstr "Falló la creación de clave aleatoria\n" msgid "Failed to create key!\n" msgstr "¡Falló la creación de clave!\n" freeipa-3.3.4/install/po/de.po0000664000175000017500000000427512271663206015533 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Fabian Affolter , 2011 # Mario Blättermann , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: German \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: de\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "Geben Sie %(label)s zum Überprüfen ein:" #, c-format msgid "Passwords do not match!" msgstr "Passwörter stimmen nicht überein!" msgid "an internal error has occurred" msgstr "Ein interner Fehler ist aufgetreten" msgid "No credentials cache found" msgstr "Keine Anmeldeinformationen-Cache gefunden" msgid "Ticket expired" msgstr "Ticket abgelaufen" msgid "Passwords do not match" msgstr "Passwörter stimmen nicht überein" msgid "Command not implemented" msgstr "Befehl nicht implementiert" msgid "This entry already exists" msgstr "Dieser Eintrag existiert bereits" #, python-format msgid "Group '%s' does not exist" msgstr "Gruppe '%s' existiert nicht" msgid "ACIs" msgstr "ACIs" msgid "ACI name" msgstr "ACI-Namen" msgid "User group" msgstr "Benutzer-Gruppe" msgid "Permissions" msgstr "Berechtigungen" msgid "Attributes" msgstr "Attribute" msgid "Type" msgstr "Typ" msgid "Member of" msgstr "Mitglied von" msgid "Member of a group" msgstr "Mitglied einer Gruppe" msgid "Filter" msgstr "Filter" msgid "Location" msgstr "Ort" msgid "Map" msgstr "Karte" msgid "Key" msgstr "Key" msgid "Mount information" msgstr "Einhänge-Informationen" msgid "description" msgstr "Beschreibung" msgid "Certificate" msgstr "Zertifikat" msgid "Subject" msgstr "Betreff" msgid "Reason" msgstr "Grund" msgid "Error" msgstr "Fehler" msgid "Automount" msgstr "Automount" msgid "DNS" msgstr "DNS" freeipa-3.3.4/install/po/pygettext.py0000775000175000017500000006766712270466515017236 0ustar mkosekmkosek#! /usr/bin/python # -*- coding: iso-8859-1 -*- # Originally written by Barry Warsaw # # Minimally patched to make it even more xgettext compatible # by Peter Funk # # 2002-11-22 Jürgen Hermann # Added checks that _() only contains string literals, and # command line args are resolved to module lists, i.e. you # can now pass a filename, a module or package name, or a # directory (including globbing chars, important for Win32). # Made docstring fit in 80 chars wide displays using pydoc. # # 2010-06-12 Jan-Hendrik Göllner # Made it plural sensitive, added ngettext as default keyword. # Any keyworded function that is being supplied > 2 arguments # is treated like ngettext. # Also added support for constructs like "_('foo' + 10*'bar')" # by evaluating the whole expression. # Code like _(foo(arg1, arg2) + "bar") does not work by design # as that expression must be evaluated at runtime and this script # only extracts static strings known before runtime. # However it is possible to do things like # "ngettext('World', 'Worlds', numWorlds)" # as only the first two arguments are evaluated. # Advanced version number from 1.5 to 1.6 # # for selftesting try: #pylint: disable=F0401 import fintl _ = fintl.gettext except ImportError: _ = lambda s: s __doc__ = _("""pygettext -- Python equivalent of xgettext(1) Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the internationalization of C programs. Most of these tools are independent of the programming language and can be used from within Python programs. Martin von Loewis' work[1] helps considerably in this regard. There's one problem though; xgettext is the program that scans source code looking for message strings, but it groks only C (or C++). Python introduces a few wrinkles, such as dual quoting characters, triple quoted strings, and raw strings. xgettext understands none of this. Enter pygettext, which uses Python's standard tokenize module to scan Python source code, generating .pot files identical to what GNU xgettext[2] generates for C and C++ code. From there, the standard GNU tools can be used. A word about marking Python strings as candidates for translation. GNU xgettext recognizes the following keywords: gettext, dgettext, dcgettext, and gettext_noop. But those can be a lot of text to include all over your code. C and C++ have a trick: they use the C preprocessor. Most internationalized C source includes a #define for gettext() to _() so that what has to be written in the source is much less. Thus these are both translatable strings: gettext("Translatable String") _("Translatable String") Python of course has no preprocessor so this doesn't work so well. Thus, pygettext searches only for _() by default, but see the -k/--keyword flag below for how to augment this. [1] http://www.python.org/workshops/1997-10/proceedings/loewis.html [2] http://www.gnu.org/software/gettext/gettext.html NOTE: pygettext attempts to be option and feature compatible with GNU xgettext where ever possible. However some options are still missing or are not fully implemented. Also, xgettext's use of command line switches with option arguments is broken, and in these cases, pygettext just defines additional switches. Usage: pygettext [options] inputfile ... Options: -a --extract-all Extract all strings. -d name --default-domain=name Rename the default output file from messages.pot to name.pot. -E --escape Replace non-ASCII characters with octal escape sequences. -D --docstrings Extract module, class, method, and function docstrings. These do not need to be wrapped in _() markers, and in fact cannot be for Python to consider them docstrings. (See also the -X option). -h --help Print this help message and exit. -k word --keyword=word Keywords to look for in addition to the default set, which are: %(DEFAULTKEYWORDS)s You can have multiple -k flags on the command line. -K --no-default-keywords Disable the default set of keywords (see above). Any keywords explicitly added with the -k/--keyword option are still recognized. --no-location Do not write filename/lineno location comments. -n --add-location Write filename/lineno location comments indicating where each extracted string is found in the source. These lines appear before each msgid. The style of comments is controlled by the -S/--style option. This is the default. -o filename --output=filename Rename the default output file from messages.pot to filename. If filename is `-' then the output is sent to standard out. -p dir --output-dir=dir Output files will be placed in directory dir. -S stylename --style stylename Specify which style to use for location comments. Two styles are supported: Solaris # File: filename, line: line-number GNU #: filename:line The style name is case insensitive. GNU style is the default. -v --verbose Print the names of the files being processed. -V --version Print the version of pygettext and exit. -w columns --width=columns Set width of output to columns. -x filename --exclude-file=filename Specify a file that contains a list of strings that are not be extracted from the input files. Each string to be excluded must appear on a line by itself in the file. -X filename --no-docstrings=filename Specify a file that contains a list of files (one per line) that should not have their docstrings extracted. This is only useful in conjunction with the -D option above. If `inputfile' is -, standard input is read. """) import os import imp import sys import glob import time import getopt import token import tokenize __version__ = '1.6' default_keywords = ['_', 'ngettext'] DEFAULTKEYWORDS = ', '.join(default_keywords) EMPTYSTRING = '' # The normal pot-file header. msgmerge and Emacs's po-mode work better if it's # there. pot_header = _('''\ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR ORGANIZATION # FIRST AUTHOR , YEAR. # msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\\n" "POT-Creation-Date: %(time)s\\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" "Last-Translator: FULL NAME \\n" "Language-Team: LANGUAGE \\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=CHARSET\\n" "Content-Transfer-Encoding: ENCODING\\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n" "Generated-By: pygettext.py %(version)s\\n" ''') def usage(code, msg=''): print >> sys.stderr, __doc__ % globals() if msg: print >> sys.stderr, msg sys.exit(code) escapes = [] def make_escapes(pass_iso8859): global escapes if pass_iso8859: # Allow iso-8859 characters to pass through so that e.g. 'msgid # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we # escape any character outside the 32..126 range. mod = 128 else: mod = 256 for i in range(256): if 32 <= (i % mod) <= 126: escapes.append(chr(i)) else: escapes.append("\\%03o" % i) escapes[ord('\\')] = '\\\\' escapes[ord('\t')] = '\\t' escapes[ord('\r')] = '\\r' escapes[ord('\n')] = '\\n' escapes[ord('\"')] = '\\"' def escape(s): global escapes s = list(s) for i in range(len(s)): s[i] = escapes[ord(s[i])] return EMPTYSTRING.join(s) def safe_eval(s): # unwrap quotes, safely return eval(s, {'__builtins__':{}}, {}) def normalize(s): # This converts the various Python string types into a format that is # appropriate for .po files, namely much closer to C style. lines = s.split('\n') if len(lines) == 1: s = '"' + escape(s) + '"' else: if not lines[-1]: del lines[-1] lines[-1] = lines[-1] + '\n' for i in range(len(lines)): lines[i] = escape(lines[i]) lineterm = '\\n"\n"' s = '""\n"' + lineterm.join(lines) + '"' return s def containsAny(str, set): """Check whether 'str' contains ANY of the chars in 'set'""" return 1 in [c in str for c in set] def _visit_pyfiles(list, dirname, names): """Helper for getFilesForName().""" # get extension for python source files if not globals().has_key('_py_ext'): global _py_ext _py_ext = [triple[0] for triple in imp.get_suffixes() if triple[2] == imp.PY_SOURCE][0] # don't recurse into CVS directories if 'CVS' in names: names.remove('CVS') # add all *.py files to list list.extend( [os.path.join(dirname, file) for file in names if os.path.splitext(file)[1] == _py_ext] ) def _get_modpkg_path(dotted_name, pathlist=None): """Get the filesystem path for a module or a package. Return the file system path to a file for a module, and to a directory for a package. Return None if the name is not found, or is a builtin or extension module. """ # split off top-most name parts = dotted_name.split('.', 1) if len(parts) > 1: # we have a dotted path, import top-level package try: file, pathname, description = imp.find_module(parts[0], pathlist) if file: file.close() except ImportError: return None # check if it's indeed a package if description[2] == imp.PKG_DIRECTORY: # recursively handle the remaining name parts pathname = _get_modpkg_path(parts[1], [pathname]) else: pathname = None else: # plain name try: file, pathname, description = imp.find_module( dotted_name, pathlist) if file: file.close() if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]: pathname = None except ImportError: pathname = None return pathname def getFilesForName(name): """Get a list of module files for a filename, a module or package name, or a directory. """ if not os.path.exists(name): # check for glob chars if containsAny(name, "*?[]"): files = glob.glob(name) list = [] for file in files: list.extend(getFilesForName(file)) return list # try to find module or package name = _get_modpkg_path(name) if not name: return [] if os.path.isdir(name): # find all python files in directory list = [] os.path.walk(name, _visit_pyfiles, list) return list elif os.path.exists(name): # a single file return [name] return [] class TokenEater: def __init__(self, options): self.__options = options self.__messages = {} self.__state = self.__waiting self.__args = [] self.__lineno = -1 self.__freshmodule = 1 self.__curfile = None def __call__(self, ttype, tstring, stup, etup, line): # dispatch ## import token ## print >> sys.stderr, 'ttype:', token.tok_name[ttype], \ ## 'tstring:', tstring self.__state(ttype, tstring, stup[0]) def __waiting(self, ttype, tstring, lineno): opts = self.__options # Do docstring extractions, if enabled if opts.docstrings and not opts.nodocstrings.get(self.__curfile): # module docstring? if self.__freshmodule: if ttype == tokenize.STRING: try: s = safe_eval(tstring) except Exception as e: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: could not evaluate argument "%(arg)s"' ) % { 'arg': tstring, 'file': self.__curfile, 'lineno': self.__lineno } print >> sys.stderr, str(e) else: self.__addentry([s], lineno, isdocstring=1) self.__freshmodule = 0 elif ttype not in (tokenize.COMMENT, tokenize.NL): self.__freshmodule = 0 return # class docstring? if ttype == tokenize.NAME and tstring in ('class', 'def'): self.__state = self.__suiteseen return if ttype == tokenize.NAME and tstring in opts.keywords: self.__state = self.__keywordseen def __suiteseen(self, ttype, tstring, lineno): # ignore anything until we see the colon if ttype == tokenize.OP and tstring == ':': self.__state = self.__suitedocstring def __suitedocstring(self, ttype, tstring, lineno): # ignore any intervening noise if ttype == tokenize.STRING: try: s = safe_eval(tstring) except Exception as e: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: could not evaluate argument "%(arg)s"' ) % { 'arg': tstring, 'file': self.__curfile, 'lineno': self.__lineno } print >> sys.stderr, str(e) else: self.__addentry([s], lineno, isdocstring=1) self.__state = self.__waiting elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, tokenize.COMMENT): # there was no class docstring self.__state = self.__waiting def __keywordseen(self, ttype, tstring, lineno): if ttype == tokenize.OP and tstring == '(': self.__args = [''] self.__lineno = lineno self.__depth = 0 self.__state = self.__scanstring1 else: self.__state = self.__waiting def __scanstring1(self, ttype, tstring, lineno): # handle first argument, which is supposed to be a string. if ttype == tokenize.OP and tstring == ')': # End of list of arguments for the current function call. # If the argument list is empty (as in keyword()), ignore this call. # otherwise evaluate the fragments we collected as the first # argument and record its line number and update the list of # messages seen. Reset state for the next batch. if self.__args[-1]: try: s = safe_eval(self.__args[-1]) except Exception as e: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: could not evaluate argument "%(arg)s"' ) % { 'arg': self.__args[-1], 'file': self.__curfile, 'lineno': self.__lineno } print >> sys.stderr, str(e) self.__state = self.__waiting return if type(s) == str or type(s) == unicode: self.__args[-1] = s self.__addentry(self.__args) else: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: argument is no str or unicode object "%(arg)s"' ) % { 'arg': s, 'file': self.__curfile, 'lineno': self.__lineno } self.__state = self.__waiting elif ttype == tokenize.OP and tstring == ',': # Start of the next argument. try: s = safe_eval(self.__args[-1]) except Exception as e: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: could not evaluate argument "%(arg)s"' ) % { 'arg': self.__args[-1], 'file': self.__curfile, 'lineno': self.__lineno } print >> sys.stderr, str(e) self.__state = self.__waiting return if type(s) == str or type(s) == unicode: self.__args[-1] = s self.__args.append('') # next argument. self.__state = self.__scanstring2 else: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: argument 1 is no str or unicode object "%(arg)s"' ) % { 'arg': s, 'file': self.__curfile, 'lineno': self.__lineno } self.__state = self.__waiting else: # add string to current argument for later evaluation. # no state change in this case. self.__args[-1] += tstring def __scanstring2(self, ttype, tstring, lineno): # handle second argument, which is supposed to be a string. if ttype == tokenize.OP and tstring == ')': # End of list of arguments for the current function call. # This is an error if we expect either one or three arguments but # never two. print >> sys.stderr, _( '*** %(file)s:%(lineno)s: unexpected number of arguments (2)"' ) % { 'file': self.__curfile, 'lineno': self.__lineno } self.__state = self.__waiting elif ttype == tokenize.OP and tstring == ',': # Start of the next argument. We do not need to parse it, we only # made sure it is there and now we assume this is a plural call. try: s = safe_eval(self.__args[-1]) except Exception as e: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: could not evaluate argument "%(arg)s"' ) % { 'arg': self.__args[-1], 'file': self.__curfile, 'lineno': self.__lineno } print >> sys.stderr, str(e) self.__state = self.__waiting return s = safe_eval(self.__args[-1]) if type(s) == str or type(s) == unicode: self.__args[-1] = s self.__addentry(self.__args) self.__state = self.__waiting else: print >> sys.stderr, _( '*** %(file)s:%(lineno)s: argument 2 is no str or unicode object "%(arg)s"' ) % { 'arg': s, 'file': self.__curfile, 'lineno': self.__lineno } self.__state = self.__waiting else: # add string to current argument for later evaluation. # no state change in this case. self.__args[-1] += tstring def __addentry(self, args, lineno=None, isdocstring=0): isplural = 0 if len(args) > 1: isplural = 1 if lineno is None: lineno = self.__lineno exclude = 0 if args[0] in self.__options.toexclude: exclude = 1 if isplural: if args[1] not in self.__options.toexclude: # in case of plural, both strings must be in the toexclude list # to exclude this entry. exclude = 0 if not exclude: entry = (self.__curfile, lineno) # entries look like this: # {('arg1','arg2') : {(filename,lineno) : }, # ('arg1',) : {(filename,lineno) : }} # a key with len > 1 indicates plurals self.__messages.setdefault(tuple(args[0:2]), {})[entry] = isdocstring def set_filename(self, filename): self.__curfile = filename self.__freshmodule = 1 def write(self, fp): options = self.__options timestamp = time.strftime('%Y-%m-%d %H:%M+%Z') # The time stamp in the header doesn't have the same format as that # generated by xgettext... print >> fp, pot_header % {'time': timestamp, 'version': __version__} # Sort the entries. First sort each particular entry's keys, then # sort all the entries by their first item. reverse = {} for k, v in self.__messages.items(): keys = v.keys() keys.sort() reverse.setdefault(tuple(keys), []).append((k, v)) rkeys = reverse.keys() rkeys.sort() for rkey in rkeys: rentries = reverse[rkey] rentries.sort() for k, v in rentries: # If the entry was gleaned out of a docstring, then add a # comment stating so. This is to aid translators who may wish # to skip translating some unimportant docstrings. isdocstring = sum(v.values()) # k is the message string, v is a dictionary-set of (filename, # lineno) tuples. We want to sort the entries in v first by # file name and then by line number. v = v.keys() v.sort() if not options.writelocations: pass # location comments are different b/w Solaris and GNU: elif options.locationstyle == options.SOLARIS: for filename, lineno in v: d = {'filename': filename, 'lineno': lineno} print >>fp, _( '# File: %(filename)s, line: %(lineno)d') % d elif options.locationstyle == options.GNU: # fit as many locations on one line, as long as the # resulting line length doesn't exceeds 'options.width' locline = '#:' for filename, lineno in v: d = {'filename': filename, 'lineno': lineno} s = _(' %(filename)s:%(lineno)d') % d if len(locline) + len(s) <= options.width: locline = locline + s else: print >> fp, locline locline = "#:" + s if len(locline) > 2: print >> fp, locline if isdocstring: print >> fp, '#, docstring' print >> fp, 'msgid', normalize(k[0]) if len(k) > 1: print >> fp, 'msgid_plural', normalize(k[1]) print >> fp, 'msgstr[0] ""' print >> fp, 'msgstr[1] ""\n' else: print >> fp, 'msgstr ""\n' def main(): global default_keywords try: opts, args = getopt.getopt( sys.argv[1:], 'ad:DEhk:Kno:p:S:Vvw:x:X:', ['extract-all', 'default-domain=', 'escape', 'help', 'keyword=', 'no-default-keywords', 'add-location', 'no-location', 'output=', 'output-dir=', 'style=', 'verbose', 'version', 'width=', 'exclude-file=', 'docstrings', 'no-docstrings', ]) except getopt.error, msg: usage(1, msg) # for holding option values class Options: # constants GNU = 1 SOLARIS = 2 # defaults extractall = 0 # FIXME: currently this option has no effect at all. escape = 0 keywords = [] outpath = '' outfile = 'messages.pot' writelocations = 1 locationstyle = GNU verbose = 0 width = 78 excludefilename = '' docstrings = 0 nodocstrings = {} options = Options() locations = {'gnu' : options.GNU, 'solaris' : options.SOLARIS, } # parse options for opt, arg in opts: if opt in ('-h', '--help'): usage(0) elif opt in ('-a', '--extract-all'): options.extractall = 1 elif opt in ('-d', '--default-domain'): options.outfile = arg + '.pot' elif opt in ('-E', '--escape'): options.escape = 1 elif opt in ('-D', '--docstrings'): options.docstrings = 1 elif opt in ('-k', '--keyword'): options.keywords.append(arg) elif opt in ('-K', '--no-default-keywords'): default_keywords = [] elif opt in ('-n', '--add-location'): options.writelocations = 1 elif opt in ('--no-location',): options.writelocations = 0 elif opt in ('-S', '--style'): options.locationstyle = locations.get(arg.lower()) if options.locationstyle is None: usage(1, _('Invalid value for --style: %s') % arg) elif opt in ('-o', '--output'): options.outfile = arg elif opt in ('-p', '--output-dir'): options.outpath = arg elif opt in ('-v', '--verbose'): options.verbose = 1 elif opt in ('-V', '--version'): print _('pygettext.py (xgettext for Python) %s') % __version__ sys.exit(0) elif opt in ('-w', '--width'): try: options.width = int(arg) except ValueError: usage(1, _('--width argument must be an integer: %s') % arg) elif opt in ('-x', '--exclude-file'): options.excludefilename = arg elif opt in ('-X', '--no-docstrings'): fp = open(arg) try: while 1: line = fp.readline() if not line: break options.nodocstrings[line[:-1]] = 1 finally: fp.close() # calculate escapes make_escapes(options.escape) # calculate all keywords options.keywords.extend(default_keywords) # initialize list of strings to exclude if options.excludefilename: try: fp = open(options.excludefilename) options.toexclude = fp.readlines() fp.close() except IOError: print >> sys.stderr, _( "Can't read --exclude-file: %s") % options.excludefilename sys.exit(1) else: options.toexclude = [] # resolve args to module lists expanded = [] for arg in args: if arg == '-': expanded.append(arg) else: expanded.extend(getFilesForName(arg)) args = expanded # slurp through all the files eater = TokenEater(options) for filename in args: if filename == '-': if options.verbose: print _('Reading standard input') fp = sys.stdin closep = 0 else: if options.verbose: print _('Working on %s') % filename fp = open(filename) closep = 1 try: eater.set_filename(filename) try: tokenize.tokenize(fp.readline, eater) except tokenize.TokenError, e: print >> sys.stderr, '%s: %s, line %d, column %d' % ( e[0], filename, e[1][0], e[1][1]) finally: if closep: fp.close() # write the output if options.outfile == '-': fp = sys.stdout closep = 0 else: if options.outpath: options.outfile = os.path.join(options.outpath, options.outfile) fp = open(options.outfile, 'w') closep = 1 try: eater.write(fp) finally: if closep: fp.close() if __name__ == '__main__': main() # some more test strings _(u'a unicode string') # this one creates a warning _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} _('more' 'than' 'one' 'string') freeipa-3.3.4/install/po/cs.po0000664000175000017500000000162012271663206015537 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Petr Viktorin , 2013 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Czech (http://www.transifex.com/projects/p/fedora/language/" "cs/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "Operating system" msgstr "OperaÄní systém" msgid "User password" msgstr "Uživatelské heslo" freeipa-3.3.4/install/po/eu.po0000664000175000017500000002326612271663206015555 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Asier Iturralde Sarasola , 2012 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Basque (http://www.transifex.com/projects/p/fedora/language/" "eu/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: eu\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #, c-format msgid "Passwords do not match!" msgstr "Pasahitzak ez datoz bat!" msgid "Command name" msgstr "Komandoaren izena" msgid "an internal error has occurred" msgstr "barne-errore bat gertatu da" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "Baliogabeko JSON-RPC eskaera: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Kerberos errorea: %(major)s/%(minor)s" msgid "Passwords do not match" msgstr "Pasahitzak ez datoz bat" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "Sarrera hau dagoeneko existitzen da" #, python-format msgid "%(desc)s: %(info)s" msgstr "%(desc)s: %(info)s" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "A list of ACI values" msgstr "ACI balioen zerrenda bat" #, python-format msgid "Syntax Error: %(error)s" msgstr "Sintaxi-errorea: %(error)s" msgid "ACI prefix" msgstr "ACI aurrizkia" msgid "ACIs" msgstr "ACIak" msgid "ACI name" msgstr "ACI izena" msgid "Permission" msgstr "Baimena" msgid "User group" msgstr "Erabiltzaile-taldea" msgid "Permissions" msgstr "Baimenak" msgid "Attributes" msgstr "Atributuak" msgid "Type" msgstr "Mota" msgid "Filter" msgstr "Iragazkia" msgid "Subtree" msgstr "Azpi-zuhaitza" msgid "Target group" msgstr "Helburuko taldea" msgid "ACI" msgstr "ACI" msgid "New ACI name" msgstr "ACI izen berria" msgid "Description" msgstr "Deskribapena" msgid "description" msgstr "deskribapena" msgid "Password" msgstr "Pasahitza" msgid "External host" msgstr "Kanpoko ostalaria" msgid "entry" msgstr "sarrera" msgid "entries" msgstr "sarrerak" msgid "Rename" msgstr "Berrizendatu" #, python-format msgid "Rename the %(ldap_obj_name)s object" msgstr "%(ldap_obj_name)s objektua berrizendatu" msgid "Certificate" msgstr "Ziurtagiria" msgid "Subject" msgstr "Gaia" msgid "Fingerprint (MD5)" msgstr "Hatz-marka (MD5)" msgid "Fingerprint (SHA1)" msgstr "Hatz-marka (SHA1)" msgid "Serial number" msgstr "Serie-zenbakia" msgid "Output filename" msgstr "Irteerako fitxategi-izena" msgid "Reason" msgstr "Arrazoia" msgid "Error" msgstr "Errorea" msgid "Status" msgstr "Egoera" msgid "Configuration" msgstr "Konfigurazioa" msgid "Maximum username length" msgstr "Erabiltzaile-izenaren gehienezko luzera" msgid "Home directory base" msgstr "Direktorio nagusiaren oinarria" msgid "Default location of home directories" msgstr "Karpeta nagusien kokaleku lehenetsia" msgid "Default shell" msgstr "Shell lehenetsia" msgid "Default shell for new users" msgstr "Erabiltzaile berrientzako shell lehenetsia" msgid "Default users group" msgstr "Erabiltzaile-talde lehenetsia" msgid "Default group for new users" msgstr "Erabiltzaile berrientzako talde lehenetsia" msgid "Default e-mail domain" msgstr "E-posta domeinu lehenetsia" msgid "The group doesn't exist" msgstr "Taldea ez da existitzen" msgid "invalid IP address format" msgstr "IP helbide formatu baliogabea" msgid "invalid IP network format" msgstr "IP sare formatu baliogabea" msgid "Hostname" msgstr "Ostalari-izena" msgid "Administrator e-mail address" msgstr "Administratzailearen e-posta helbidea" msgid "Force" msgstr "Behartu" msgid "Class" msgstr "Klasea" msgid "group" msgstr "taldea" msgid "groups" msgstr "taldeak" msgid "User Groups" msgstr "Erabiltzaile-taldeak" msgid "User Group" msgstr "Erabiltzaile-taldea" msgid "Create a new group." msgstr "Sortu talde berri bat." msgid "Delete group." msgstr "Ezabatu taldea." msgid "Modify a group." msgstr "Aldatu talde bat." msgid "Search for groups." msgstr "Bilatu taldeak." msgid "HBAC rule" msgstr "HBAC araua" msgid "HBAC rules" msgstr "HBAC arauak" msgid "HBAC Rules" msgstr "HBAC arauak" msgid "Rule type" msgstr "Arau-mota" msgid "Enabled" msgstr "Gaituta" msgid "Users" msgstr "Erabiltzaileak" msgid "Hosts" msgstr "Ostalariak" msgid "Host Groups" msgstr "Ostalari-taldeak" msgid "Services" msgstr "Zerbitzuak" msgid "Service Groups" msgstr "Zerbitzu-taldeak" msgid "HBAC service" msgstr "HBAC zerbitzua" msgid "HBAC Services" msgstr "HBAC zerbitzuak" msgid "Service name" msgstr "Zerbitzuaren izena" msgid "HBAC service description" msgstr "HBAC zerbitzuaren deskribapena" msgid "Service group name" msgstr "Zerbitzu-taldearen izena" msgid "HBAC service group description" msgstr "HBAC zerbitzu-taldearen deskribapena" msgid "Serial Number" msgstr "Serie-zenbakia" msgid "Host name" msgstr "Ostalari-izena" msgid "A description of this host" msgstr "Ostalari honen deskribapena" msgid "Operating system" msgstr "Sistema eragilea" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "Ostalariaren sistema eragilea eta bertsioa (adibidez, \"Fedora 9\")" msgid "User password" msgstr "Erabiltzailearen pasahitza" msgid "Random password" msgstr "Ausazko pasahitza" #, python-format msgid "Added host \"%(value)s\"" msgstr "\"%(value)s\" ostalaria gehituta" #, python-format msgid "Deleted host \"%(value)s\"" msgstr "\"%(value)s\" ostalaria ezabatuta" #, python-format msgid "Modified host \"%(value)s\"" msgstr "\"%(value)s\" ostalaria aldatuta" msgid "Host-group" msgstr "Ostalari-taldea" msgid "Name of host-group" msgstr "Ostalari-taldearen izena" msgid "A description of this host-group" msgstr "Ostalari-talde honen deskribapena" #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "\"%(value)s\" ostalari-taldea gehituta" msgid "Add and Add Another" msgstr "Gehitu eta gehitu beste bat" msgid "Add and Close" msgstr "Gehitu eta itxi" msgid "Add and Edit" msgstr "Gehitu eta editatu" msgid "Add Many" msgstr "Gehitu hainbat" msgid "Cancel" msgstr "Utzi" msgid "Close" msgstr "Itxi" msgid "OK" msgstr "Ados" msgid "Retry" msgstr "Saiatu berriz" msgid "View" msgstr "Ikusi" msgid "General" msgstr "Orokorra" msgid "Settings" msgstr "Ezarpenak" msgid "Search" msgstr "Bilatu" msgid "Username" msgstr "Erabiltzaile-izena" msgid "Attribute" msgstr "Atributua" msgid "Fingerprints" msgstr "Hatz-markak" msgid "MD5 Fingerprint" msgstr "MD5 hatz-marka" msgid "New Certificate" msgstr "Ziurtagiri berria" msgid "Organization" msgstr "Erakundea" msgid "SHA1 Fingerprint" msgstr "SHA1 hatz-marka" msgid "Data" msgstr "Datuak" msgid "Group Settings" msgstr "Taldearen ezarpenak" msgid "Host Name" msgstr "Ostalari-izena" msgid "Set OTP" msgstr "Ezarri OTP" msgid "User" msgstr "Erabiltzailea" msgid "Groups" msgstr "Taldeak" msgid "Allow" msgstr "Onartu" msgid "Any Command" msgstr "Edozein komando" msgid "Any Group" msgstr "Edozein talde" msgid "Run Commands" msgstr "Exekutatu komandoak" msgid "Deny" msgstr "Ukatu" msgid "Specified Groups" msgstr "Zehazturiko taldeak" msgid "Account Settings" msgstr "Kontuaren ezarpenak" msgid "Contact Settings" msgstr "Kontaktuaren ezarpenak" msgid "New Password" msgstr "Pasahitz berria" msgid "Passwords must match" msgstr "Pasahitzek bat etorri behar dute" msgid "Reset Password" msgstr "Berrezarri pasahitza" msgid "Are you sure you want to delete selected entries?" msgstr "Ziur zaude hautatutako sarrerak ezabatu nahi dituzula?" msgid "DNS" msgstr "DNS" msgid "IPA Server" msgstr "IPA zerbitzaria" msgid "Sudo" msgstr "Sudo" msgid "Invalid LDAP URI." msgstr "LDAP URI baliogabea." msgid "NIS domain name" msgstr "NIS domeinu-izena" msgid "PKINIT" msgstr "PKINIT" msgid "Group" msgstr "Taldea" msgid "History size" msgstr "Historiaren tamaina" #, python-format msgid "Added service \"%(value)s\"" msgstr "\"%(value)s\" zerbitzua gehituta" #, python-format msgid "Deleted service \"%(value)s\"" msgstr "\"%(value)s\" zerbitzua ezabatuta" msgid "Sudo Commands" msgstr "Sudo komandoak" msgid "Sudo Command Group" msgstr "Sudo komando-taldea" msgid "External User" msgstr "Kanpoko erabiltzailea" msgid "RunAs External User" msgstr "Exekutatu kanpoko erabiltzaile bezala" msgid "RunAs External Group" msgstr "Exekutatu kanpoko talde bezala" msgid "Sudo Option" msgstr "Sudo aukera" msgid "First name" msgstr "Izena" msgid "Last name" msgstr "Abizena" msgid "Full name" msgstr "Izen osoa" msgid "Display name" msgstr "Bistaratu izena" msgid "Email address" msgstr "E-posta helbidea" msgid "UID" msgstr "UID" msgid "Street address" msgstr "Kalea" msgid "Telephone Number" msgstr "Telefono-zenbakia" msgid "Mobile Telephone Number" msgstr "Mugikor-zenbakia" msgid "Pager Number" msgstr "Bilagailu-zenbakia" msgid "Fax Number" msgstr "Fax-zenbakia" msgid "Manager" msgstr "Kudeatzailea" #, python-format msgid "Added user \"%(value)s\"" msgstr "\"%(value)s\" erabiltzailea gehituta" #, python-format msgid "Deleted user \"%(value)s\"" msgstr "\"%(value)s\" erabiltzailea ezabatuta" #, python-format msgid "Modified user \"%(value)s\"" msgstr "\"%(value)s\" erabiltzailea aldatuta" msgid "LDAP password" msgstr "LDAP pasahitza" #, c-format msgid "Incorrect password.\n" msgstr "Pasahitz okerra.\n" #, c-format msgid "ipa-getkeytab not found\n" msgstr "ez da ipa-getkeytab aurkitu\n" msgid "hostname" msgstr "ostalari-izena" msgid "IPA Server to use" msgstr "Erabili beharreko IPA zerbitzaria" msgid "filename" msgstr "fitxategi-izena" msgid "password" msgstr "pasahitza" freeipa-3.3.4/install/po/contributing_translators.txt0000664000175000017500000000071512202434255022474 0ustar mkosekmkosekbn_IN: Bengali India sankarshan mukhopadhyay es: Spanish Héctor Daniel Cabrera id: Indonesian Teguh DC kn: Kannada gundachandru pl: Polish Piotr DrÄ…g ru: Russian Andrew Martynov uk: Ukrainian Yuri Chornoivan zh_CN: Chinese Simplified Jake Li freeipa-3.3.4/install/po/bn_IN.po0000664000175000017500000000350212271663206016120 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # jdennis , 2011 # sankarshan mukhopadhyay , 2010 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Bengali (India) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: bn_IN\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Passwords do not match" msgstr "পাসওয়ারà§à¦¡ দà§à¦Ÿà¦¿ মিলছে না" msgid "This is already a posix group" msgstr "à¦à¦•টি পসিকà§à¦¸ (posix) গà§à¦°à§à¦ª আগে থেকে উপসà§à¦¥à¦¿à¦¤" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "incorrect type" msgstr "ভà§à¦² পà§à¦°à¦•ার" msgid "Only one value is allowed" msgstr "কেবলমাতà§à¦° à¦à¦•টি মান অনà§à¦®à¦¦à¦¿à¦¤" msgid "must be a decimal number" msgstr "à¦à¦•টি দশমিক সংখà§à¦¯à¦¾ হওয়া জরà§à¦°à¦¿" #, python-format msgid "%(count)d variables" msgstr "%(count)d ভেরিয়াবেল" #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "%(count)d পà§à¦²à¦¾à¦—-ইন লোড করা হয়েছে" msgstr[1] "%(count)d পà§à¦²à¦¾à¦—-ইন লোড করা হয়েছে" #, python-format msgid "Added user \"%(value)s\"" msgstr "\"%(value)s\" বà§à¦¯à¦¬à¦¹à¦¾à¦°à¦•ারী যোগ করা হয়েছে" freeipa-3.3.4/install/po/nl.po0000664000175000017500000000146012271663206015545 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Geert Warrink , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Dutch (http://www.transifex.com/projects/p/fedora/language/" "nl/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: nl\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #, c-format msgid "Passwords do not match!" msgstr "Wachtwoorden komen niet overheen!" freeipa-3.3.4/install/po/zh_CN.po0000664000175000017500000001575412271663206016150 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Jake Li , 2010 # jdennis , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Chinese (China) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: zh_CN\n" "Plural-Forms: nplurals=1; plural=0;\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "冿¬¡è¾“å…¥ %(label)s进行校验: " #, c-format msgid "Passwords do not match!" msgstr "密ç ä¸åŒ¹é…ï¼" msgid "an internal error has occurred" msgstr "å‘生了一个内部错误" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "无效的JSON-RPC请求: %(error)s" msgid "Passwords do not match" msgstr "密ç ä¸åŒ¹é…" msgid "Command not implemented" msgstr "命令没有实现" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "æ¡ç›®å·²ç»å­˜åœ¨" msgid "This command requires root access" msgstr "该命令需è¦root访问æƒé™" msgid "This is already a posix group" msgstr "è¿™å·²ç»æ˜¯ä¸€ä¸ªposix组" msgid "A group may not be a member of itself" msgstr "一个组ä¸èƒ½æ˜¯è‡ªå·±çš„æˆå‘˜" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Base64è§£ç å¤±è´¥: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "一个组ä¸èƒ½æ˜¯è‡ªå·±çš„æˆå‘˜" msgid "The default users group cannot be removed" msgstr "é»˜è®¤çš„ç”¨æˆ·ç»„ä¸æˆè¢«åˆ é™¤" msgid "change collided with another change" msgstr "修改冲çª" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "Results are truncated, try a more specific search" msgstr "结果被截断,请å°è¯•更明确的æœç´¢" msgid "incorrect type" msgstr "䏿­£ç¡®çš„类型" msgid "Only one value is allowed" msgstr "åªå…许一个值" msgid "must be True or False" msgstr "必须是True或False" msgid "must be an integer" msgstr "必须是一个整数" msgid "must be a decimal number" msgstr "必须是一个å进制数" msgid "must be binary data" msgstr "必须是二进制数æ®" msgid "must be Unicode text" msgstr "必须是Unicode文本" #, python-format msgid "Group '%s' does not exist" msgstr "组 '%s' ä¸å­˜åœ¨" msgid "ACIs" msgstr "ACIs" msgid "ACI name" msgstr "ACIåç§°" msgid "User group" msgstr "用户组" msgid "Permissions" msgstr "æƒé™" msgid "Attributes" msgstr "属性" msgid "Type" msgstr "类型" msgid "Member of a group" msgstr "组æˆå‘˜" msgid "Filter" msgstr "过滤" msgid "Subtree" msgstr "å­æ ‘" msgid "Target group" msgstr "目标组" msgid "Description" msgstr "æè¿°" msgid "Location" msgstr "ä½ç½®" msgid "description" msgstr "æè¿°" msgid "Mount point" msgstr "挂载点" msgid "Password" msgstr "密ç " msgid "Failed members" msgstr "失败的æˆå‘˜" msgid "Member users" msgstr "æˆå‘˜ç”¨æˆ·" msgid "Member groups" msgstr "æˆå‘˜ç»„" msgid "Member hosts" msgstr "æˆå‘˜ä¸»æœº" msgid "Member host-groups" msgstr "主机组æˆå‘˜" msgid "Member of host-groups" msgstr "主机组æˆå‘˜" msgid "External host" msgstr "外部主机" msgid "Certificate" msgstr "è¯ä¹¦" msgid "Subject" msgstr "主题" msgid "Serial number" msgstr "åºåˆ—å·" msgid "Request id" msgstr "请求å·" msgid "Request status" msgstr "请求状æ€" msgid "Revocation reason" msgstr "撤消原因" msgid "Revoked" msgstr "撤销" msgid "Reason" msgstr "原因" msgid "Reason for revoking the certificate (0-10)" msgstr "撤消è¯ä¹¦çš„原因(0-10)" msgid "Error" msgstr "错误" msgid "Home directory base" msgstr "主目录" msgid "Default shell" msgstr "默认shell" msgid "Default users group" msgstr "默认用户组" msgid "Search time limit" msgstr "æœç´¢æ—¶é—´é™åˆ¶" msgid "User search fields" msgstr "用户æœç´¢å­—段" msgid "Priority" msgstr "优先级" msgid "User Groups" msgstr "用户组" msgid "Group name" msgstr "组å" msgid "Group description" msgstr "组æè¿°" msgid "GID" msgstr "GID" #, python-format msgid "Added group \"%(value)s\"" msgstr "已添加组\"%(value)s\"" #, python-format msgid "Deleted group \"%(value)s\"" msgstr "已删除组\"%(value)s\"" #, python-format msgid "Modified group \"%(value)s\"" msgstr "已修改组\"%(value)s\"" msgid "Rule name" msgstr "规则å" msgid "User category" msgstr "用户类别" msgid "Host category" msgstr "主机类别" msgid "Users" msgstr "用户" msgid "Hosts" msgstr "主机" msgid "Host Groups" msgstr "主机组" msgid "Services" msgstr "æœåŠ¡" msgid "Access time" msgstr "访问时间" msgid "Service name" msgstr "æœåŠ¡å" msgid "User name" msgstr "用户å" msgid "Host name" msgstr "主机å" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "主机地点(如\"Baltimore, MD\")" msgid "Host location (e.g. \"Lab 2\")" msgstr "主机ä½ç½®(如\"Lab 2\")" msgid "Platform" msgstr "å¹³å°" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "ä¸»æœºç¡¬ä»¶å¹³å° (e.g. \"Lenovo T61\")" msgid "Operating system" msgstr "æ“作系统" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "主机æ“作系统åŠç‰ˆæœ¬(e.g. \"Fedora 9\")" msgid "User password" msgstr "用户密ç " msgid "Base-64 encoded server certificate" msgstr "Base-64 ç¼–ç æ ¼å¼çš„æœåŠ¡å™¨è¯ä¹¦" #, python-format msgid "Added host \"%(value)s\"" msgstr "新增主机 \"%(value)s\"" #, python-format msgid "Deleted host \"%(value)s\"" msgstr "已删除主机 \"%(value)s\"" #, python-format msgid "Modified host \"%(value)s\"" msgstr "已修改主机 \"%(value)s\"" msgid "Host-group" msgstr "主机组" msgid "Name of host-group" msgstr "主机组åç§°" msgid "Data" msgstr "æ•°æ®" msgid "User" msgstr "用户" msgid "Groups" msgstr "用户组" msgid "DNS" msgstr "DNS" msgid "LDAP URI" msgstr "LDAP URI" msgid "User container" msgstr "用户容器" msgid "Group container" msgstr "组容器" msgid "Netgroups" msgstr "网络组" msgid "Netgroup name" msgstr "网络组åç§°" msgid "Netgroup description" msgstr "网络组æè¿°" msgid "NIS domain name" msgstr "NIS域å" msgid "Group" msgstr "组" msgid "Min length" msgstr "最å°é•¿åº¦" msgid "A description of this role-group" msgstr "该角色组的æè¿°" msgid "User login" msgstr "用户登录å" msgid "First name" msgstr "å" msgid "Last name" msgstr "å§“" msgid "Login shell" msgstr "登录shell" msgid "Email address" msgstr "邮件地å€" msgid "UID" msgstr "UID" msgid "Street address" msgstr "è¡—é“地å€" #, python-format msgid "Added user \"%(value)s\"" msgstr "新增用户\"%(value)s\"" #, python-format msgid "Deleted user \"%(value)s\"" msgstr "已删除用户\"%(value)s\"" #, python-format msgid "Modified user \"%(value)s\"" msgstr "已修改用户\"%(value)s\"" freeipa-3.3.4/install/po/ca.po0000664000175000017500000002011312271663206015513 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # jordimash , 2013 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Catalan \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: ca\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" msgid "Passwords do not match" msgstr "Les contrasenyes no coincideixen" msgid "Command not implemented" msgstr "No s'ha implementat l'ordre" msgid "Permission" msgstr "Permís" msgid "Permissions" msgstr "Permisos" msgid "Attributes" msgstr "Atributs" msgid "Type" msgstr "Tipus" msgid "Filter" msgstr "Filtre" msgid "Subtree" msgstr "Subarbre" msgid "Description" msgstr "Descripció" msgid "Location" msgstr "Ubicació" msgid "Map" msgstr "Mapa" msgid "Key" msgstr "Tecla" msgid "description" msgstr "descripció" msgid "Mount point" msgstr "Punt de muntatge" msgid "Password" msgstr "Contrasenya" msgid "entry" msgstr "entrada" msgid "Rights" msgstr "Drets" msgid "Rename" msgstr "Canvia el nom" msgid "Certificate" msgstr "Certificat" msgid "Subject" msgstr "Assumpte" msgid "Issuer" msgstr "Emissor" msgid "Not Before" msgstr "No abans" msgid "Not After" msgstr "No després" msgid "Serial number" msgstr "Número de sèrie" msgid "Revoked" msgstr "Revocat" msgid "Reason" msgstr "Raó" msgid "Error" msgstr "Error" msgid "Status" msgstr "Estat" msgid "Configuration" msgstr "Configuració" msgid "IP Address" msgstr "Adreça IP" msgid "Subtype" msgstr "Subtipus" msgid "Hostname" msgstr "Nom de l'ordinador" msgid "Algorithm" msgstr "Algorisme" msgid "Target" msgstr "Objectiu" msgid "Flags" msgstr "Indicadors" msgid "Protocol" msgstr "Protocol" msgid "Public Key" msgstr "Clau pública" msgid "Size" msgstr "Mida" msgid "Regular Expression" msgstr "Expressió regular" msgid "Priority" msgstr "Prioritat" msgid "Weight" msgstr "Pes" msgid "Port" msgstr "Port" msgid "Labels" msgstr "Etiquetes" msgid "Signature" msgstr "Signatura" msgid "Fingerprint" msgstr "Empremta" msgid "Force" msgstr "Força" msgid "Class" msgstr "Classe" msgid "group" msgstr "grup" msgid "Group name" msgstr "Nom del grup" msgid "Enabled" msgstr "S'ha habilitat" msgid "Users" msgstr "Usuaris" msgid "Services" msgstr "Serveis" msgid "Access time" msgstr "Temps d'accés" msgid "Warning" msgstr "Avís" msgid "User name" msgstr "Nom d'usuari" msgid "Serial Number" msgstr "Número de sèrie" msgid "Host" msgstr "Ordinador central" msgid "Host name" msgstr "Nom de l'amfitrió" msgid "Locality" msgstr "Localitat" msgid "Platform" msgstr "Plataforma" msgid "Operating system" msgstr "Sistema operatiu" msgid "Apply" msgstr "Aplica" msgid "Actions" msgstr "Accions" msgid "Add" msgstr "Afegeix-ho" msgid "Back" msgstr "Enrere" msgid "Cancel" msgstr "Cancel·la" msgid "Close" msgstr "Tanca" msgid "Disable" msgstr "Inhabilita" msgid "Edit" msgstr "Edita" msgid "Enable" msgstr "Habilita" msgid "Find" msgstr "Cerca" msgid "OK" msgstr "D'acord" msgid "Refresh" msgstr "Refresca" msgid "Delete" msgstr "Suprimeix" msgid "Reset" msgstr "Reinicia" msgid "Restore" msgstr "Restaura" msgid "Retry" msgstr "Reintent" msgid "Revoke" msgstr "Revoca" msgid "Set" msgstr "Aplica" msgid "Update" msgstr "Actualització" msgid "View" msgstr "Visualització" msgid "General" msgstr "General" msgid "Identity Settings" msgstr "Paràmetres de la identitat" msgid "Available" msgstr "Disponible" msgid "Confirmation" msgstr "Confirmació" msgid "Unsaved Changes" msgstr "Canvis sense desar" msgid "Show details" msgstr "Mostra els detalls" msgid "Unknown Error" msgstr "Error desconegut" msgid "URL" msgstr "URL" msgid "Settings" msgstr "Paràmetres" msgid "Search" msgstr "Cerca" msgid "False" msgstr "Fals" msgid "Login" msgstr "Entra" msgid "Logout" msgstr "Surt" msgid "Username" msgstr "Nom d'usuari" msgid "seconds" msgstr "segons" msgid "Attribute" msgstr "Atribut" msgid "Add Rule" msgstr "Afegeix una regla" msgid "Exclusive" msgstr "Exclusiu" msgid "Expression" msgstr "Expressió" msgid "Affiliation Changed" msgstr "L'afiliació ha canviat" msgid "CA Compromise" msgstr "CA en compromís" msgid "Certificates" msgstr "Certificats" msgid "Certificate Hold" msgstr "Retenció del certificat" msgid "Cessation of Operation" msgstr "Cessació de l'operació" msgid "Common Name" msgstr "Nom comú" msgid "Expires On" msgstr "Data de venciment" msgid "Fingerprints" msgstr "Empremtes digitals" msgid "Issued By" msgstr "Emès per" msgid "Issued On" msgstr "Data d'emissió" msgid "Issued To" msgstr "Emès a nom de" msgid "Key Compromise" msgstr "Clau en compromís" msgid "MD5 Fingerprint" msgstr "Empremta digital MD5" msgid "Note" msgstr "Nota" msgid "Organization" msgstr "Organització" msgid "Organizational Unit" msgstr "Unitat organitzativa" msgid "SHA1 Fingerprint" msgstr "Empremta digital SHA1" msgid "Superseded" msgstr "Substituït" msgid "Unspecified" msgstr "Sense especificar" msgid "Validity" msgstr "Validesa" msgid "Options" msgstr "Opcions" msgid "Data" msgstr "Dades" msgid "Record Type" msgstr "Tipus de registre" msgid "External" msgstr "Extern" msgid "Normal" msgstr "Normal" msgid "Anyone" msgstr "Qualsevol" msgid "Who" msgstr "Qui" msgid "Access Denied" msgstr "S'ha denegat l'accés" msgid "Access Granted" msgstr "Accés permès" msgid "Matched" msgstr "Coincideix" msgid "Rules" msgstr "Regles" msgid "Unmatched" msgstr "No coincideix" msgid "Host Name" msgstr "Nom de l'ordinador" msgid "User" msgstr "Usuari" msgid "Identity" msgstr "Identitat" msgid "Active Directory domain" msgstr "Domini d'Active Directory" msgid "Modified" msgstr "Modificat" msgid "Groups" msgstr "Grups" msgid "Commands" msgstr "Ordres" msgid "Allow" msgstr "Permet" msgid "Account" msgstr "Compte" msgid "Domain" msgstr "Domini" msgid "Account Settings" msgstr "Paràmetres dels comptes" msgid "Mailing Address" msgstr "Adreça postal" msgid "New Password" msgstr "Contrasenya nova" msgid "Reset Password" msgstr "Reinicia la contrasenya" msgid "Select All" msgstr "Selecciona-ho tot" msgid "Unselect All" msgstr "No seleccionis res" msgid "Disabled" msgstr "Inhabilitat" msgid "DNS" msgstr "DNS" msgid "Policy" msgstr "Política" msgid "True" msgstr "Cert" msgid "Next" msgstr "Següent" msgid "Page" msgstr "Pàgina" msgid "Prev" msgstr "Anterior" msgid "undo" msgstr "desfés" msgid "Continue" msgstr "Continua" msgid "Netgroup name" msgstr "Nom de grup de xarxa" msgid "Invalid credentials" msgstr "Credencials no vàlides" msgid "permissions" msgstr "permisos" msgid "Group" msgstr "Grup" msgid "Role" msgstr "Rol" msgid "services" msgstr "serveis" msgid "Unknown" msgstr "Desconegut" msgid "Trust" msgstr "Confiança" msgid "Server" msgstr "Servidor" msgid "Time now" msgstr "L'hora actual" msgid "user" msgstr "usuari" msgid "users" msgstr "usuaris" msgid "User login" msgstr "Entrada" msgid "First name" msgstr "Nom" msgid "Last name" msgstr "Cognom" msgid "Full name" msgstr "Nom complet" msgid "Initials" msgstr "Inicials" msgid "Home directory" msgstr "Directori de l'usuari" msgid "Login shell" msgstr "Intèrpret d'ordres de l'inici de sessió" msgid "Email address" msgstr "Adreça de correu electrònic" msgid "UID" msgstr "UID" msgid "City" msgstr "Ciutat" msgid "State/Province" msgstr "Estat/província" msgid "Telephone Number" msgstr "Número de telèfon" msgid "Pager Number" msgstr "Número de buscapersones" msgid "Fax Number" msgstr "Número de fax" msgid "Job Title" msgstr "Càrrec" msgid "Manager" msgstr "Gestor" msgid "Self" msgstr "Ell mateix" msgid "Server Name" msgstr "Nom del servidor" msgid "filename" msgstr "nomdelfitxer" msgid "password" msgstr "contrasenya" msgid "Debugging output" msgstr "Sortida de depuració" msgid "Out of memory\n" msgstr "Sense memòria\n" freeipa-3.3.4/install/po/ipa.pot0000664000175000017500000100132512271663206016072 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: ipa\n" "Report-Msgid-Bugs-To: https://hosted.fedoraproject.org/projects/freeipa/" "newticket\n" "POT-Creation-Date: 2013-09-26 10:57+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: ipalib/cli.py:593 #, python-format msgid "Enter %(label)s again to verify: " msgstr "" #: ipalib/cli.py:601 ipa-client/ipa-getkeytab.c:420 #, c-format msgid "Passwords do not match!" msgstr "" #: ipalib/cli.py:624 msgid "No matching entries found" msgstr "" #: ipalib/cli.py:668 msgid "Topic or Command" msgstr "" #: ipalib/cli.py:669 msgid "The topic or command name." msgstr "" #: ipalib/cli.py:833 msgid "Topic commands:" msgstr "" #: ipalib/cli.py:838 msgid "To get command help, use:" msgstr "" #: ipalib/cli.py:839 msgid " ipa --help" msgstr "" #: ipalib/cli.py:848 msgid "Command name" msgstr "" #: ipalib/cli.py:998 msgid "Positional arguments" msgstr "" #: ipalib/cli.py:1254 msgid "No file to read" msgstr "" #: ipalib/errors.py:269 #, python-format msgid "%(cver)s client incompatible with %(sver)s server at '%(server)s'" msgstr "" #: ipalib/errors.py:287 #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "" #: ipalib/errors.py:303 msgid "an internal error has occurred" msgstr "" #: ipalib/errors.py:325 #, python-format msgid "an internal error has occurred on server at '%(server)s'" msgstr "" #: ipalib/errors.py:341 #, python-format msgid "unknown command '%(name)s'" msgstr "" #: ipalib/errors.py:358 ipalib/errors.py:383 #, python-format msgid "error on server '%(server)s': %(error)s" msgstr "" #: ipalib/errors.py:374 #, python-format msgid "cannot connect to '%(uri)s': %(error)s" msgstr "" #: ipalib/errors.py:392 #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "" #: ipalib/errors.py:408 #, python-format msgid "error marshalling data for XML-RPC transport: %(error)s" msgstr "" #: ipalib/errors.py:424 #, python-format msgid "Missing or invalid HTTP Referer, %(referer)s" msgstr "" #: ipalib/errors.py:451 #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "" #: ipalib/errors.py:468 msgid "did not receive Kerberos credentials" msgstr "" #: ipalib/errors.py:484 #, python-format msgid "Service '%(service)s' not found in Kerberos database" msgstr "" #: ipalib/errors.py:500 msgid "No credentials cache found" msgstr "" #: ipalib/errors.py:516 msgid "Ticket expired" msgstr "" #: ipalib/errors.py:532 msgid "Credentials cache permissions incorrect" msgstr "" #: ipalib/errors.py:548 msgid "Bad format in credentials cache" msgstr "" #: ipalib/errors.py:564 msgid "Cannot resolve KDC for requested realm" msgstr "" #: ipalib/errors.py:576 msgid "Session error" msgstr "" #: ipalib/errors.py:584 #, python-format msgid "Principal %(principal)s cannot be authenticated: %(message)s" msgstr "" #: ipalib/errors.py:602 #, python-format msgid "Insufficient access: %(info)s" msgstr "" #: ipalib/errors.py:646 #, python-format msgid "command '%(name)s' takes no arguments" msgstr "" #: ipalib/errors.py:666 #, python-format msgid "command '%(name)s' takes at most %(count)d argument" msgid_plural "command '%(name)s' takes at most %(count)d arguments" msgstr[0] "" msgstr[1] "" #: ipalib/errors.py:696 #, python-format msgid "overlapping arguments and options: %(names)s" msgstr "" #: ipalib/errors.py:712 #, python-format msgid "'%(name)s' is required" msgstr "" #: ipalib/errors.py:728 ipalib/errors.py:744 #, python-format msgid "invalid '%(name)s': %(error)s" msgstr "" #: ipalib/errors.py:760 #, python-format msgid "api has no such namespace: '%(name)s'" msgstr "" #: ipalib/errors.py:769 msgid "Passwords do not match" msgstr "" #: ipalib/errors.py:778 msgid "Command not implemented" msgstr "" #: ipalib/errors.py:787 msgid "Client is not configured. Run ipa-client-install." msgstr "" #: ipalib/errors.py:796 #, python-format msgid "Could not get %(name)s interactively" msgstr "" #: ipalib/errors.py:811 #, python-format msgid "Command '%(name)s' has been deprecated" msgstr "" #: ipalib/errors.py:839 ipalib/errors.py:1079 ipalib/errors.py:1173 #: ipalib/errors.py:1570 ipalib/errors.py:1587 #, python-format msgid "%(reason)s" msgstr "" #: ipalib/errors.py:855 msgid "This entry already exists" msgstr "" #: ipalib/errors.py:871 msgid "You must enroll a host in order to create a host service" msgstr "" #: ipalib/errors.py:887 #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" #: ipalib/errors.py:903 msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "" #: ipalib/errors.py:919 msgid "This command requires root access" msgstr "" #: ipalib/errors.py:935 msgid "This is already a posix group" msgstr "" #: ipalib/errors.py:951 #, python-format msgid "Principal is not of the form user@REALM: '%(principal)s'" msgstr "" #: ipalib/errors.py:967 msgid "This entry is already enabled" msgstr "" #: ipalib/errors.py:983 msgid "This entry is already disabled" msgstr "" #: ipalib/errors.py:999 msgid "This entry cannot be enabled or disabled" msgstr "" #: ipalib/errors.py:1015 msgid "This entry is not a member" msgstr "" #: ipalib/errors.py:1031 msgid "A group may not be a member of itself" msgstr "" #: ipalib/errors.py:1047 msgid "This entry is already a member" msgstr "" #: ipalib/errors.py:1063 #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "" #: ipalib/errors.py:1095 msgid "A group may not be added as a member of itself" msgstr "" #: ipalib/errors.py:1111 msgid "The default users group cannot be removed" msgstr "" #: ipalib/errors.py:1127 msgid "Host does not have corresponding DNS A record" msgstr "" #: ipalib/errors.py:1142 msgid "Deleting a managed group is not allowed. It must be detached first." msgstr "" #: ipalib/errors.py:1157 msgid "A managed group cannot have a password policy." msgstr "" #: ipalib/errors.py:1189 #, python-format msgid "'%(entry)s' doesn't have a certificate." msgstr "" #: ipalib/errors.py:1205 #, python-format msgid "Unable to create private group. A group '%(group)s' already exists." msgstr "" #: ipalib/errors.py:1221 #, python-format msgid "" "A problem was encountered when verifying that all members were %(verb)s: " "%(exc)s" msgstr "" #: ipalib/errors.py:1239 #, python-format msgid "%(attr)s does not contain '%(value)s'" msgstr "" #: ipalib/errors.py:1256 #, python-format msgid "" "The search criteria was not specific enough. Expected 1 and found %(found)d." msgstr "" #: ipalib/errors.py:1273 msgid "This group already allows external members" msgstr "" #: ipalib/errors.py:1290 msgid "This group cannot be posix because it is external" msgstr "" #: ipalib/errors.py:1307 msgid "This is already a posix group and cannot be converted to external one" msgstr "" #: ipalib/errors.py:1330 #, python-format msgid "no command nor help topic '%(topic)s'" msgstr "" #: ipalib/errors.py:1354 msgid "change collided with another change" msgstr "" #: ipalib/errors.py:1370 msgid "no modifications to be performed" msgstr "" #: ipalib/errors.py:1386 #, python-format msgid "%(desc)s: %(info)s" msgstr "" #: ipalib/errors.py:1402 msgid "limits exceeded for this query" msgstr "" #: ipalib/errors.py:1417 #, python-format msgid "%(info)s" msgstr "" #: ipalib/errors.py:1432 msgid "modifying primary key is not allowed" msgstr "" #: ipalib/errors.py:1448 #, python-format msgid "%(attr)s: Only one value allowed." msgstr "" #: ipalib/errors.py:1464 #, python-format msgid "%(attr)s: Invalid syntax." msgstr "" #: ipalib/errors.py:1480 #, python-format msgid "Bad search filter %(info)s" msgstr "" #: ipalib/errors.py:1496 msgid "Not allowed on non-leaf entry" msgstr "" #: ipalib/errors.py:1512 msgid "LDAP timeout" msgstr "" #: ipalib/errors.py:1537 #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "" #: ipalib/errors.py:1553 #, python-format msgid "Certificate format error: %(error)s" msgstr "" #: ipalib/errors.py:1604 msgid "Already registered" msgstr "" #: ipalib/errors.py:1620 msgid "Not registered yet" msgstr "" #: ipalib/errors.py:1636 #, python-format msgid "%(key)s cannot be deleted because %(label)s %(dependent)s requires it" msgstr "" #: ipalib/errors.py:1652 #, python-format msgid "" "%(key)s cannot be deleted or disabled because it is the last member of " "%(label)s %(container)s" msgstr "" #: ipalib/errors.py:1668 #, python-format msgid "%(label)s %(key)s cannot be deleted/modified: %(reason)s" msgstr "" #: ipalib/errors.py:1685 #, python-format msgid "%(name)s certificate is not valid" msgstr "" #: ipalib/frontend.py:412 msgid "Results are truncated, try a more specific search" msgstr "" #: ipalib/frontend.py:531 #, python-format msgid "Unknown option: %(option)s" msgstr "" #: ipalib/frontend.py:903 msgid "" "Retrieve and print all attributes from the server. Affects command output." msgstr "" #: ipalib/frontend.py:909 msgid "Print entries as stored on the server. Only affects output format." msgstr "" #: ipalib/frontend.py:915 ipalib/plugins/batch.py:69 msgid "Client version. Used to determine if server will accept request." msgstr "" #: ipalib/frontend.py:1088 msgid "Forward to server instead of running locally" msgstr "" #: ipalib/messages.py:73 msgid "Additional instructions:" msgstr "" #: ipalib/messages.py:134 #, python-format msgid "" "API Version number was not sent, forward compatibility not guaranteed. " "Assuming server's API version, %(server_version)s" msgstr "" #: ipalib/output.py:92 msgid "A dictionary representing an LDAP entry" msgstr "" #: ipalib/output.py:100 msgid "A list of LDAP entries" msgstr "" #: ipalib/output.py:111 msgid "All commands should at least have a result" msgstr "" #: ipalib/output.py:114 msgid "User-friendly description of action performed" msgstr "" #: ipalib/output.py:118 msgid "The primary_key value of the entry, e.g. 'jdoe' for a user" msgstr "" #: ipalib/output.py:133 msgid "Number of entries returned" msgstr "" #: ipalib/output.py:134 msgid "True if not all results were returned" msgstr "" #: ipalib/output.py:139 msgid "List of deletions that failed" msgstr "" #: ipalib/output.py:145 msgid "True means the operation was successful" msgstr "" #: ipalib/parameters.py:366 msgid "incorrect type" msgstr "" #: ipalib/parameters.py:369 msgid "Only one value is allowed" msgstr "" #: ipalib/parameters.py:935 msgid "must be True or False" msgstr "" #: ipalib/parameters.py:1036 msgid "must be an integer" msgstr "" #: ipalib/parameters.py:1087 #, python-format msgid "must be at least %(minvalue)d" msgstr "" #: ipalib/parameters.py:1097 #, python-format msgid "can be at most %(maxvalue)d" msgstr "" #: ipalib/parameters.py:1138 msgid "must be a decimal number" msgstr "" #: ipalib/parameters.py:1184 #, python-format msgid "must be at least %(minvalue)s" msgstr "" #: ipalib/parameters.py:1194 #, python-format msgid "can be at most %(maxvalue)s" msgstr "" #: ipalib/parameters.py:1202 #, python-format msgid "" "number class '%(cls)s' is not included in a list of allowed number classes: " "%(allowed)s" msgstr "" #: ipalib/parameters.py:1326 #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "" #: ipalib/parameters.py:1344 msgid "must be binary data" msgstr "" #: ipalib/parameters.py:1360 #, python-format msgid "must be at least %(minlength)d bytes" msgstr "" #: ipalib/parameters.py:1370 #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "" #: ipalib/parameters.py:1380 #, python-format msgid "must be exactly %(length)d bytes" msgstr "" #: ipalib/parameters.py:1410 msgid "must be Unicode text" msgstr "" #: ipalib/parameters.py:1443 msgid "Leading and trailing spaces are not allowed" msgstr "" #: ipalib/parameters.py:1451 #, python-format msgid "must be at least %(minlength)d characters" msgstr "" #: ipalib/parameters.py:1461 #, python-format msgid "can be at most %(maxlength)d characters" msgstr "" #: ipalib/parameters.py:1471 #, python-format msgid "must be exactly %(length)d characters" msgstr "" #: ipalib/parameters.py:1490 #, python-format msgid "The character %(char)r is not allowed." msgstr "" #: ipalib/parameters.py:1539 #, python-format msgid "must be '%(value)s'" msgstr "" #: ipalib/parameters.py:1542 #, python-format msgid "must be one of %(values)s" msgstr "" #: ipalib/parameters.py:1781 msgid "incomplete time value" msgstr "" #: ipalib/parameters.py:1818 msgid "this option is deprecated" msgstr "" #: ipalib/plugins/aci.py:154 msgid "A list of ACI values" msgstr "" #: ipalib/plugins/aci.py:218 msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr "" #: ipalib/plugins/aci.py:221 msgid "ACI prefix is required" msgstr "" #: ipalib/plugins/aci.py:224 msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" #: ipalib/plugins/aci.py:227 msgid "filter and memberof are mutually exclusive" msgstr "" #: ipalib/plugins/aci.py:233 msgid "group, permission and self are mutually exclusive" msgstr "" #: ipalib/plugins/aci.py:235 msgid "One of group, permission or self is required" msgstr "" #: ipalib/plugins/aci.py:258 #, python-format msgid "Group '%s' does not exist" msgstr "" #: ipalib/plugins/aci.py:284 msgid "empty filter" msgstr "" #: ipalib/plugins/aci.py:305 #, python-format msgid "Syntax Error: %(error)s" msgstr "" #: ipalib/plugins/aci.py:351 #, python-format msgid "invalid DN (%s)" msgstr "" #: ipalib/plugins/aci.py:398 #, python-format msgid "ACI with name \"%s\" not found" msgstr "" #: ipalib/plugins/aci.py:416 msgid "ACI prefix" msgstr "" #: ipalib/plugins/aci.py:417 msgid "" "Prefix used to distinguish ACI types (permission, delegation, selfservice, " "none)" msgstr "" #: ipalib/plugins/aci.py:428 msgid "ACIs" msgstr "" #: ipalib/plugins/aci.py:433 msgid "ACI name" msgstr "" #: ipalib/plugins/aci.py:439 ipalib/plugins/permission.py:123 msgid "Permission" msgstr "" #: ipalib/plugins/aci.py:440 msgid "Permission ACI grants access to" msgstr "" #: ipalib/plugins/aci.py:445 ipalib/plugins/delegation.py:101 msgid "User group" msgstr "" #: ipalib/plugins/aci.py:446 ipalib/plugins/delegation.py:102 msgid "User group ACI grants access to" msgstr "" #: ipalib/plugins/aci.py:451 ipalib/plugins/baseldap.py:65 #: ipalib/plugins/delegation.py:83 ipalib/plugins/permission.py:122 #: ipalib/plugins/permission.py:135 ipalib/plugins/selfservice.py:87 msgid "Permissions" msgstr "" #: ipalib/plugins/aci.py:452 msgid "Permissions to grant(read, write, add, delete, all)" msgstr "" #: ipalib/plugins/aci.py:460 ipalib/plugins/permission.py:143 msgid "Attributes to which the permission applies" msgstr "" #: ipalib/plugins/aci.py:461 ipalib/plugins/delegation.py:89 #: ipalib/plugins/permission.py:142 ipalib/plugins/selfservice.py:93 msgid "Attributes" msgstr "" #: ipalib/plugins/aci.py:467 ipalib/plugins/permission.py:150 msgid "Type" msgstr "" #: ipalib/plugins/aci.py:468 msgid "type of IPA object (user, group, host, hostgroup, service, netgroup)" msgstr "" #: ipalib/plugins/aci.py:474 msgid "Member of" msgstr "" #: ipalib/plugins/aci.py:475 msgid "Member of a group" msgstr "" #: ipalib/plugins/aci.py:480 ipalib/plugins/permission.py:163 msgid "Filter" msgstr "" #: ipalib/plugins/aci.py:481 ipalib/plugins/permission.py:164 msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "" #: ipalib/plugins/aci.py:486 ipalib/plugins/permission.py:169 msgid "Subtree" msgstr "" #: ipalib/plugins/aci.py:487 msgid "Subtree to apply ACI to" msgstr "" #: ipalib/plugins/aci.py:492 ipalib/plugins/permission.py:175 msgid "Target group" msgstr "" #: ipalib/plugins/aci.py:493 msgid "Group to apply ACI to" msgstr "" #: ipalib/plugins/aci.py:498 msgid "Target your own entry (self)" msgstr "" #: ipalib/plugins/aci.py:499 msgid "Apply ACI to your own entry (self)" msgstr "" #: ipalib/plugins/aci.py:511 #, python-format msgid "Created ACI \"%(value)s\"" msgstr "" #: ipalib/plugins/aci.py:516 msgid "Test the ACI syntax but don't write anything" msgstr "" #: ipalib/plugins/aci.py:567 #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "" #: ipalib/plugins/aci.py:610 ipalib/plugins/aci.py:886 #: ipalib/plugins/aci.py:927 ipalib/plugins/delegation.py:59 #: ipalib/plugins/permission.py:88 ipalib/plugins/selfservice.py:60 msgid "ACI" msgstr "" #: ipalib/plugins/aci.py:618 #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "" #: ipalib/plugins/aci.py:693 #, python-format msgid "%(count)d ACI matched" msgid_plural "%(count)d ACIs matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/aci.py:934 msgid "New ACI name" msgstr "" #: ipalib/plugins/aci.py:938 #, python-format msgid "Renamed ACI to \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:28 msgid "" "\n" "Auto Membership Rule.\n" "\n" "Bring clarity to the membership of hosts and users by configuring inclusive\n" "or exclusive regex patterns, you can automatically assign a new entries " "into\n" "a group or hostgroup based upon attribute information.\n" "\n" "A rule is directly associated with a group by name, so you cannot create\n" "a rule without an accompanying group or hostgroup.\n" "\n" "A condition is a regular expression used by 389-ds to match a new incoming\n" "entry with an automember rule. If it matches an inclusive rule then the\n" "entry is added to the appropriate group or hostgroup.\n" "\n" "A default group or hostgroup could be specified for entries that do not\n" "match any rule. In case of user entries this group will be a fallback group\n" "because all users are by default members of group specified in IPA config.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add the initial group or hostgroup:\n" " ipa hostgroup-add --desc=\"Web Servers\" webservers\n" " ipa group-add --desc=\"Developers\" devel\n" "\n" " Add the initial rule:\n" " ipa automember-add --type=hostgroup webservers\n" " ipa automember-add --type=group devel\n" "\n" " Add a condition to the rule:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" " ipa automember-add-condition --key=manager --type=group --inclusive-" "regex=^uid=mscott devel\n" "\n" " Add an exclusive condition to the rule to prevent auto assignment:\n" " ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-" "regex=^web5\\.example\\.com webservers\n" "\n" " Add a host:\n" " ipa host-add web1.example.com\n" "\n" " Add a user:\n" " ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott\n" "\n" " Verify automembership:\n" " ipa hostgroup-show webservers\n" " Host-group: webservers\n" " Description: Web Servers\n" " Member hosts: web1.example.com\n" "\n" " ipa group-show devel\n" " Group name: devel\n" " Description: Developers\n" " GID: 1004200000\n" " Member users: tuser\n" "\n" " Remove a condition from the rule:\n" " ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-" "regex=^web[1-9]+\\.example\\.com webservers\n" "\n" " Modify the automember rule:\n" " ipa automember-mod\n" "\n" " Set the default (fallback) target group:\n" " ipa automember-default-group-set --default-group=webservers --" "type=hostgroup\n" " ipa automember-default-group-set --default-group=ipausers --type=group\n" "\n" " Remove the default (fallback) target group:\n" " ipa automember-default-group-remove --type=hostgroup\n" " ipa automember-default-group-remove --type=group\n" "\n" " Show the default (fallback) target group:\n" " ipa automember-default-group-show --type=hostgroup\n" " ipa automember-default-group-show --type=group\n" "\n" " Find all of the automember rules:\n" " ipa automember-find\n" "\n" " Display a automember rule:\n" " ipa automember-show --type=hostgroup webservers\n" " ipa automember-show --type=group devel\n" "\n" " Delete an automember rule:\n" " ipa automember-del --type=hostgroup webservers\n" " ipa automember-del --type=group devel\n" msgstr "" #: ipalib/plugins/automember.py:119 ipalib/plugins/automember.py:120 msgid "Inclusive Regex" msgstr "" #: ipalib/plugins/automember.py:126 ipalib/plugins/automember.py:127 msgid "Exclusive Regex" msgstr "" #: ipalib/plugins/automember.py:132 msgid "Attribute Key" msgstr "" #: ipalib/plugins/automember.py:133 msgid "" "Attribute to filter via regex. For example fqdn for a host, or manager for a " "user" msgstr "" #: ipalib/plugins/automember.py:140 msgid "Grouping Type" msgstr "" #: ipalib/plugins/automember.py:141 msgid "Grouping to which the rule applies" msgstr "" #: ipalib/plugins/automember.py:149 ipalib/plugins/automember.py:150 msgid "Automember Rule" msgstr "" #: ipalib/plugins/automember.py:171 msgid "Auto Membership Rule" msgstr "" #: ipalib/plugins/automember.py:176 ipalib/plugins/automount.py:579 #: ipalib/plugins/group.py:155 ipalib/plugins/hbacrule.py:179 #: ipalib/plugins/hbacsvc.py:79 ipalib/plugins/hbacsvcgroup.py:73 #: ipalib/plugins/host.py:268 ipalib/plugins/hostgroup.py:90 #: ipalib/plugins/netgroup.py:122 ipalib/plugins/privilege.py:73 #: ipalib/plugins/role.py:92 ipalib/plugins/selinuxusermap.py:184 #: ipalib/plugins/sudocmd.py:77 ipalib/plugins/sudocmdgroup.py:78 #: ipalib/plugins/sudorule.py:111 msgid "Description" msgstr "" #: ipalib/plugins/automember.py:177 msgid "A description of this auto member rule" msgstr "" #: ipalib/plugins/automember.py:181 ipalib/plugins/automember.py:511 msgid "Default (fallback) Group" msgstr "" #: ipalib/plugins/automember.py:182 msgid "Default group for entries to land" msgstr "" #: ipalib/plugins/automember.py:193 #, python-format msgid "Group: %s not found!" msgstr "" #: ipalib/plugins/automember.py:217 #, python-format msgid "%s is not a valid attribute." msgstr "" #: ipalib/plugins/automember.py:230 msgid "" "\n" " Add an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:235 #, python-format msgid "Added automember rule \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:242 msgid "Auto Membership is not configured" msgstr "" #: ipalib/plugins/automember.py:255 msgid "" "\n" " Add conditions to an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:260 msgid "Failed to add" msgstr "" #: ipalib/plugins/automember.py:267 #, python-format msgid "Added condition(s) to \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:276 msgid "Conditions that could not be added" msgstr "" #: ipalib/plugins/automember.py:280 msgid "Number of conditions added" msgstr "" #: ipalib/plugins/automember.py:290 ipalib/plugins/automember.py:376 #, python-format msgid "Auto member rule: %s not found!" msgstr "" #: ipalib/plugins/automember.py:332 msgid "" "\n" " Override this so we can add completed and failed to the return " "result.\n" " " msgstr "" #: ipalib/plugins/automember.py:348 msgid "" "\n" " Remove conditions from an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:353 #, python-format msgid "Removed condition(s) from \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:362 msgid "Conditions that could not be removed" msgstr "" #: ipalib/plugins/automember.py:366 msgid "Number of conditions removed" msgstr "" #: ipalib/plugins/automember.py:420 msgid "" "\n" " Override this so we can set completed and failed.\n" " " msgstr "" #: ipalib/plugins/automember.py:436 msgid "" "\n" " Modify an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:441 #, python-format msgid "Modified automember rule \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:452 msgid "" "\n" " Delete an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:457 #, python-format msgid "Deleted automember rule \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:468 msgid "" "\n" " Search for automember rules.\n" " " msgstr "" #: ipalib/plugins/automember.py:475 #, python-format msgid "%(count)d rules matched" msgid_plural "%(count)d rules matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/automember.py:488 msgid "" "\n" " Display information about an automember rule.\n" " " msgstr "" #: ipalib/plugins/automember.py:504 msgid "" "\n" " Set default (fallback) group for all unmatched entries.\n" " " msgstr "" #: ipalib/plugins/automember.py:512 msgid "Default (fallback) group for entries to land" msgstr "" #: ipalib/plugins/automember.py:516 #, python-format msgid "Set default (fallback) group for automember \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:533 msgid "" "\n" " Remove default (fallback) group for all unmatched entries.\n" " " msgstr "" #: ipalib/plugins/automember.py:538 #, python-format msgid "Removed default (fallback) group for automember \"%(value)s\"" msgstr "" #: ipalib/plugins/automember.py:548 ipalib/plugins/automember.py:556 #: ipalib/plugins/automember.py:581 msgid "No default (fallback) group set" msgstr "" #: ipalib/plugins/automember.py:568 msgid "" "\n" " Display information about the default (fallback) automember groups.\n" " " msgstr "" #: ipalib/plugins/automount.py:29 msgid "" "\n" "Automount\n" "\n" "Stores automount(8) configuration for autofs(8) in IPA.\n" "\n" "The base of an automount configuration is the configuration file auto." "master.\n" "This is also the base location in IPA. Multiple auto.master configurations\n" "can be stored in separate locations. A location is implementation-specific\n" "with the default being a location named 'default'. For example, you can " "have\n" "locations by geographic region, by floor, by type, etc.\n" "\n" "Automount has three basic object types: locations, maps and keys.\n" "\n" "A location defines a set of maps anchored in auto.master. This allows you\n" "to store multiple automount configurations. A location in itself isn't\n" "very interesting, it is just a point to start a new automount map.\n" "\n" "A map is roughly equivalent to a discrete automount file and provides\n" "storage for keys.\n" "\n" "A key is a mount point associated with a map.\n" "\n" "When a new location is created, two maps are automatically created for\n" "it: auto.master and auto.direct. auto.master is the root map for all\n" "automount maps for the location. auto.direct is the default map for\n" "direct mounts and is mounted on /-.\n" "\n" "An automount map may contain a submount key. This key defines a mount\n" "location within the map that references another map. This can be done\n" "either using automountmap-add-indirect --parentmap or manually\n" "with automountkey-add and setting info to \"-type=autofs :\".\n" "\n" "EXAMPLES:\n" "\n" "Locations:\n" "\n" " Create a named location, \"Baltimore\":\n" " ipa automountlocation-add baltimore\n" "\n" " Display the new location:\n" " ipa automountlocation-show baltimore\n" "\n" " Find available locations:\n" " ipa automountlocation-find\n" "\n" " Remove a named automount location:\n" " ipa automountlocation-del baltimore\n" "\n" " Show what the automount maps would look like if they were in the " "filesystem:\n" " ipa automountlocation-tofiles baltimore\n" "\n" " Import an existing configuration into a location:\n" " ipa automountlocation-import baltimore /etc/auto.master\n" "\n" " The import will fail if any duplicate entries are found. For\n" " continuous operation where errors are ignored, use the --continue\n" " option.\n" "\n" "Maps:\n" "\n" " Create a new map, \"auto.share\":\n" " ipa automountmap-add baltimore auto.share\n" "\n" " Display the new map:\n" " ipa automountmap-show baltimore auto.share\n" "\n" " Find maps in the location baltimore:\n" " ipa automountmap-find baltimore\n" "\n" " Create an indirect map with auto.share as a submount:\n" " ipa automountmap-add-indirect baltimore --parentmap=auto.share --" "mount=sub auto.man\n" "\n" " This is equivalent to:\n" "\n" " ipa automountmap-add-indirect baltimore --mount=/man auto.man\n" " ipa automountkey-add baltimore auto.man --key=sub --info=\"-" "fstype=autofs ldap:auto.share\"\n" "\n" " Remove the auto.share map:\n" " ipa automountmap-del baltimore auto.share\n" "\n" "Keys:\n" "\n" " Create a new key for the auto.share map in location baltimore. This ties\n" " the map we previously created to auto.master:\n" " ipa automountkey-add baltimore auto.master --key=/share --info=auto." "share\n" "\n" " Create a new key for our auto.share map, an NFS mount for man pages:\n" " ipa automountkey-add baltimore auto.share --key=man --info=\"-ro,soft," "rsize=8192,wsize=8192 ipa.example.com:/shared/man\"\n" "\n" " Find all keys for the auto.share map:\n" " ipa automountkey-find baltimore auto.share\n" "\n" " Find all direct automount keys:\n" " ipa automountkey-find baltimore --key=/-\n" "\n" " Remove the man key from the auto.share map:\n" " ipa automountkey-del baltimore auto.share --key=man\n" msgstr "" #: ipalib/plugins/automount.py:205 msgid "automount location" msgstr "" #: ipalib/plugins/automount.py:206 msgid "automount locations" msgstr "" #: ipalib/plugins/automount.py:209 msgid "Automount Locations" msgstr "" #: ipalib/plugins/automount.py:210 msgid "Automount Location" msgstr "" #: ipalib/plugins/automount.py:215 ipalib/plugins/host.py:278 msgid "Location" msgstr "" #: ipalib/plugins/automount.py:216 msgid "Automount location name." msgstr "" #: ipalib/plugins/automount.py:225 msgid "Create a new automount location." msgstr "" #: ipalib/plugins/automount.py:227 #, python-format msgid "Added automount location \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:247 msgid "Delete an automount location." msgstr "" #: ipalib/plugins/automount.py:249 #, python-format msgid "Deleted automount location \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:255 msgid "Display an automount location." msgstr "" #: ipalib/plugins/automount.py:261 msgid "Search for an automount location." msgstr "" #: ipalib/plugins/automount.py:264 #, python-format msgid "%(count)d automount location matched" msgid_plural "%(count)d automount locations matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/automount.py:272 msgid "Generate automount files for a specific location." msgstr "" #: ipalib/plugins/automount.py:350 msgid "maps not connected to /etc/auto.master:" msgstr "" #: ipalib/plugins/automount.py:368 msgid "Import automount files for a specific location." msgstr "" #: ipalib/plugins/automount.py:372 msgid "Master file" msgstr "" #: ipalib/plugins/automount.py:373 msgid "Automount master file." msgstr "" #: ipalib/plugins/automount.py:380 msgid "" "Continuous operation mode. Errors are reported but the process continues." msgstr "" #: ipalib/plugins/automount.py:392 #, python-format msgid "File %(file)s not found" msgstr "" #: ipalib/plugins/automount.py:444 #, python-format msgid "key %(key)s already exists" msgstr "" #: ipalib/plugins/automount.py:460 #, python-format msgid "map %(map)s already exists" msgstr "" #: ipalib/plugins/automount.py:565 msgid "automount map" msgstr "" #: ipalib/plugins/automount.py:566 msgid "automount maps" msgstr "" #: ipalib/plugins/automount.py:573 msgid "Map" msgstr "" #: ipalib/plugins/automount.py:574 msgid "Automount map name." msgstr "" #: ipalib/plugins/automount.py:583 msgid "Automount Maps" msgstr "" #: ipalib/plugins/automount.py:584 msgid "Automount Map" msgstr "" #: ipalib/plugins/automount.py:590 msgid "Create a new automount map." msgstr "" #: ipalib/plugins/automount.py:592 #, python-format msgid "Added automount map \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:598 msgid "Delete an automount map." msgstr "" #: ipalib/plugins/automount.py:600 #, python-format msgid "Deleted automount map \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:619 msgid "Modify an automount map." msgstr "" #: ipalib/plugins/automount.py:621 #, python-format msgid "Modified automount map \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:627 msgid "Search for an automount map." msgstr "" #: ipalib/plugins/automount.py:630 #, python-format msgid "%(count)d automount map matched" msgid_plural "%(count)d automount maps matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/automount.py:638 msgid "Display an automount map." msgstr "" #: ipalib/plugins/automount.py:644 msgid "Automount key object." msgstr "" #: ipalib/plugins/automount.py:648 msgid "automount key" msgstr "" #: ipalib/plugins/automount.py:649 msgid "automount keys" msgstr "" #: ipalib/plugins/automount.py:660 ipalib/plugins/automount.py:883 #: ipalib/plugins/automount.py:993 msgid "Key" msgstr "" #: ipalib/plugins/automount.py:661 ipalib/plugins/automount.py:884 #: ipalib/plugins/automount.py:994 msgid "Automount key name." msgstr "" #: ipalib/plugins/automount.py:666 ipalib/plugins/automount.py:888 #: ipalib/plugins/automount.py:998 msgid "Mount information" msgstr "" #: ipalib/plugins/automount.py:669 msgid "description" msgstr "" #: ipalib/plugins/automount.py:678 msgid "Automount Keys" msgstr "" #: ipalib/plugins/automount.py:679 msgid "Automount Key" msgstr "" #: ipalib/plugins/automount.py:680 #, python-format msgid "" "The key,info pair must be unique. A key named %(key)s with info %(info)s " "already exists" msgstr "" #: ipalib/plugins/automount.py:681 #, python-format msgid "key named %(key)s already exists" msgstr "" #: ipalib/plugins/automount.py:682 #, python-format msgid "The automount key %(key)s with info %(info)s does not exist" msgstr "" #: ipalib/plugins/automount.py:732 #, python-format msgid "" "More than one entry with key %(key)s found, use --info to select specific " "entry." msgstr "" #: ipalib/plugins/automount.py:792 msgid "Create a new automount key." msgstr "" #: ipalib/plugins/automount.py:794 #, python-format msgid "Added automount key \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:822 msgid "Create a new indirect mount point." msgstr "" #: ipalib/plugins/automount.py:824 #, python-format msgid "Added automount indirect map \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:829 msgid "Mount point" msgstr "" #: ipalib/plugins/automount.py:833 msgid "Parent map" msgstr "" #: ipalib/plugins/automount.py:834 msgid "Name of parent automount map (default: auto.master)." msgstr "" #: ipalib/plugins/automount.py:848 msgid "mount point is relative to parent map, cannot begin with /" msgstr "" #: ipalib/plugins/automount.py:876 msgid "Delete an automount key." msgstr "" #: ipalib/plugins/automount.py:878 #, python-format msgid "Deleted automount key \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:918 msgid "Modify an automount key." msgstr "" #: ipalib/plugins/automount.py:920 #, python-format msgid "Modified automount key \"%(value)s\"" msgstr "" #: ipalib/plugins/automount.py:927 msgid "New mount information" msgstr "" #: ipalib/plugins/automount.py:977 msgid "Search for an automount key." msgstr "" #: ipalib/plugins/automount.py:980 #, python-format msgid "%(count)d automount key matched" msgid_plural "%(count)d automount keys matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/automount.py:988 msgid "Display an automount key." msgstr "" #: ipalib/plugins/baseldap.py:41 ipalib/plugins/internal.py:280 #: ipalib/plugins/internal.py:633 ipalib/plugins/migration.py:491 #: ipalib/plugins/user.py:289 msgid "Password" msgstr "" #: ipalib/plugins/baseldap.py:44 msgid "Failed members" msgstr "" #: ipalib/plugins/baseldap.py:47 msgid "Member users" msgstr "" #: ipalib/plugins/baseldap.py:50 msgid "Member groups" msgstr "" #: ipalib/plugins/baseldap.py:53 msgid "Member of groups" msgstr "" #: ipalib/plugins/baseldap.py:56 msgid "Member hosts" msgstr "" #: ipalib/plugins/baseldap.py:59 msgid "Member host-groups" msgstr "" #: ipalib/plugins/baseldap.py:62 msgid "Member of host-groups" msgstr "" #: ipalib/plugins/baseldap.py:71 ipalib/plugins/role.py:81 msgid "Roles" msgstr "" #: ipalib/plugins/baseldap.py:74 ipalib/plugins/sudocmdgroup.py:66 #: ipalib/plugins/sudocmdgroup.py:86 msgid "Sudo Command Groups" msgstr "" #: ipalib/plugins/baseldap.py:80 msgid "Granting privilege to roles" msgstr "" #: ipalib/plugins/baseldap.py:83 msgid "Member netgroups" msgstr "" #: ipalib/plugins/baseldap.py:86 msgid "Member of netgroups" msgstr "" #: ipalib/plugins/baseldap.py:89 msgid "Member services" msgstr "" #: ipalib/plugins/baseldap.py:92 msgid "Member service groups" msgstr "" #: ipalib/plugins/baseldap.py:98 msgid "Member HBAC service" msgstr "" #: ipalib/plugins/baseldap.py:101 msgid "Member HBAC service groups" msgstr "" #: ipalib/plugins/baseldap.py:116 msgid "Indirect Member users" msgstr "" #: ipalib/plugins/baseldap.py:119 msgid "Indirect Member groups" msgstr "" #: ipalib/plugins/baseldap.py:122 msgid "Indirect Member hosts" msgstr "" #: ipalib/plugins/baseldap.py:125 msgid "Indirect Member host-groups" msgstr "" #: ipalib/plugins/baseldap.py:128 msgid "Indirect Member of roles" msgstr "" #: ipalib/plugins/baseldap.py:131 msgid "Indirect Member permissions" msgstr "" #: ipalib/plugins/baseldap.py:134 msgid "Indirect Member HBAC service" msgstr "" #: ipalib/plugins/baseldap.py:137 msgid "Indirect Member HBAC service group" msgstr "" #: ipalib/plugins/baseldap.py:140 msgid "Indirect Member netgroups" msgstr "" #: ipalib/plugins/baseldap.py:161 msgid "Failed source hosts/hostgroups" msgstr "" #: ipalib/plugins/baseldap.py:164 msgid "Failed hosts/hostgroups" msgstr "" #: ipalib/plugins/baseldap.py:167 msgid "Failed users/groups" msgstr "" #: ipalib/plugins/baseldap.py:170 msgid "Failed service/service groups" msgstr "" #: ipalib/plugins/baseldap.py:173 msgid "Failed to remove" msgstr "" #: ipalib/plugins/baseldap.py:177 msgid "Failed RunAs" msgstr "" #: ipalib/plugins/baseldap.py:180 msgid "Failed RunAsGroup" msgstr "" #: ipalib/plugins/baseldap.py:198 msgid "Invalid format. Should be name=value" msgstr "" #: ipalib/plugins/baseldap.py:286 msgid "External host" msgstr "" #: ipalib/plugins/baseldap.py:419 msgid "An IPA master host cannot be deleted or disabled" msgstr "" #: ipalib/plugins/baseldap.py:433 msgid "entry" msgstr "" #: ipalib/plugins/baseldap.py:434 msgid "entries" msgstr "" #: ipalib/plugins/baseldap.py:466 ipalib/plugins/baseldap.py:467 msgid "Entry" msgstr "" #: ipalib/plugins/baseldap.py:469 #, python-format msgid "container entry (%(container)s) not found" msgstr "" #: ipalib/plugins/baseldap.py:470 #, python-format msgid "%(parent)s: %(oname)s not found" msgstr "" #: ipalib/plugins/baseldap.py:471 #, python-format msgid "%(pkey)s: %(oname)s not found" msgstr "" #: ipalib/plugins/baseldap.py:472 #, python-format msgid "%(oname)s with name \"%(pkey)s\" already exists" msgstr "" #: ipalib/plugins/baseldap.py:669 ipalib/plugins/baseldap.py:677 #: ipalib/plugins/baseldap.py:682 #, python-format msgid "attribute \"%(attribute)s\" not allowed" msgstr "" #: ipalib/plugins/baseldap.py:744 msgid "" "Set an attribute to a name/value pair. Format is attr=value.\n" "For multi-valued attributes, the command replaces the values already present." msgstr "" #: ipalib/plugins/baseldap.py:750 msgid "" "Add an attribute/value pair. Format is attr=value. The attribute\n" "must be part of the schema." msgstr "" #: ipalib/plugins/baseldap.py:756 msgid "" "Delete an attribute/value pair. The option will be evaluated\n" "last, after all sets and adds." msgstr "" #: ipalib/plugins/baseldap.py:784 msgid "attribute is not configurable" msgstr "" #: ipalib/plugins/baseldap.py:887 msgid "No such attribute on this entry" msgstr "" #: ipalib/plugins/baseldap.py:981 msgid "Suppress processing of membership attributes." msgstr "" #: ipalib/plugins/baseldap.py:1165 msgid "Continuous mode: Don't stop on errors." msgstr "" #: ipalib/plugins/baseldap.py:1190 ipalib/plugins/baseldap.py:1263 #: ipalib/plugins/internal.py:501 msgid "Rights" msgstr "" #: ipalib/plugins/baseldap.py:1191 ipalib/plugins/baseldap.py:1264 msgid "" "Display the access rights of this entry (requires --all). See ipa man page " "for details." msgstr "" #: ipalib/plugins/baseldap.py:1273 msgid "Rename" msgstr "" #: ipalib/plugins/baseldap.py:1274 #, python-format msgid "Rename the %(ldap_obj_name)s object" msgstr "" #: ipalib/plugins/baseldap.py:1355 msgid "the entry was deleted while being modified" msgstr "" #: ipalib/plugins/baseldap.py:1482 ipalib/plugins/baseldap.py:1955 #, python-format msgid "%s" msgstr "" #: ipalib/plugins/baseldap.py:1494 #, python-format msgid "member %s" msgstr "" #: ipalib/plugins/baseldap.py:1524 ipalib/plugins/baseldap.py:1980 #, python-format msgid "%s to add" msgstr "" #: ipalib/plugins/baseldap.py:1532 ipalib/plugins/baseldap.py:1992 #: ipalib/plugins/privilege.py:150 ipalib/plugins/privilege.py:175 #: ipalib/plugins/role.py:164 ipalib/plugins/role.py:187 msgid "Members that could not be added" msgstr "" #: ipalib/plugins/baseldap.py:1536 ipalib/plugins/baseldap.py:1996 msgid "Number of members added" msgstr "" #: ipalib/plugins/baseldap.py:1625 ipalib/plugins/baseldap.py:2085 #, python-format msgid "%s to remove" msgstr "" #: ipalib/plugins/baseldap.py:1632 ipalib/plugins/baseldap.py:2097 msgid "Members that could not be removed" msgstr "" #: ipalib/plugins/baseldap.py:1636 ipalib/plugins/baseldap.py:2101 msgid "Number of members removed" msgstr "" #: ipalib/plugins/baseldap.py:1726 msgid "Primary key only" msgstr "" #: ipalib/plugins/baseldap.py:1727 #, python-format msgid "Results should contain primary key attribute only (\"%s\")" msgstr "" #: ipalib/plugins/baseldap.py:1735 #, python-format msgid "" "Search for %(searched_object)s with these %(relationship)s %(ldap_object)s." msgstr "" #: ipalib/plugins/baseldap.py:1736 #, python-format msgid "" "Search for %(searched_object)s without these %(relationship)s " "%(ldap_object)s." msgstr "" #: ipalib/plugins/baseldap.py:1745 msgid "Time Limit" msgstr "" #: ipalib/plugins/baseldap.py:1746 msgid "Time limit of search in seconds" msgstr "" #: ipalib/plugins/baseldap.py:1752 ipalib/plugins/cert.py:696 #: ipalib/plugins/hbactest.py:285 msgid "Size Limit" msgstr "" #: ipalib/plugins/baseldap.py:1753 msgid "Maximum number of entries returned" msgstr "" #: ipalib/plugins/baseldap.py:1766 msgid "A string searched in all relevant object attributes" msgstr "" #: ipalib/plugins/batch.py:62 msgid "Nested Methods to execute" msgstr "" #: ipalib/plugins/cert.py:45 msgid "" "\n" "IPA certificate operations\n" "\n" "Implements a set of commands for managing server SSL certificates.\n" "\n" "Certificate requests exist in the form of a Certificate Signing Request " "(CSR)\n" "in PEM format.\n" "\n" "The dogtag CA uses just the CN value of the CSR and forces the rest of the\n" "subject to values configured in the server.\n" "\n" "A certificate is stored with a service principal and a service principal\n" "needs a host.\n" "\n" "In order to request a certificate:\n" "\n" "* The host must exist\n" "* The service must exist (or you use the --add option to automatically add " "it)\n" "\n" "SEARCHING:\n" "\n" "Certificates may be searched on by certificate subject, serial number,\n" "revocation reason, validity dates and the issued date.\n" "\n" "When searching on dates the _from date does a >= search and the _to date\n" "does a <= search. When combined these are done as an AND.\n" "\n" "Dates are treated as GMT to match the dates in the certificates.\n" "\n" "The date format is YYYY-mm-dd.\n" "\n" "EXAMPLES:\n" "\n" " Request a new certificate and add the principal:\n" " ipa cert-request --add --principal=HTTP/lion.example.com example.csr\n" "\n" " Retrieve an existing certificate:\n" " ipa cert-show 1032\n" "\n" " Revoke a certificate (see RFC 5280 for reason details):\n" " ipa cert-revoke --revocation-reason=6 1032\n" "\n" " Remove a certificate from revocation hold status:\n" " ipa cert-remove-hold 1032\n" "\n" " Check the status of a signing request:\n" " ipa cert-status 10\n" "\n" " Search for certificates by hostname:\n" " ipa cert-find --subject=ipaserver.example.com\n" "\n" " Search for revoked certificates by reason:\n" " ipa cert-find --revocation-reason=5\n" "\n" " Search for certificates based on issuance date\n" " ipa cert-find --issuedon-from=2013-02-01 --issuedon-to=2013-02-07\n" "\n" "IPA currently immediately issues (or declines) all certificate requests so\n" "the status of a request is not normally useful. This is for future use\n" "or the case where a CA does not immediately issue a certificate.\n" "\n" "The following revocation reasons are supported:\n" "\n" " * 0 - unspecified\n" " * 1 - keyCompromise\n" " * 2 - cACompromise\n" " * 3 - affiliationChanged\n" " * 4 - superseded\n" " * 5 - cessationOfOperation\n" " * 6 - certificateHold\n" " * 8 - removeFromCRL\n" " * 9 - privilegeWithdrawn\n" " * 10 - aACompromise\n" "\n" "Note that reason code 7 is not used. See RFC 5280 for more details:\n" "\n" "http://www.ietf.org/rfc/rfc5280.txt\n" "\n" msgstr "" #: ipalib/plugins/cert.py:145 msgid "Failure decoding Certificate Signing Request:" msgstr "" #: ipalib/plugins/cert.py:158 ipalib/plugins/cert.py:175 msgid "Failure decoding Certificate Signing Request" msgstr "" #: ipalib/plugins/cert.py:177 #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "" #: ipalib/plugins/cert.py:240 msgid "Submit a certificate signing request." msgstr "" #: ipalib/plugins/cert.py:244 msgid "CSR" msgstr "" #: ipalib/plugins/cert.py:253 ipalib/plugins/service.py:321 msgid "Principal" msgstr "" #: ipalib/plugins/cert.py:254 msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "" #: ipalib/plugins/cert.py:261 msgid "automatically add the principal if it doesn't exist" msgstr "" #: ipalib/plugins/cert.py:269 ipalib/plugins/cert.py:481 #: ipalib/plugins/host.py:307 ipalib/plugins/internal.py:319 #: ipalib/plugins/service.py:328 msgid "Certificate" msgstr "" #: ipalib/plugins/cert.py:272 ipalib/plugins/cert.py:484 #: ipalib/plugins/cert.py:638 ipalib/plugins/cert.py:639 #: ipalib/plugins/host.py:167 ipalib/plugins/internal.py:332 #: ipalib/plugins/service.py:102 msgid "Subject" msgstr "" #: ipalib/plugins/cert.py:275 ipalib/plugins/cert.py:487 #: ipalib/plugins/host.py:176 ipalib/plugins/service.py:111 msgid "Issuer" msgstr "" #: ipalib/plugins/cert.py:278 ipalib/plugins/cert.py:490 #: ipalib/plugins/host.py:179 ipalib/plugins/service.py:114 msgid "Not Before" msgstr "" #: ipalib/plugins/cert.py:281 ipalib/plugins/cert.py:493 #: ipalib/plugins/host.py:182 ipalib/plugins/service.py:117 msgid "Not After" msgstr "" #: ipalib/plugins/cert.py:284 ipalib/plugins/cert.py:496 #: ipalib/plugins/host.py:185 ipalib/plugins/service.py:120 msgid "Fingerprint (MD5)" msgstr "" #: ipalib/plugins/cert.py:287 ipalib/plugins/cert.py:499 #: ipalib/plugins/host.py:188 ipalib/plugins/service.py:123 msgid "Fingerprint (SHA1)" msgstr "" #: ipalib/plugins/cert.py:290 ipalib/plugins/cert.py:469 #: ipalib/plugins/cert.py:710 msgid "Serial number" msgstr "" #: ipalib/plugins/cert.py:293 ipalib/plugins/cert.py:505 #: ipalib/plugins/cert.py:707 msgid "Serial number (hex)" msgstr "" #: ipalib/plugins/cert.py:300 ipalib/plugins/misc.py:57 msgid "Dictionary mapping variable name to value" msgstr "" #: ipalib/plugins/cert.py:333 msgid "No hostname was found in subject of request." msgstr "" #: ipalib/plugins/cert.py:338 #, python-format msgid "" "hostname in subject of request '%(subject_host)s' does not match principal " "hostname '%(hostname)s'" msgstr "" #: ipalib/plugins/cert.py:356 msgid "The service principal for this request doesn't exist." msgstr "" #: ipalib/plugins/cert.py:362 msgid "You need to be a member of the serviceadmin role to add services" msgstr "" #: ipalib/plugins/cert.py:367 #, python-format msgid "" "Insufficient 'write' privilege to the 'userCertificate' attribute of entry " "'%s'." msgstr "" #: ipalib/plugins/cert.py:383 #, python-format msgid "no host record for subject alt name %s in certificate request" msgstr "" #: ipalib/plugins/cert.py:389 #, python-format msgid "" "Insufficient privilege to create a certificate with subject alt name '%s'." msgstr "" #: ipalib/plugins/cert.py:442 msgid "Check the status of a certificate signing request." msgstr "" #: ipalib/plugins/cert.py:446 msgid "Request id" msgstr "" #: ipalib/plugins/cert.py:452 msgid "Request status" msgstr "" #: ipalib/plugins/cert.py:470 msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "" #: ipalib/plugins/cert.py:475 msgid "Retrieve an existing certificate." msgstr "" #: ipalib/plugins/cert.py:502 ipalib/plugins/host.py:191 #: ipalib/plugins/internal.py:329 ipalib/plugins/internal.py:358 #: ipalib/plugins/service.py:126 msgid "Revocation reason" msgstr "" #: ipalib/plugins/cert.py:511 msgid "Output filename" msgstr "" #: ipalib/plugins/cert.py:512 msgid "File to store the certificate in." msgstr "" #: ipalib/plugins/cert.py:563 msgid "Revoke a certificate." msgstr "" #: ipalib/plugins/cert.py:569 msgid "Revoked" msgstr "" #: ipalib/plugins/cert.py:577 ipalib/plugins/cert.py:643 msgid "Reason" msgstr "" #: ipalib/plugins/cert.py:578 ipalib/plugins/cert.py:644 msgid "Reason for revoking the certificate (0-10)" msgstr "" #: ipalib/plugins/cert.py:600 msgid "7 is not a valid revocation reason" msgstr "" #: ipalib/plugins/cert.py:610 msgid "Take a revoked certificate off hold." msgstr "" #: ipalib/plugins/cert.py:616 msgid "Unrevoked" msgstr "" #: ipalib/plugins/cert.py:619 ipalib/plugins/internal.py:249 msgid "Error" msgstr "" #: ipalib/plugins/cert.py:634 msgid "Search for existing certificates." msgstr "" #: ipalib/plugins/cert.py:650 msgid "minimum serial number" msgstr "" #: ipalib/plugins/cert.py:655 msgid "maximum serial number" msgstr "" #: ipalib/plugins/cert.py:660 msgid "match the common name exactly" msgstr "" #: ipalib/plugins/cert.py:664 msgid "Valid not after from this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:668 msgid "Valid not after to this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:672 msgid "Valid not before from this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:676 msgid "Valid not before to this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:680 msgid "Issued on from this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:684 msgid "Issued on to this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:688 msgid "Revoked on from this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:692 msgid "Revoked on to this date (YYYY-mm-dd)" msgstr "" #: ipalib/plugins/cert.py:697 msgid "Maximum number of certs returned" msgstr "" #: ipalib/plugins/cert.py:713 ipalib/plugins/internal.py:366 #: ipalib/plugins/internal.py:472 ipalib/plugins/internal.py:552 #: ipalib/plugins/internal.py:659 msgid "Status" msgstr "" #: ipalib/plugins/cert.py:718 #, python-format msgid "%(count)d certificate matched" msgid_plural "%(count)d certificates matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/config.py:32 msgid "" "\n" "Server configuration\n" "\n" "Manage the default values that IPA uses and some of its tuning parameters.\n" "\n" "NOTES:\n" "\n" "The password notification value (--pwdexpnotify) is stored here so it will\n" "be replicated. It is not currently used to notify users in advance of an\n" "expiring password.\n" "\n" "Some attributes are read-only, provided only for information purposes. " "These\n" "include:\n" "\n" "Certificate Subject base: the configured certificate subject base,\n" " e.g. O=EXAMPLE.COM. This is configurable only at install time.\n" "Password plug-in features: currently defines additional hashes that the\n" " password will generate (there may be other conditions).\n" "\n" "When setting the order list for mapping SELinux users you may need to\n" "quote the value so it isn't interpreted by the shell.\n" "\n" "EXAMPLES:\n" "\n" " Show basic server configuration:\n" " ipa config-show\n" "\n" " Show all configuration options:\n" " ipa config-show --all\n" "\n" " Change maximum username length to 99 characters:\n" " ipa config-mod --maxusername=99\n" "\n" " Increase default time and size limits for maximum IPA server search:\n" " ipa config-mod --searchtimelimit=10 --searchrecordslimit=2000\n" "\n" " Set default user e-mail domain:\n" " ipa config-mod --emaildomain=example.com\n" "\n" " Enable migration mode to make \"ipa migrate-ds\" command operational:\n" " ipa config-mod --enable-migration=TRUE\n" "\n" " Define SELinux user map order:\n" " ipa config-mod --ipaselinuxusermaporder='guest_u:s0$xguest_u:s0$user_u:s0-" "s0:c0.c1023$staff_u:s0-s0:c0.c1023$unconfined_u:s0-s0:c0.c1023'\n" msgstr "" #: ipalib/plugins/config.py:80 msgid "searchtimelimit must be -1 or > 1." msgstr "" #: ipalib/plugins/config.py:87 msgid "configuration options" msgstr "" #: ipalib/plugins/config.py:97 ipalib/plugins/config.py:98 msgid "Configuration" msgstr "" #: ipalib/plugins/config.py:103 msgid "Maximum username length" msgstr "" #: ipalib/plugins/config.py:108 msgid "Home directory base" msgstr "" #: ipalib/plugins/config.py:109 msgid "Default location of home directories" msgstr "" #: ipalib/plugins/config.py:113 msgid "Default shell" msgstr "" #: ipalib/plugins/config.py:114 msgid "Default shell for new users" msgstr "" #: ipalib/plugins/config.py:118 msgid "Default users group" msgstr "" #: ipalib/plugins/config.py:119 msgid "Default group for new users" msgstr "" #: ipalib/plugins/config.py:123 ipalib/plugins/config.py:124 msgid "Default e-mail domain" msgstr "" #: ipalib/plugins/config.py:128 msgid "Search time limit" msgstr "" #: ipalib/plugins/config.py:129 msgid "" "Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)" msgstr "" #: ipalib/plugins/config.py:134 msgid "Search size limit" msgstr "" #: ipalib/plugins/config.py:135 msgid "Maximum number of records to search (-1 is unlimited)" msgstr "" #: ipalib/plugins/config.py:140 msgid "User search fields" msgstr "" #: ipalib/plugins/config.py:141 msgid "A comma-separated list of fields to search in when searching for users" msgstr "" #: ipalib/plugins/config.py:146 msgid "A comma-separated list of fields to search in when searching for groups" msgstr "" #: ipalib/plugins/config.py:150 ipalib/plugins/config.py:151 msgid "Enable migration mode" msgstr "" #: ipalib/plugins/config.py:155 msgid "Certificate Subject base" msgstr "" #: ipalib/plugins/config.py:156 msgid "Base for certificate subjects (OU=Test,O=Example)" msgstr "" #: ipalib/plugins/config.py:161 msgid "Default group objectclasses" msgstr "" #: ipalib/plugins/config.py:162 msgid "Default group objectclasses (comma-separated list)" msgstr "" #: ipalib/plugins/config.py:167 msgid "Default user objectclasses" msgstr "" #: ipalib/plugins/config.py:168 msgid "Default user objectclasses (comma-separated list)" msgstr "" #: ipalib/plugins/config.py:173 msgid "Password Expiration Notification (days)" msgstr "" #: ipalib/plugins/config.py:174 msgid "Number of days's notice of impending password expiration" msgstr "" #: ipalib/plugins/config.py:179 msgid "Password plugin features" msgstr "" #: ipalib/plugins/config.py:180 msgid "Extra hashes to generate in password plug-in" msgstr "" #: ipalib/plugins/config.py:186 msgid "SELinux user map order" msgstr "" #: ipalib/plugins/config.py:187 msgid "Order in increasing priority of SELinux users, delimited by $" msgstr "" #: ipalib/plugins/config.py:190 msgid "Default SELinux user" msgstr "" #: ipalib/plugins/config.py:191 msgid "Default SELinux user when no match is found in SELinux map rule" msgstr "" #: ipalib/plugins/config.py:195 msgid "Default PAC types" msgstr "" #: ipalib/plugins/config.py:196 msgid "Default types of PAC supported for services" msgstr "" #: ipalib/plugins/config.py:209 msgid "Modify configuration options." msgstr "" #: ipalib/plugins/config.py:218 msgid "The group doesn't exist" msgstr "" #: ipalib/plugins/config.py:233 #, python-format msgid "attribute \"%s\" not allowed" msgstr "" #: ipalib/plugins/config.py:241 msgid "May not be empty" msgstr "" #: ipalib/plugins/config.py:259 #, python-format msgid "%(obj)s default attribute %(attr)s would not be allowed!" msgstr "" #: ipalib/plugins/config.py:291 msgid "A list of SELinux users delimited by $ expected" msgstr "" #: ipalib/plugins/config.py:295 #, python-format msgid "SELinux user '%(user)s' is not valid: %(error)s" msgstr "" #: ipalib/plugins/config.py:307 msgid "SELinux user map default user not in order list" msgstr "" #: ipalib/plugins/config.py:315 msgid "Show the current configuration." msgstr "" #: ipalib/plugins/delegation.py:29 msgid "" "\n" "Group to Group Delegation\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "Group to Group Delegations grants the members of one group to update a set\n" "of attributes of members of another group.\n" "\n" "EXAMPLES:\n" "\n" " Add a delegation rule to allow managers to edit employee's addresses:\n" " ipa delegation-add --attrs=street --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones. Add postalCode to the list:\n" " ipa delegation-mod --attrs=street --attrs=postalCode --group=managers --" "membergroup=employees \"managers edit employees' street\"\n" "\n" " Display our updated rule:\n" " ipa delegation-show \"managers edit employees' street\"\n" "\n" " Delete a rule:\n" " ipa delegation-del \"managers edit employees' street\"\n" msgstr "" #: ipalib/plugins/delegation.py:69 msgid "delegation" msgstr "" #: ipalib/plugins/delegation.py:70 msgid "delegations" msgstr "" #: ipalib/plugins/delegation.py:71 msgid "Delegations" msgstr "" #: ipalib/plugins/delegation.py:72 msgid "Delegation" msgstr "" #: ipalib/plugins/delegation.py:77 ipalib/plugins/delegation.py:78 msgid "Delegation name" msgstr "" #: ipalib/plugins/delegation.py:84 ipalib/plugins/selfservice.py:88 msgid "Permissions to grant (read, write). Default is write." msgstr "" #: ipalib/plugins/delegation.py:90 msgid "Attributes to which the delegation applies" msgstr "" #: ipalib/plugins/delegation.py:96 msgid "Member user group" msgstr "" #: ipalib/plugins/delegation.py:97 msgid "User group to apply delegation to" msgstr "" #: ipalib/plugins/delegation.py:130 msgid "Add a new delegation." msgstr "" #: ipalib/plugins/delegation.py:132 #, python-format msgid "Added delegation \"%(value)s\"" msgstr "" #: ipalib/plugins/delegation.py:151 msgid "Delete a delegation." msgstr "" #: ipalib/plugins/delegation.py:154 #, python-format msgid "Deleted delegation \"%(value)s\"" msgstr "" #: ipalib/plugins/delegation.py:169 msgid "Modify a delegation." msgstr "" #: ipalib/plugins/delegation.py:171 #, python-format msgid "Modified delegation \"%(value)s\"" msgstr "" #: ipalib/plugins/delegation.py:188 msgid "Search for delegations." msgstr "" #: ipalib/plugins/delegation.py:191 #, python-format msgid "%(count)d delegation matched" msgid_plural "%(count)d delegations matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/delegation.py:214 msgid "Display information about a delegation." msgstr "" #: ipalib/plugins/dns.py:41 msgid "" "\n" "Domain Name System (DNS)\n" "\n" "Manage DNS zone and resource records.\n" "\n" "\n" "USING STRUCTURED PER-TYPE OPTIONS\n" "\n" "There are many structured DNS RR types where DNS data stored in LDAP server\n" "is not just a scalar value, for example an IP address or a domain name, but\n" "a data structure which may be often complex. A good example is a LOC record\n" "[RFC1876] which consists of many mandatory and optional parts (degrees,\n" "minutes, seconds of latitude and longitude, altitude or precision).\n" "\n" "It may be difficult to manipulate such DNS records without making a mistake\n" "and entering an invalid value. DNS module provides an abstraction over " "these\n" "raw records and allows to manipulate each RR type with specific options. " "For\n" "each supported RR type, DNS module provides a standard option to manipulate\n" "a raw records with format ---rec, e.g. --mx-rec, and special " "options\n" "for every part of the RR structure with format ---, e.g.\n" "--mx-preference and --mx-exchanger.\n" "\n" "When adding a record, either RR specific options or standard option for a " "raw\n" "value can be used, they just should not be combined in one add operation. " "When\n" "modifying an existing entry, new RR specific options can be used to change\n" "one part of a DNS record, where the standard option for raw value is used\n" "to specify the modified value. The following example demonstrates\n" "a modification of MX record preference from 0 to 1 in a record without\n" "modifying the exchanger:\n" "ipa dnsrecord-mod --mx-rec=\"0 mx.example.com.\" --mx-preference=1\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add new zone:\n" " ipa dnszone-add example.com --name-server=ns \\\n" " --admin-email=admin@example.com \\\n" " --ip-address=10.0.0.1\n" "\n" " Add system permission that can be used for per-zone privilege delegation:\n" " ipa dnszone-add-permission example.com\n" "\n" " Modify the zone to allow dynamic updates for hosts own records in realm " "EXAMPLE.COM:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE\n" "\n" " This is the equivalent of:\n" " ipa dnszone-mod example.com --dynamic-update=TRUE \\\n" " --update-policy=\"grant EXAMPLE.COM krb5-self * A; grant EXAMPLE.COM " "krb5-self * AAAA; grant EXAMPLE.COM krb5-self * SSHFP;\"\n" "\n" " Modify the zone to allow zone transfers for local network only:\n" " ipa dnszone-mod example.com --allow-transfer=10.0.0.0/8\n" "\n" " Add new reverse zone specified by network IP address:\n" " ipa dnszone-add --name-from-ip=80.142.15.0/24 \\\n" " --name-server=ns.example.com.\n" "\n" " Add second nameserver for example.com:\n" " ipa dnsrecord-add example.com @ --ns-rec=nameserver2.example.com\n" "\n" " Add a mail server for example.com:\n" " ipa dnsrecord-add example.com @ --mx-rec=\"10 mail1\"\n" "\n" " Add another record using MX record specific options:\n" " ipa dnsrecord-add example.com @ --mx-preference=20 --mx-exchanger=mail2\n" "\n" " Add another record using interactive mode (started when dnsrecord-add, " "dnsrecord-mod,\n" " or dnsrecord-del are executed with no options):\n" " ipa dnsrecord-add example.com @\n" " Please choose a type of DNS resource record to be added\n" " The most common types for this type of zone are: NS, MX, LOC\n" "\n" " DNS resource record type: MX\n" " MX Preference: 30\n" " MX Exchanger: mail3\n" " Record name: example.com\n" " MX record: 10 mail1, 20 mail2, 30 mail3\n" " NS record: nameserver.example.com., nameserver2.example.com.\n" "\n" " Delete previously added nameserver from example.com:\n" " ipa dnsrecord-del example.com @ --ns-rec=nameserver2.example.com.\n" "\n" " Add LOC record for example.com:\n" " ipa dnsrecord-add example.com @ --loc-rec=\"49 11 42.4 N 16 36 29.6 E " "227.64m\"\n" "\n" " Add new A record for www.example.com. Create a reverse record in " "appropriate\n" " reverse zone as well. In this case a PTR record \"2\" pointing to www." "example.com\n" " will be created in zone 15.142.80.in-addr.arpa.\n" " ipa dnsrecord-add example.com www --a-rec=80.142.15.2 --a-create-reverse\n" "\n" " Add new PTR record for www.example.com\n" " ipa dnsrecord-add 15.142.80.in-addr.arpa. 2 --ptr-rec=www.example.com.\n" "\n" " Add new SRV records for LDAP servers. Three quarters of the requests\n" " should go to fast.example.com, one quarter to slow.example.com. If neither\n" " is available, switch to backup.example.com.\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 3 389 fast.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"0 1 389 slow.example." "com\"\n" " ipa dnsrecord-add example.com _ldap._tcp --srv-rec=\"1 1 389 backup." "example.com\"\n" "\n" " The interactive mode can be used for easy modification:\n" " ipa dnsrecord-mod example.com _ldap._tcp\n" " No option to modify specific record provided.\n" " Current DNS record contents:\n" "\n" " SRV record: 0 3 389 fast.example.com, 0 1 389 slow.example.com, 1 1 389 " "backup.example.com\n" "\n" " Modify SRV record '0 3 389 fast.example.com'? Yes/No (default No):\n" " Modify SRV record '0 1 389 slow.example.com'? Yes/No (default No): y\n" " SRV Priority [0]: (keep the default value)\n" " SRV Weight [1]: 2 (modified value)\n" " SRV Port [389]: (keep the default value)\n" " SRV Target [slow.example.com]: (keep the default value)\n" " 1 SRV record skipped. Only one value per DNS record type can be modified " "at one time.\n" " Record name: _ldap._tcp\n" " SRV record: 0 3 389 fast.example.com, 1 1 389 backup.example.com, 0 2 " "389 slow.example.com\n" "\n" " After this modification, three fifths of the requests should go to\n" " fast.example.com and two fifths to slow.example.com.\n" "\n" " An example of the interactive mode for dnsrecord-del command:\n" " ipa dnsrecord-del example.com www\n" " No option to delete specific record provided.\n" " Delete all? Yes/No (default No): (do not delete all records)\n" " Current DNS record contents:\n" "\n" " A record: 1.2.3.4, 11.22.33.44\n" "\n" " Delete A record '1.2.3.4'? Yes/No (default No):\n" " Delete A record '11.22.33.44'? Yes/No (default No): y\n" " Record name: www\n" " A record: 1.2.3.4 (A record 11.22.33.44 has been " "deleted)\n" "\n" " Show zone example.com:\n" " ipa dnszone-show example.com\n" "\n" " Find zone with \"example\" in its domain name:\n" " ipa dnszone-find example\n" "\n" " Find records for resources with \"www\" in their name in zone example.com:\n" " ipa dnsrecord-find example.com www\n" "\n" " Find A records with value 10.10.0.1 in zone example.com\n" " ipa dnsrecord-find example.com --a-rec=10.10.0.1\n" "\n" " Show records for resource www in zone example.com\n" " ipa dnsrecord-show example.com www\n" "\n" " Delegate zone sub.example to another nameserver:\n" " ipa dnsrecord-add example.com ns.sub --a-rec=10.0.100.5\n" " ipa dnsrecord-add example.com sub --ns-rec=ns.sub.example.com.\n" "\n" " If global forwarder is configured, all requests to sub.example.com will be\n" " routed through the global forwarder. To change the behavior for example." "com\n" " zone only and forward the request directly to ns.sub.example.com., global\n" " forwarding may be disabled per-zone:\n" " ipa dnszone-mod example.com --forward-policy=none\n" "\n" " Forward all requests for the zone external.com to another nameserver using\n" " a \"first\" policy (it will send the queries to the selected forwarder and " "if\n" " not answered it will use global resolvers):\n" " ipa dnszone-add external.com\n" " ipa dnszone-mod external.com --forwarder=10.20.0.1 \\\n" " --forward-policy=first\n" "\n" " Delete zone example.com with all resource records:\n" " ipa dnszone-del example.com\n" "\n" " Resolve a host name to see if it exists (will add default IPA domain\n" " if one is not included):\n" " ipa dns-resolve www.example.com\n" " ipa dns-resolve www\n" "\n" "\n" "GLOBAL DNS CONFIGURATION\n" "\n" "DNS configuration passed to command line install script is stored in a " "local\n" "configuration file on each IPA server where DNS service is configured. " "These\n" "local settings can be overridden with a common configuration stored in LDAP\n" "server:\n" "\n" " Show global DNS configuration:\n" " ipa dnsconfig-show\n" "\n" " Modify global DNS configuration and set a list of global forwarders:\n" " ipa dnsconfig-mod --forwarder=10.0.0.1\n" msgstr "" #: ipalib/plugins/dns.py:293 #, python-format msgid "invalid IP address version (is %(value)d, must be %(required_value)d)!" msgstr "" #: ipalib/plugins/dns.py:296 msgid "invalid IP address format" msgstr "" #: ipalib/plugins/dns.py:309 msgid "invalid IP network format" msgstr "" #: ipalib/plugins/dns.py:318 msgid "each ACL element must be terminated with a semicolon" msgstr "" #: ipalib/plugins/dns.py:335 msgid "invalid address format" msgstr "" #: ipalib/plugins/dns.py:379 ipalib/plugins/dns.py:422 #, python-format msgid "invalid domain-name: %s" msgstr "" #: ipalib/plugins/dns.py:408 #, python-format msgid "%(port)s is not a valid port" msgstr "" #: ipalib/plugins/dns.py:484 #, python-format msgid "DNS reverse zone for IP address %(addr)s not found" msgstr "" #: ipalib/plugins/dns.py:496 #, python-format msgid "DNS zone %(zone)s not found" msgstr "" #: ipalib/plugins/dns.py:510 #, python-format msgid "IP address %(ip)s is already assigned in domain %(domain)s." msgstr "" #: ipalib/plugins/dns.py:523 #, python-format msgid "" "Reverse record for IP address %(ip)s already exists in reverse zone %(zone)s." msgstr "" #: ipalib/plugins/dns.py:559 #, python-format msgid "%s record" msgstr "" #: ipalib/plugins/dns.py:561 #, python-format msgid "Raw %s records" msgstr "" #: ipalib/plugins/dns.py:562 #, python-format msgid "%s Record" msgstr "" #: ipalib/plugins/dns.py:563 #, python-format msgid "(see RFC %s for details)" msgstr "" #: ipalib/plugins/dns.py:619 #, python-format msgid "'%s' is a required part of DNS record" msgstr "" #: ipalib/plugins/dns.py:626 msgid "Invalid number of parts!" msgstr "" #: ipalib/plugins/dns.py:681 #, python-format msgid "DNS RR type \"%s\" is not supported by bind-dyndb-ldap plugin" msgstr "" #: ipalib/plugins/dns.py:697 #, python-format msgid "format must be specified as \"%(format)s\" %(rfcs)s" msgstr "" #: ipalib/plugins/dns.py:821 msgid "Create reverse" msgstr "" #: ipalib/plugins/dns.py:822 msgid "Create reverse record for this IP Address" msgstr "" #: ipalib/plugins/dns.py:857 #, python-format msgid "Cannot create reverse record for \"%(value)s\": %(exc)s" msgstr "" #: ipalib/plugins/dns.py:866 ipalib/plugins/dns.py:889 #: ipalib/plugins/host.py:407 msgid "IP Address" msgstr "" #: ipalib/plugins/dns.py:875 ipalib/plugins/dns.py:1486 msgid "Record data" msgstr "" #: ipalib/plugins/dns.py:898 msgid "Subtype" msgstr "" #: ipalib/plugins/dns.py:904 ipalib/plugins/dns.py:943 #: ipalib/plugins/dns.py:1196 ipalib/plugins/dns.py:1293 #: ipalib/plugins/dns.py:2930 msgid "Hostname" msgstr "" #: ipalib/plugins/dns.py:918 msgid "Certificate Type" msgstr "" #: ipalib/plugins/dns.py:923 ipalib/plugins/dns.py:978 #: ipalib/plugins/dns.py:1376 msgid "Key Tag" msgstr "" #: ipalib/plugins/dns.py:928 ipalib/plugins/dns.py:983 #: ipalib/plugins/dns.py:1017 ipalib/plugins/dns.py:1354 #: ipalib/plugins/dns.py:1402 msgid "Algorithm" msgstr "" #: ipalib/plugins/dns.py:933 msgid "Certificate/CRL" msgstr "" #: ipalib/plugins/dns.py:944 msgid "A hostname which this alias hostname points to" msgstr "" #: ipalib/plugins/dns.py:964 ipalib/plugins/dns.py:1330 #: ipalib/plugins/internal.py:502 msgid "Target" msgstr "" #: ipalib/plugins/dns.py:988 msgid "Digest Type" msgstr "" #: ipalib/plugins/dns.py:993 msgid "Digest" msgstr "" #: ipalib/plugins/dns.py:1007 ipalib/plugins/dns.py:1272 msgid "Flags" msgstr "" #: ipalib/plugins/dns.py:1012 msgid "Protocol" msgstr "" #: ipalib/plugins/dns.py:1022 msgid "Public Key" msgstr "" #: ipalib/plugins/dns.py:1036 ipalib/plugins/dns.py:1177 #: ipalib/plugins/dns.py:1266 msgid "Preference" msgstr "" #: ipalib/plugins/dns.py:1037 ipalib/plugins/dns.py:1178 msgid "Preference given to this exchanger. Lower values are more preferred" msgstr "" #: ipalib/plugins/dns.py:1043 ipalib/plugins/dns.py:1184 msgid "Exchanger" msgstr "" #: ipalib/plugins/dns.py:1044 msgid "A host willing to act as a key exchanger" msgstr "" #: ipalib/plugins/dns.py:1053 msgid "Degrees Latitude" msgstr "" #: ipalib/plugins/dns.py:1058 msgid "Minutes Latitude" msgstr "" #: ipalib/plugins/dns.py:1063 msgid "Seconds Latitude" msgstr "" #: ipalib/plugins/dns.py:1069 msgid "Direction Latitude" msgstr "" #: ipalib/plugins/dns.py:1073 msgid "Degrees Longitude" msgstr "" #: ipalib/plugins/dns.py:1078 msgid "Minutes Longitude" msgstr "" #: ipalib/plugins/dns.py:1083 msgid "Seconds Longitude" msgstr "" #: ipalib/plugins/dns.py:1089 msgid "Direction Longitude" msgstr "" #: ipalib/plugins/dns.py:1093 msgid "Altitude" msgstr "" #: ipalib/plugins/dns.py:1099 msgid "Size" msgstr "" #: ipalib/plugins/dns.py:1105 msgid "Horizontal Precision" msgstr "" #: ipalib/plugins/dns.py:1111 msgid "Vertical Precision" msgstr "" #: ipalib/plugins/dns.py:1118 msgid "" "format must be specified as\n" " \"d1 [m1 [s1]] {\"N\"|\"S\"} d2 [m2 [s2]] {\"E\"|\"W\"} alt[\"m\"] " "[siz[\"m\"] [hp[\"m\"] [vp[\"m\"]]]]\"\n" " where:\n" " d1: [0 .. 90] (degrees latitude)\n" " d2: [0 .. 180] (degrees longitude)\n" " m1, m2: [0 .. 59] (minutes latitude/longitude)\n" " s1, s2: [0 .. 59.999] (seconds latitude/longitude)\n" " alt: [-100000.00 .. 42849672.95] BY .01 (altitude in meters)\n" " siz, hp, vp: [0 .. 90000000.00] (size/precision in meters)\n" " See RFC 1876 for details" msgstr "" #: ipalib/plugins/dns.py:1167 #, python-format msgid "'%(required)s' must not be empty when '%(name)s' is set" msgstr "" #: ipalib/plugins/dns.py:1185 msgid "A host willing to act as a mail exchanger" msgstr "" #: ipalib/plugins/dns.py:1203 msgid "" "format must be specified as \"NEXT TYPE1 [TYPE2 [TYPE3 [...]]]\" (see RFC " "4034 for details)" msgstr "" #: ipalib/plugins/dns.py:1210 msgid "Next Domain Name" msgstr "" #: ipalib/plugins/dns.py:1213 msgid "Type Map" msgstr "" #: ipalib/plugins/dns.py:1253 msgid "flags must be one of \"S\", \"A\", \"U\", or \"P\"" msgstr "" #: ipalib/plugins/dns.py:1261 msgid "Order" msgstr "" #: ipalib/plugins/dns.py:1276 ipalib/plugins/hbactest.py:265 #: ipalib/plugins/internal.py:551 ipalib/plugins/service.py:316 msgid "Service" msgstr "" #: ipalib/plugins/dns.py:1279 msgid "Regular Expression" msgstr "" #: ipalib/plugins/dns.py:1282 msgid "Replacement" msgstr "" #: ipalib/plugins/dns.py:1294 msgid "The hostname this reverse record points to" msgstr "" #: ipalib/plugins/dns.py:1314 ipalib/plugins/pwpolicy.py:267 msgid "Priority" msgstr "" #: ipalib/plugins/dns.py:1319 msgid "Weight" msgstr "" #: ipalib/plugins/dns.py:1324 msgid "Port" msgstr "" #: ipalib/plugins/dns.py:1331 msgid "" "The domain name of the target host or '.' if the service is decidedly not " "available at this domain" msgstr "" #: ipalib/plugins/dns.py:1340 msgid "the value does not follow \"YYYYMMDDHHMMSS\" time format" msgstr "" #: ipalib/plugins/dns.py:1350 msgid "Type Covered" msgstr "" #: ipalib/plugins/dns.py:1359 msgid "Labels" msgstr "" #: ipalib/plugins/dns.py:1364 msgid "Original TTL" msgstr "" #: ipalib/plugins/dns.py:1369 msgid "Signature Expiration" msgstr "" #: ipalib/plugins/dns.py:1373 msgid "Signature Inception" msgstr "" #: ipalib/plugins/dns.py:1381 msgid "Signer's Name" msgstr "" #: ipalib/plugins/dns.py:1384 msgid "Signature" msgstr "" #: ipalib/plugins/dns.py:1407 msgid "Fingerprint Type" msgstr "" #: ipalib/plugins/dns.py:1412 msgid "Fingerprint" msgstr "" #: ipalib/plugins/dns.py:1433 msgid "Text Data" msgstr "" #: ipalib/plugins/dns.py:1480 msgid "Records" msgstr "" #: ipalib/plugins/dns.py:1483 msgid "Record type" msgstr "" #: ipalib/plugins/dns.py:1516 #, python-format msgid "Nameserver '%(host)s' does not have a corresponding A/AAAA record" msgstr "" #: ipalib/plugins/dns.py:1534 msgid "Managedby permission" msgstr "" #: ipalib/plugins/dns.py:1543 msgid "DNS zone" msgstr "" #: ipalib/plugins/dns.py:1544 msgid "DNS zones" msgstr "" #: ipalib/plugins/dns.py:1553 msgid "DNS Zones" msgstr "" #: ipalib/plugins/dns.py:1554 msgid "DNS Zone" msgstr "" #: ipalib/plugins/dns.py:1560 msgid "Zone name" msgstr "" #: ipalib/plugins/dns.py:1561 msgid "Zone name (FQDN)" msgstr "" #: ipalib/plugins/dns.py:1567 msgid "Reverse zone IP network" msgstr "" #: ipalib/plugins/dns.py:1568 msgid "IP network to create reverse zone name from" msgstr "" #: ipalib/plugins/dns.py:1573 msgid "Authoritative nameserver" msgstr "" #: ipalib/plugins/dns.py:1574 msgid "Authoritative nameserver domain name" msgstr "" #: ipalib/plugins/dns.py:1580 ipalib/plugins/dns.py:1581 msgid "Administrator e-mail address" msgstr "" #: ipalib/plugins/dns.py:1587 msgid "SOA serial" msgstr "" #: ipalib/plugins/dns.py:1588 msgid "SOA record serial number" msgstr "" #: ipalib/plugins/dns.py:1596 msgid "SOA refresh" msgstr "" #: ipalib/plugins/dns.py:1597 msgid "SOA record refresh time" msgstr "" #: ipalib/plugins/dns.py:1605 msgid "SOA retry" msgstr "" #: ipalib/plugins/dns.py:1606 msgid "SOA record retry time" msgstr "" #: ipalib/plugins/dns.py:1614 msgid "SOA expire" msgstr "" #: ipalib/plugins/dns.py:1615 msgid "SOA record expire time" msgstr "" #: ipalib/plugins/dns.py:1623 msgid "SOA minimum" msgstr "" #: ipalib/plugins/dns.py:1624 msgid "How long should negative responses be cached" msgstr "" #: ipalib/plugins/dns.py:1632 msgid "SOA time to live" msgstr "" #: ipalib/plugins/dns.py:1633 msgid "SOA record time to live" msgstr "" #: ipalib/plugins/dns.py:1639 msgid "SOA class" msgstr "" #: ipalib/plugins/dns.py:1640 msgid "SOA record class" msgstr "" #: ipalib/plugins/dns.py:1645 ipalib/plugins/dns.py:1646 msgid "BIND update policy" msgstr "" #: ipalib/plugins/dns.py:1652 msgid "Active zone" msgstr "" #: ipalib/plugins/dns.py:1653 msgid "Is zone active?" msgstr "" #: ipalib/plugins/dns.py:1659 msgid "Dynamic update" msgstr "" #: ipalib/plugins/dns.py:1660 msgid "Allow dynamic updates." msgstr "" #: ipalib/plugins/dns.py:1669 msgid "Allow query" msgstr "" #: ipalib/plugins/dns.py:1670 msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "issue queries" msgstr "" #: ipalib/plugins/dns.py:1678 msgid "Allow transfer" msgstr "" #: ipalib/plugins/dns.py:1679 msgid "" "Semicolon separated list of IP addresses or networks which are allowed to " "transfer the zone" msgstr "" #: ipalib/plugins/dns.py:1686 msgid "Zone forwarders" msgstr "" #: ipalib/plugins/dns.py:1687 msgid "" "Per-zone forwarders. A custom port can be specified for each forwarder using " "a standard format \"IP_ADDRESS port PORT\"" msgstr "" #: ipalib/plugins/dns.py:1693 ipalib/plugins/dns.py:2999 msgid "Forward policy" msgstr "" #: ipalib/plugins/dns.py:1694 msgid "" "Per-zone conditional forwarding policy. Set to \"none\" to disable " "forwarding to global forwarder for this zone. In that case, conditional zone " "forwarders are disregarded." msgstr "" #: ipalib/plugins/dns.py:1701 ipalib/plugins/dns.py:3006 msgid "Allow PTR sync" msgstr "" #: ipalib/plugins/dns.py:1702 msgid "" "Allow synchronization of forward (A, AAAA) and reverse (PTR) records in the " "zone" msgstr "" #: ipalib/plugins/dns.py:1764 msgid "Create new DNS zone (SOA record)." msgstr "" #: ipalib/plugins/dns.py:1769 ipalib/plugins/dns.py:1904 #: ipalib/plugins/dns.py:2365 ipalib/plugins/host.py:399 #: ipalib/plugins/permission.py:298 ipalib/plugins/realmdomains.py:97 #: ipalib/plugins/service.py:369 msgid "Force" msgstr "" #: ipalib/plugins/dns.py:1770 msgid "Force DNS zone creation even if nameserver is not resolvable." msgstr "" #: ipalib/plugins/dns.py:1773 msgid "Add forward record for nameserver located in the created zone" msgstr "" #: ipalib/plugins/dns.py:1774 ipalib/plugins/dns.py:1795 msgid "Nameserver IP address" msgstr "" #: ipalib/plugins/dns.py:1801 msgid "DNS is not configured" msgstr "" #: ipalib/plugins/dns.py:1811 msgid "Nameserver address is not a domain name" msgstr "" #: ipalib/plugins/dns.py:1824 msgid "Nameserver for reverse zone cannot be a relative DNS name" msgstr "" #: ipalib/plugins/dns.py:1828 msgid "Nameserver DNS record is created for for forward zones only" msgstr "" #: ipalib/plugins/dns.py:1832 msgid "Nameserver DNS record is created only for nameservers in current zone" msgstr "" #: ipalib/plugins/dns.py:1873 msgid "Delete DNS zone (SOA record)." msgstr "" #: ipalib/plugins/dns.py:1875 #, python-format msgid "Deleted DNS zone \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:1900 msgid "Modify DNS zone (SOA record)." msgstr "" #: ipalib/plugins/dns.py:1905 msgid "Force nameserver change even if nameserver not in DNS" msgstr "" #: ipalib/plugins/dns.py:1922 msgid "Search for DNS zones (SOA records)." msgstr "" #: ipalib/plugins/dns.py:1946 msgid "Forward zones only" msgstr "" #: ipalib/plugins/dns.py:1948 msgid "Search for forward zones only" msgstr "" #: ipalib/plugins/dns.py:1968 msgid "Display information about a DNS zone (SOA record)." msgstr "" #: ipalib/plugins/dns.py:1976 msgid "Disable DNS Zone." msgstr "" #: ipalib/plugins/dns.py:1979 #, python-format msgid "Disabled DNS zone \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:1997 msgid "Enable DNS Zone." msgstr "" #: ipalib/plugins/dns.py:2000 #, python-format msgid "Enabled DNS zone \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:2017 msgid "Add a permission for per-zone access delegation." msgstr "" #: ipalib/plugins/dns.py:2020 #, python-format msgid "Added system permission \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:2053 msgid "Remove a permission for per-zone access delegation." msgstr "" #: ipalib/plugins/dns.py:2056 #, python-format msgid "Removed system permission \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:2087 msgid "DNS resource record" msgstr "" #: ipalib/plugins/dns.py:2088 msgid "DNS resource records" msgstr "" #: ipalib/plugins/dns.py:2093 msgid "DNS Resource Records" msgstr "" #: ipalib/plugins/dns.py:2094 msgid "DNS Resource Record" msgstr "" #: ipalib/plugins/dns.py:2100 ipalib/plugins/dns.py:2101 msgid "Record name" msgstr "" #: ipalib/plugins/dns.py:2106 ipalib/plugins/dns.py:2107 msgid "Time to live" msgstr "" #: ipalib/plugins/dns.py:2111 ipalib/plugins/host.py:331 msgid "Class" msgstr "" #: ipalib/plugins/dns.py:2112 msgid "DNS class" msgstr "" #: ipalib/plugins/dns.py:2118 msgid "Structured" msgstr "" #: ipalib/plugins/dns.py:2119 msgid "Parse all raw DNS records and return them in a structured way" msgstr "" #: ipalib/plugins/dns.py:2150 #, python-format msgid "" "Reverse zone for PTR record should be a sub-zone of one the following fully " "qualified domains: %s" msgstr "" #: ipalib/plugins/dns.py:2156 #, python-format msgid "" "Reverse zone %(name)s requires exactly %(count)d IP address components, " "%(user_count)d given" msgstr "" #: ipalib/plugins/dns.py:2328 msgid "only one CNAME record is allowed per name (RFC 2136, section 1.1.5)" msgstr "" #: ipalib/plugins/dns.py:2334 msgid "" "CNAME record is not allowed to coexist with any other record (RFC 1034, " "section 3.6.2)" msgstr "" #: ipalib/plugins/dns.py:2346 msgid "only one DNAME record is allowed per name (RFC 6672, section 2.4)" msgstr "" #: ipalib/plugins/dns.py:2351 msgid "" "DNAME record is not allowed to coexist with an NS record except when located " "in a zone root record (RFC 6672, section 2.3)" msgstr "" #: ipalib/plugins/dns.py:2359 msgid "Add new DNS resource record." msgstr "" #: ipalib/plugins/dns.py:2367 msgid "force NS record creation even if its hostname is not in DNS" msgstr "" #: ipalib/plugins/dns.py:2404 msgid "Please choose a type of DNS resource record to be added" msgstr "" #: ipalib/plugins/dns.py:2405 #, python-format msgid "The most common types for this type of zone are: %s\n" msgstr "" #: ipalib/plugins/dns.py:2410 msgid "DNS resource record type" msgstr "" #: ipalib/plugins/dns.py:2426 #, python-format msgid "Invalid or unsupported type. Allowed values are: %s" msgstr "" #: ipalib/plugins/dns.py:2454 #, python-format msgid "Raw value of a DNS record was already set by \"%(name)s\" option" msgstr "" #: ipalib/plugins/dns.py:2549 msgid "Modify a DNS resource record." msgstr "" #: ipalib/plugins/dns.py:2566 msgid "DNS zone root record cannot be renamed" msgstr "" #: ipalib/plugins/dns.py:2584 msgid "DNS records can be only updated one at a time" msgstr "" #: ipalib/plugins/dns.py:2664 msgid "No option to modify specific record provided." msgstr "" #: ipalib/plugins/dns.py:2667 ipalib/plugins/dns.py:2839 msgid "Current DNS record contents:\n" msgstr "" #: ipalib/plugins/dns.py:2689 #, python-format msgid "Modify %(name)s '%(value)s'?" msgstr "" #: ipalib/plugins/dns.py:2697 #, python-format msgid "" "%(count)d %(type)s record skipped. Only one value per DNS record type can be " "modified at one time." msgid_plural "" "%(count)d %(type)s records skipped. Only one value per DNS record type can " "be modified at one time." msgstr[0] "" msgstr[1] "" #: ipalib/plugins/dns.py:2709 #, python-format msgid "Deleted record \"%(value)s\"" msgstr "" #: ipalib/plugins/dns.py:2716 msgid "Delete DNS resource record." msgstr "" #: ipalib/plugins/dns.py:2720 msgid "" "Neither --del-all nor options to delete a specific record provided.\n" "Command help may be consulted for all supported record types." msgstr "" #: ipalib/plugins/dns.py:2726 msgid "Delete all associated records" msgstr "" #: ipalib/plugins/dns.py:2792 #, python-format msgid "Zone record '%s' cannot be deleted" msgstr "" #: ipalib/plugins/dns.py:2831 msgid "No option to delete specific record provided." msgstr "" #: ipalib/plugins/dns.py:2832 msgid "Delete all?" msgstr "" #: ipalib/plugins/dns.py:2860 #, python-format msgid "Delete %(name)s '%(value)s'?" msgstr "" #: ipalib/plugins/dns.py:2871 msgid "Display DNS resource." msgstr "" #: ipalib/plugins/dns.py:2888 msgid "Search for DNS resources." msgstr "" #: ipalib/plugins/dns.py:2923 msgid "Resolve a host name in DNS." msgstr "" #: ipalib/plugins/dns.py:2926 #, python-format msgid "Found '%(value)s'" msgstr "" #: ipalib/plugins/dns.py:2943 #, python-format msgid "Host '%(host)s' not found" msgstr "" #: ipalib/plugins/dns.py:2980 msgid "DNS configuration options" msgstr "" #: ipalib/plugins/dns.py:2985 ipalib/plugins/dns.py:2986 msgid "DNS Global Configuration" msgstr "" #: ipalib/plugins/dns.py:2992 msgid "Global forwarders" msgstr "" #: ipalib/plugins/dns.py:2993 msgid "" "Global forwarders. A custom port can be specified for each forwarder using a " "standard format \"IP_ADDRESS port PORT\"" msgstr "" #: ipalib/plugins/dns.py:3000 msgid "" "Global forwarding policy. Set to \"none\" to disable any configured global " "forwarders." msgstr "" #: ipalib/plugins/dns.py:3007 msgid "Allow synchronization of forward (A, AAAA) and reverse (PTR) records" msgstr "" #: ipalib/plugins/dns.py:3011 msgid "Zone refresh interval" msgstr "" #: ipalib/plugins/dns.py:3025 msgid "Global DNS configuration is empty" msgstr "" #: ipalib/plugins/dns.py:3031 msgid "Modify global DNS configuration." msgstr "" #: ipalib/plugins/dns.py:3042 msgid "Show the current global DNS configuration." msgstr "" #: ipalib/plugins/group.py:33 msgid "" "\n" "Groups of users\n" "\n" "Manage groups of users. By default, new groups are POSIX groups. You\n" "can add the --nonposix option to the group-add command to mark a new group\n" "as non-POSIX. You can use the --posix argument with the group-mod command\n" "to convert a non-POSIX group into a POSIX group. POSIX groups cannot be\n" "converted to non-POSIX groups.\n" "\n" "Every group must have a description.\n" "\n" "POSIX groups must have a Group ID (GID) number. Changing a GID is\n" "supported but can have an impact on your file permissions. It is not " "necessary\n" "to supply a GID when creating a group. IPA will generate one automatically\n" "if it is not provided.\n" "\n" "EXAMPLES:\n" "\n" " Add a new group:\n" " ipa group-add --desc='local administrators' localadmins\n" "\n" " Add a new non-POSIX group:\n" " ipa group-add --nonposix --desc='remote administrators' remoteadmins\n" "\n" " Convert a non-POSIX group to posix:\n" " ipa group-mod --posix remoteadmins\n" "\n" " Add a new POSIX group with a specific Group ID number:\n" " ipa group-add --gid=500 --desc='unix admins' unixadmins\n" "\n" " Add a new POSIX group and let IPA assign a Group ID number:\n" " ipa group-add --desc='printer admins' printeradmins\n" "\n" " Remove a group:\n" " ipa group-del unixadmins\n" "\n" " To add the \"remoteadmins\" group to the \"localadmins\" group:\n" " ipa group-add-member --groups=remoteadmins localadmins\n" "\n" " Add multiple users to the \"localadmins\" group:\n" " ipa group-add-member --users=test1 --users=test2 localadmins\n" "\n" " Remove a user from the \"localadmins\" group:\n" " ipa group-remove-member --users=test2 localadmins\n" "\n" " Display information about a named group.\n" " ipa group-show localadmins\n" "\n" "External group membership is designed to allow users from trusted domains\n" "to be mapped to local POSIX groups in order to actually use IPA resources.\n" "External members should be added to groups that specifically created as\n" "external and non-POSIX. Such group later should be included into one of " "POSIX\n" "groups.\n" "\n" "An external group member is currently a Security Identifier (SID) as defined " "by\n" "the trusted domain. When adding external group members, it is possible to\n" "specify them in either SID, or DOM\\name, or name@domain format. IPA will " "attempt\n" "to resolve passed name to SID with the use of Global Catalog of the trusted " "domain.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" msgstr "" #: ipalib/plugins/group.py:120 ipalib/plugins/group.py:229 #: ipalib/plugins/group.py:449 ipalib/plugins/user.py:189 msgid "group" msgstr "" #: ipalib/plugins/group.py:121 msgid "groups" msgstr "" #: ipalib/plugins/group.py:140 ipalib/plugins/hbacrule.py:190 #: ipalib/plugins/internal.py:495 ipalib/plugins/selinuxusermap.py:195 #: ipalib/plugins/sudorule.py:159 msgid "User Groups" msgstr "" #: ipalib/plugins/group.py:141 msgid "User Group" msgstr "" #: ipalib/plugins/group.py:149 msgid "Group name" msgstr "" #: ipalib/plugins/group.py:156 ipalib/plugins/sudocmdgroup.py:79 msgid "Group description" msgstr "" #: ipalib/plugins/group.py:160 ipalib/plugins/user.py:311 msgid "GID" msgstr "" #: ipalib/plugins/group.py:161 msgid "GID (use this option to set it manually)" msgstr "" #: ipalib/plugins/group.py:170 msgid "External member" msgstr "" #: ipalib/plugins/group.py:171 msgid "Members of a trusted domain in DOM\\name or name@domain form" msgstr "" #: ipalib/plugins/group.py:177 msgid "Create a new group." msgstr "" #: ipalib/plugins/group.py:179 #, python-format msgid "Added group \"%(value)s\"" msgstr "" #: ipalib/plugins/group.py:184 msgid "Create as a non-POSIX group" msgstr "" #: ipalib/plugins/group.py:189 msgid "Allow adding external non-IPA members from trusted domains" msgstr "" #: ipalib/plugins/group.py:214 msgid "Delete group." msgstr "" #: ipalib/plugins/group.py:216 #, python-format msgid "Deleted group \"%(value)s\"" msgstr "" #: ipalib/plugins/group.py:230 msgid "privileged group" msgstr "" #: ipalib/plugins/group.py:248 msgid "Modify a group." msgstr "" #: ipalib/plugins/group.py:250 #, python-format msgid "Modified group \"%(value)s\"" msgstr "" #: ipalib/plugins/group.py:255 msgid "change to a POSIX group" msgstr "" #: ipalib/plugins/group.py:259 msgid "change to support external non-IPA members from trusted domains" msgstr "" #: ipalib/plugins/group.py:318 msgid "Search for groups." msgstr "" #: ipalib/plugins/group.py:323 #, python-format msgid "%(count)d group matched" msgid_plural "%(count)d groups matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/group.py:329 msgid "search for private groups" msgstr "" #: ipalib/plugins/group.py:333 msgid "search for POSIX groups" msgstr "" #: ipalib/plugins/group.py:337 msgid "" "search for groups with support of external non-IPA members from trusted " "domains" msgstr "" #: ipalib/plugins/group.py:341 msgid "search for non-POSIX groups" msgstr "" #: ipalib/plugins/group.py:388 msgid "Display information about a named group." msgstr "" #: ipalib/plugins/group.py:394 msgid "Add members to a group." msgstr "" #: ipalib/plugins/group.py:403 ipalib/plugins/group.py:457 #: ipalib/plugins/hbactest.py:382 msgid "" "Cannot perform external member validation without Samba 4 support installed. " "Make sure you have installed server-trust-ad sub-package of IPA on the server" msgstr "" #: ipalib/plugins/group.py:408 ipalib/plugins/group.py:462 #: ipalib/plugins/trust.py:368 msgid "" "Cannot perform join operation without own domain configured. Make sure you " "have run ipa-adtrust-install on the IPA server first" msgstr "" #: ipalib/plugins/group.py:436 msgid "Remove members from a group." msgstr "" #: ipalib/plugins/group.py:490 msgid "Detach a managed group from a user." msgstr "" #: ipalib/plugins/group.py:493 #, python-format msgid "Detached group \"%(value)s\" from user \"%(value)s\"" msgstr "" #: ipalib/plugins/group.py:514 msgid "not allowed to modify user entries" msgstr "" #: ipalib/plugins/group.py:520 msgid "not allowed to modify group entries" msgstr "" #: ipalib/plugins/group.py:539 msgid "Not a managed group" msgstr "" #: ipalib/plugins/hbacrule.py:25 msgid "" "\n" "Host-based access control\n" "\n" "Control who can access what services on what hosts. You\n" "can use HBAC to control which users or groups can\n" "access a service, or group of services, on a target host.\n" "\n" "You can also specify a category of users and target hosts.\n" "This is currently limited to \"all\", but might be expanded in the\n" "future.\n" "\n" "Target hosts in HBAC rules must be hosts managed by IPA.\n" "\n" "The available services and groups of services are controlled by the\n" "hbacsvc and hbacsvcgroup plug-ins respectively.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that grants all users access to the host \"server" "\" from\n" " anywhere:\n" " ipa hbacrule-add --usercat=all test1\n" " ipa hbacrule-add-host --hosts=server.example.com test1\n" "\n" " Display the properties of a named HBAC rule:\n" " ipa hbacrule-show test1\n" "\n" " Create a rule for a specific service. This lets the user john access\n" " the sshd service on any machine from any machine:\n" " ipa hbacrule-add --hostcat=all john_sshd\n" " ipa hbacrule-add-user --users=john john_sshd\n" " ipa hbacrule-add-service --hbacsvcs=sshd john_sshd\n" "\n" " Create a rule for a new service group. This lets the user john access\n" " the FTP service on any machine from any machine:\n" " ipa hbacsvcgroup-add ftpers\n" " ipa hbacsvc-add sftp\n" " ipa hbacsvcgroup-add-member --hbacsvcs=ftp --hbacsvcs=sftp ftpers\n" " ipa hbacrule-add --hostcat=all john_ftp\n" " ipa hbacrule-add-user --users=john john_ftp\n" " ipa hbacrule-add-service --hbacsvcgroups=ftpers john_ftp\n" "\n" " Disable a named HBAC rule:\n" " ipa hbacrule-disable test1\n" "\n" " Remove a named HBAC rule:\n" " ipa hbacrule-del allow_server\n" msgstr "" #: ipalib/plugins/hbacrule.py:89 msgid "Host-based access control commands" msgstr "" #: ipalib/plugins/hbacrule.py:93 msgid "The deny type has been deprecated." msgstr "" #: ipalib/plugins/hbacrule.py:115 msgid "HBAC rule" msgstr "" #: ipalib/plugins/hbacrule.py:116 msgid "HBAC rules" msgstr "" #: ipalib/plugins/hbacrule.py:134 msgid "HBAC Rules" msgstr "" #: ipalib/plugins/hbacrule.py:135 ipalib/plugins/selinuxusermap.py:167 msgid "HBAC Rule" msgstr "" #: ipalib/plugins/hbacrule.py:140 ipalib/plugins/selinuxusermap.py:158 #: ipalib/plugins/sudorule.py:106 msgid "Rule name" msgstr "" #: ipalib/plugins/hbacrule.py:145 msgid "Rule type (allow)" msgstr "" #: ipalib/plugins/hbacrule.py:146 msgid "Rule type" msgstr "" #: ipalib/plugins/hbacrule.py:156 ipalib/plugins/netgroup.py:139 #: ipalib/plugins/selinuxusermap.py:172 ipalib/plugins/sudorule.py:119 msgid "User category" msgstr "" #: ipalib/plugins/hbacrule.py:157 ipalib/plugins/netgroup.py:140 #: ipalib/plugins/selinuxusermap.py:173 ipalib/plugins/sudorule.py:120 msgid "User category the rule applies to" msgstr "" #: ipalib/plugins/hbacrule.py:162 ipalib/plugins/netgroup.py:145 #: ipalib/plugins/selinuxusermap.py:178 ipalib/plugins/sudorule.py:125 msgid "Host category" msgstr "" #: ipalib/plugins/hbacrule.py:163 ipalib/plugins/netgroup.py:146 #: ipalib/plugins/selinuxusermap.py:179 ipalib/plugins/sudorule.py:126 msgid "Host category the rule applies to" msgstr "" #: ipalib/plugins/hbacrule.py:169 msgid "Service category" msgstr "" #: ipalib/plugins/hbacrule.py:170 msgid "Service category the rule applies to" msgstr "" #: ipalib/plugins/hbacrule.py:182 ipalib/plugins/internal.py:658 #: ipalib/plugins/selinuxusermap.py:187 ipalib/plugins/sudorule.py:114 msgid "Enabled" msgstr "" #: ipalib/plugins/hbacrule.py:186 ipalib/plugins/internal.py:496 #: ipalib/plugins/selinuxusermap.py:191 ipalib/plugins/sudorule.py:155 #: ipalib/plugins/user.py:225 msgid "Users" msgstr "" #: ipalib/plugins/hbacrule.py:194 ipalib/plugins/host.py:256 #: ipalib/plugins/internal.py:490 ipalib/plugins/selinuxusermap.py:199 #: ipalib/plugins/sudorule.py:163 msgid "Hosts" msgstr "" #: ipalib/plugins/hbacrule.py:198 ipalib/plugins/hostgroup.py:75 #: ipalib/plugins/internal.py:489 ipalib/plugins/selinuxusermap.py:203 #: ipalib/plugins/sudorule.py:167 msgid "Host Groups" msgstr "" #: ipalib/plugins/hbacrule.py:204 ipalib/plugins/internal.py:437 #: ipalib/plugins/service.py:315 msgid "Services" msgstr "" #: ipalib/plugins/hbacrule.py:208 msgid "Service Groups" msgstr "" #: ipalib/plugins/hbacrule.py:218 msgid "Create a new HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:220 #, python-format msgid "Added HBAC rule \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacrule.py:232 msgid "Delete an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:234 #, python-format msgid "Deleted HBAC rule \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacrule.py:249 msgid "Modify an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:251 #, python-format msgid "Modified HBAC rule \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacrule.py:261 ipalib/plugins/netgroup.py:213 #: ipalib/plugins/sudorule.py:289 msgid "user category cannot be set to 'all' while there are allowed users" msgstr "" #: ipalib/plugins/hbacrule.py:263 ipalib/plugins/netgroup.py:215 #: ipalib/plugins/sudorule.py:291 msgid "host category cannot be set to 'all' while there are allowed hosts" msgstr "" #: ipalib/plugins/hbacrule.py:265 msgid "" "service category cannot be set to 'all' while there are allowed services" msgstr "" #: ipalib/plugins/hbacrule.py:272 msgid "Search for HBAC rules." msgstr "" #: ipalib/plugins/hbacrule.py:275 #, python-format msgid "%(count)d HBAC rule matched" msgid_plural "%(count)d HBAC rules matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/hbacrule.py:282 msgid "Display the properties of an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:288 msgid "Enable an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:290 #, python-format msgid "Enabled HBAC rule \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacrule.py:315 msgid "Disable an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:317 #, python-format msgid "Disabled HBAC rule \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacrule.py:349 ipalib/plugins/hbacrule.py:389 msgid "Access time" msgstr "" #: ipalib/plugins/hbacrule.py:423 msgid "Add users and groups to an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:437 ipalib/plugins/selinuxusermap.py:460 #: ipalib/plugins/sudorule.py:439 msgid "users cannot be added when user category='all'" msgstr "" #: ipalib/plugins/hbacrule.py:444 msgid "Remove users and groups from an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:453 msgid "Add target hosts and hostgroups to an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:467 ipalib/plugins/selinuxusermap.py:492 #: ipalib/plugins/sudorule.py:475 msgid "hosts cannot be added when host category='all'" msgstr "" #: ipalib/plugins/hbacrule.py:474 msgid "Remove target hosts and hostgroups from an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:507 msgid "Add services to an HBAC rule." msgstr "" #: ipalib/plugins/hbacrule.py:521 msgid "services cannot be added when service category='all'" msgstr "" #: ipalib/plugins/hbacrule.py:528 msgid "Remove service and service groups from an HBAC rule." msgstr "" #: ipalib/plugins/hbacsvc.py:27 msgid "" "\n" "HBAC Services\n" "\n" "The PAM services that HBAC can control access to. The name used here\n" "must match the service name that PAM is evaluating.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service:\n" " ipa hbacsvc-add tftp\n" "\n" " Modify an existing HBAC service:\n" " ipa hbacsvc-mod --desc=\"TFTP service\" tftp\n" "\n" " Search for HBAC services. This example will return two results, the FTP\n" " service and the newly-added tftp service:\n" " ipa hbacsvc-find ftp\n" "\n" " Delete an HBAC service:\n" " ipa hbacsvc-del tftp\n" "\n" msgstr "" #: ipalib/plugins/hbacsvc.py:50 ipalib/plugins/hbacsvcgroup.py:45 msgid "Host based access control commands" msgstr "" #: ipalib/plugins/hbacsvc.py:57 ipalib/plugins/hbacsvc.py:73 msgid "HBAC service" msgstr "" #: ipalib/plugins/hbacsvc.py:58 msgid "HBAC services" msgstr "" #: ipalib/plugins/hbacsvc.py:66 msgid "HBAC Services" msgstr "" #: ipalib/plugins/hbacsvc.py:67 msgid "HBAC Service" msgstr "" #: ipalib/plugins/hbacsvc.py:72 msgid "Service name" msgstr "" #: ipalib/plugins/hbacsvc.py:80 msgid "HBAC service description" msgstr "" #: ipalib/plugins/hbacsvc.py:88 msgid "Add a new HBAC service." msgstr "" #: ipalib/plugins/hbacsvc.py:90 #, python-format msgid "Added HBAC service \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvc.py:96 msgid "Delete an existing HBAC service." msgstr "" #: ipalib/plugins/hbacsvc.py:98 #, python-format msgid "Deleted HBAC service \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvc.py:104 msgid "Modify an HBAC service." msgstr "" #: ipalib/plugins/hbacsvc.py:106 #, python-format msgid "Modified HBAC service \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvc.py:112 msgid "Search for HBAC services." msgstr "" #: ipalib/plugins/hbacsvc.py:115 #, python-format msgid "%(count)d HBAC service matched" msgid_plural "%(count)d HBAC services matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/hbacsvc.py:122 msgid "Display information about an HBAC service." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:24 msgid "" "\n" "HBAC Service Groups\n" "\n" "HBAC service groups can contain any number of individual services,\n" "or \"members\". Every group must have a description.\n" "\n" "EXAMPLES:\n" "\n" " Add a new HBAC service group:\n" " ipa hbacsvcgroup-add --desc=\"login services\" login\n" "\n" " Add members to an HBAC service group:\n" " ipa hbacsvcgroup-add-member --hbacsvcs=sshd --hbacsvcs=login login\n" "\n" " Display information about a named group:\n" " ipa hbacsvcgroup-show login\n" "\n" " Delete an HBAC service group:\n" " ipa hbacsvcgroup-del login\n" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:52 msgid "HBAC service group" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:53 msgid "HBAC service groups" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:61 msgid "HBAC Service Groups" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:62 msgid "HBAC Service Group" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:67 msgid "Service group name" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:74 msgid "HBAC service group description" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:82 msgid "Add a new HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:84 #, python-format msgid "Added HBAC service group \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:90 msgid "Delete an HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:92 #, python-format msgid "Deleted HBAC service group \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:98 msgid "Modify an HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:100 #, python-format msgid "Modified HBAC service group \"%(value)s\"" msgstr "" #: ipalib/plugins/hbacsvcgroup.py:106 msgid "Search for an HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:109 #, python-format msgid "%(count)d HBAC service group matched" msgid_plural "%(count)d HBAC service groups matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/hbacsvcgroup.py:116 msgid "Display information about an HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:122 msgid "Add members to an HBAC service group." msgstr "" #: ipalib/plugins/hbacsvcgroup.py:128 msgid "Remove members from an HBAC service group." msgstr "" #: ipalib/plugins/hbactest.py:35 msgid "" "\n" "Simulate use of Host-based access controls\n" "\n" "HBAC rules control who can access what services on what hosts.\n" "You can use HBAC to control which users or groups can access a service,\n" "or group of services, on a target host.\n" "\n" "Since applying HBAC rules implies use of a production environment,\n" "this plugin aims to provide simulation of HBAC rules evaluation without\n" "having access to the production environment.\n" "\n" " Test user coming to a service on a named host against\n" " existing enabled rules.\n" "\n" " ipa hbactest --user= --host= --service=\n" " [--rules=rules-list] [--nodetail] [--enabled] [--disabled]\n" " [--sizelimit= ]\n" "\n" " --user, --host, and --service are mandatory, others are optional.\n" "\n" " If --rules is specified simulate enabling of the specified rules and test\n" " the login of the user using only these rules.\n" "\n" " If --enabled is specified, all enabled HBAC rules will be added to " "simulation\n" "\n" " If --disabled is specified, all disabled HBAC rules will be added to " "simulation\n" "\n" " If --nodetail is specified, do not return information about rules matched/" "not matched.\n" "\n" " If both --rules and --enabled are specified, apply simulation to --rules " "_and_\n" " all IPA enabled rules.\n" "\n" " If no --rules specified, simulation is run against all IPA enabled rules.\n" " By default there is a IPA-wide limit to number of entries fetched, you can " "change it\n" " with --sizelimit option.\n" "\n" "EXAMPLES:\n" "\n" " 1. Use all enabled HBAC rules in IPA database to simulate:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 2. Disable detailed summary of how rules were applied:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --nodetail\n" " --------------------\n" " Access granted: True\n" " --------------------\n" "\n" " 3. Test explicitly specified HBAC rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: myrule\n" "\n" " 4. Use all enabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --enabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Matched rules: allow_all\n" "\n" " 5. Test all disabled HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: new-rule\n" "\n" " 6. Test all disabled HBAC rules in IPA database + explicitly specified " "rules:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --rules=myrule --rules=my-second-rule --disabled\n" " ---------------------\n" " Access granted: False\n" " ---------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" "\n" " 7. Test all (enabled and disabled) HBAC rules in IPA database:\n" " $ ipa hbactest --user=a1a --host=bar --service=sshd \\\n" " --enabled --disabled\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Not matched rules: my-second-rule\n" " Not matched rules: my-third-rule\n" " Not matched rules: myrule\n" " Not matched rules: new-rule\n" " Matched rules: allow_all\n" "\n" "\n" "HBACTEST AND TRUSTED DOMAINS\n" "\n" "When an external trusted domain is configured in IPA, HBAC rules are also " "applied\n" "on users accessing IPA resources from the trusted domain. Trusted domain " "users and\n" "groups (and their SIDs) can be then assigned to external groups which can " "be\n" "members of POSIX groups in IPA which can be used in HBAC rules and thus " "allowing\n" "access to resources protected by the HBAC system.\n" "\n" "hbactest plugin is capable of testing access for both local IPA users and " "users\n" "from the trusted domains, either by a fully qualified user name or by user " "SID.\n" "Such user names need to have a trusted domain specified as a short name\n" "(DOMAIN\\Administrator) or with a user principal name (UPN), " "Administrator@ad.test.\n" "\n" "Please note that hbactest executed with a trusted domain user as --user " "parameter\n" "can be only run by members of \"trust admins\" group.\n" "\n" "EXAMPLES:\n" "\n" " 1. Test if a user from a trusted domain specified by its shortname " "matches any\n" " rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Administrator' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 2. Test if a user from a trusted domain specified by its domain name " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'Administrator@domain.com' --host `hostname` --" "service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 3. Test if a user from a trusted domain specified by its SID matches any " "rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-500 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Matched rules: can_login\n" "\n" " 4. Test if other user from a trusted domain specified by its SID matches " "any rule:\n" "\n" " $ ipa hbactest --user S-1-5-21-3035198329-144811719-1378114514-1203 \\\n" " --host `hostname` --service sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" "\n" " 5. Test if other user from a trusted domain specified by its shortname " "matches\n" " any rule:\n" "\n" " $ ipa hbactest --user 'DOMAIN\\Otheruser' --host `hostname` --service " "sshd\n" " --------------------\n" " Access granted: True\n" " --------------------\n" " Matched rules: allow_all\n" " Not matched rules: can_login\n" msgstr "" #: ipalib/plugins/hbactest.py:241 msgid "Simulate use of Host-based access controls" msgstr "" #: ipalib/plugins/hbactest.py:245 msgid "Warning" msgstr "" #: ipalib/plugins/hbactest.py:246 msgid "Matched rules" msgstr "" #: ipalib/plugins/hbactest.py:247 msgid "Not matched rules" msgstr "" #: ipalib/plugins/hbactest.py:248 msgid "Non-existent or invalid rules" msgstr "" #: ipalib/plugins/hbactest.py:249 msgid "Result of simulation" msgstr "" #: ipalib/plugins/hbactest.py:255 ipalib/plugins/krbtpolicy.py:85 #: ipalib/plugins/passwd.py:70 msgid "User name" msgstr "" #: ipalib/plugins/hbactest.py:261 msgid "Target host" msgstr "" #: ipalib/plugins/hbactest.py:269 msgid "Rules to test. If not specified, --enabled is assumed" msgstr "" #: ipalib/plugins/hbactest.py:274 msgid "Hide details which rules are matched, not matched, or invalid" msgstr "" #: ipalib/plugins/hbactest.py:278 msgid "Include all enabled IPA rules into test [default]" msgstr "" #: ipalib/plugins/hbactest.py:282 msgid "Include all disabled IPA rules into test" msgstr "" #: ipalib/plugins/hbactest.py:286 msgid "Maximum number of rules to process when no --rules is specified" msgstr "" #: ipalib/plugins/hbactest.py:364 msgid "Unresolved rules in --rules" msgstr "" #: ipalib/plugins/hbactest.py:388 ipalib/plugins/trust.py:507 msgid "" "Cannot search in trusted domains without own domain configured. Make sure " "you have run ipa-adtrust-install on the IPA server first" msgstr "" #: ipalib/plugins/hbactest.py:472 #, python-format msgid "Access granted: %s" msgstr "" #: ipalib/plugins/host.py:48 msgid "" "\n" "Hosts/Machines\n" "\n" "A host represents a machine. It can be used in a number of contexts:\n" "- service entries are associated with a host\n" "- a host stores the host/ service principal\n" "- a host can be used in Host-based Access Control (HBAC) rules\n" "- every enrolled client generates a host entry\n" "\n" "ENROLLMENT:\n" "\n" "There are three enrollment scenarios when enrolling a new client:\n" "\n" "1. You are enrolling as a full administrator. The host entry may exist\n" " or not. A full administrator is a member of the hostadmin role\n" " or the admins group.\n" "2. You are enrolling as a limited administrator. The host must already\n" " exist. A limited administrator is a member a role with the\n" " Host Enrollment privilege.\n" "3. The host has been created with a one-time password.\n" "\n" "\n" "RE-ENROLLMENT:\n" "\n" "Host that has been enrolled at some point, and lost its configuration (e.g. " "VM\n" "destroyed) can be re-enrolled.\n" "\n" "For more information, consult the manual pages for ipa-client-install.\n" "\n" "A host can optionally store information such as where it is located,\n" "the OS that it runs, etc.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host:\n" " ipa host-add --location=\"3rd floor lab\" --locality=Dallas test.example." "com\n" "\n" " Delete a host:\n" " ipa host-del test.example.com\n" "\n" " Add a new host with a one-time password:\n" " ipa host-add --os='Fedora 12' --password=Secret123 test.example.com\n" "\n" " Add a new host with a random one-time password:\n" " ipa host-add --os='Fedora 12' --random test.example.com\n" "\n" " Modify information about a host:\n" " ipa host-mod --os='Fedora 12' test.example.com\n" "\n" " Remove SSH public keys of a host and update DNS to reflect this change:\n" " ipa host-mod --sshpubkey= --updatedns test.example.com\n" "\n" " Disable the host Kerberos key, SSL certificate and all of its services:\n" " ipa host-disable test.example.com\n" "\n" " Add a host that can manage this host's keytab and certificate:\n" " ipa host-add-managedby --hosts=test2 test\n" msgstr "" #: ipalib/plugins/host.py:158 ipalib/plugins/service.py:96 msgid "Keytab" msgstr "" #: ipalib/plugins/host.py:170 ipalib/plugins/internal.py:363 #: ipalib/plugins/service.py:105 msgid "Serial Number" msgstr "" #: ipalib/plugins/host.py:173 ipalib/plugins/internal.py:364 #: ipalib/plugins/service.py:108 msgid "Serial Number (hex)" msgstr "" #: ipalib/plugins/host.py:194 msgid "Failed managedby" msgstr "" #: ipalib/plugins/host.py:197 ipalib/plugins/user.py:92 msgid "SSH public key fingerprint" msgstr "" #: ipalib/plugins/host.py:223 msgid "host" msgstr "" #: ipalib/plugins/host.py:224 msgid "hosts" msgstr "" #: ipalib/plugins/host.py:257 ipalib/plugins/internal.py:488 #: ipalib/plugins/internal.py:539 msgid "Host" msgstr "" #: ipalib/plugins/host.py:262 msgid "Host name" msgstr "" #: ipalib/plugins/host.py:269 msgid "A description of this host" msgstr "" #: ipalib/plugins/host.py:273 msgid "Locality" msgstr "" #: ipalib/plugins/host.py:274 msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "" #: ipalib/plugins/host.py:279 msgid "Host location (e.g. \"Lab 2\")" msgstr "" #: ipalib/plugins/host.py:283 msgid "Platform" msgstr "" #: ipalib/plugins/host.py:284 msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "" #: ipalib/plugins/host.py:288 msgid "Operating system" msgstr "" #: ipalib/plugins/host.py:289 msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "" #: ipalib/plugins/host.py:293 msgid "User password" msgstr "" #: ipalib/plugins/host.py:294 msgid "Password used in bulk enrollment" msgstr "" #: ipalib/plugins/host.py:297 msgid "Generate a random password to be used in bulk enrollment" msgstr "" #: ipalib/plugins/host.py:302 ipalib/plugins/user.py:301 msgid "Random password" msgstr "" #: ipalib/plugins/host.py:308 ipalib/plugins/service.py:329 msgid "Base-64 encoded server certificate" msgstr "" #: ipalib/plugins/host.py:311 ipalib/plugins/host.py:629 msgid "Principal name" msgstr "" #: ipalib/plugins/host.py:319 msgid "MAC address" msgstr "" #: ipalib/plugins/host.py:320 msgid "Hardware MAC address(es) on this host" msgstr "" #: ipalib/plugins/host.py:324 ipalib/plugins/user.py:363 msgid "SSH public key" msgstr "" #: ipalib/plugins/host.py:332 msgid "" "Host category (semantics placed on this attribute are for local " "interpretation)" msgstr "" #: ipalib/plugins/host.py:392 msgid "Add a new host." msgstr "" #: ipalib/plugins/host.py:395 #, python-format msgid "Added host \"%(value)s\"" msgstr "" #: ipalib/plugins/host.py:400 msgid "force host name even if not in DNS" msgstr "" #: ipalib/plugins/host.py:403 msgid "skip reverse DNS detection" msgstr "" #: ipalib/plugins/host.py:406 msgid "Add the host to DNS with this IP address" msgstr "" #: ipalib/plugins/host.py:487 #, python-format msgid "The host was added but the DNS update failed with: %(exc)s" msgstr "" #: ipalib/plugins/host.py:508 msgid "Delete a host." msgstr "" #: ipalib/plugins/host.py:510 #, python-format msgid "Deleted host \"%(value)s\"" msgstr "" #: ipalib/plugins/host.py:515 msgid "Remove entries from DNS" msgstr "" #: ipalib/plugins/host.py:620 msgid "Modify information about a host." msgstr "" #: ipalib/plugins/host.py:623 #, python-format msgid "Modified host \"%(value)s\"" msgstr "" #: ipalib/plugins/host.py:630 msgid "Kerberos principal name for this host" msgstr "" #: ipalib/plugins/host.py:634 msgid "Update DNS entries" msgstr "" #: ipalib/plugins/host.py:647 msgid "Password cannot be set on enrolled host." msgstr "" #: ipalib/plugins/host.py:651 msgid "cn is immutable" msgstr "" #: ipalib/plugins/host.py:770 msgid "Search for hosts." msgstr "" #: ipalib/plugins/host.py:774 #, python-format msgid "%(count)d host matched" msgid_plural "%(count)d hosts matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/host.py:856 msgid "Display information about a host." msgstr "" #: ipalib/plugins/host.py:861 ipalib/plugins/service.py:560 msgid "file to store certificate in" msgstr "" #: ipalib/plugins/host.py:893 ipalib/plugins/service.py:580 #, python-format msgid "Certificate stored in file '%(file)s'" msgstr "" #: ipalib/plugins/host.py:904 msgid "Disable the Kerberos key, SSL certificate and all services of a host." msgstr "" #: ipalib/plugins/host.py:907 #, python-format msgid "Disabled host \"%(value)s\"" msgstr "" #: ipalib/plugins/host.py:1000 msgid "Add hosts that can manage this host." msgstr "" #: ipalib/plugins/host.py:1015 msgid "Remove hosts that can manage this host." msgstr "" #: ipalib/plugins/hostgroup.py:26 msgid "" "\n" "Groups of hosts.\n" "\n" "Manage groups of hosts. This is useful for applying access control to a\n" "number of hosts by using Host-based Access Control.\n" "\n" "EXAMPLES:\n" "\n" " Add a new host group:\n" " ipa hostgroup-add --desc=\"Baltimore hosts\" baltimore\n" "\n" " Add another new host group:\n" " ipa hostgroup-add --desc=\"Maryland hosts\" maryland\n" "\n" " Add members to the hostgroup (using Bash brace expansion):\n" " ipa hostgroup-add-member --hosts={box1,box2,box3} baltimore\n" "\n" " Add a hostgroup as a member of another hostgroup:\n" " ipa hostgroup-add-member --hostgroups=baltimore maryland\n" "\n" " Remove a host from the hostgroup:\n" " ipa hostgroup-remove-member --hosts=box2 baltimore\n" "\n" " Display a host group:\n" " ipa hostgroup-show baltimore\n" "\n" " Delete a hostgroup:\n" " ipa hostgroup-del baltimore\n" msgstr "" #: ipalib/plugins/hostgroup.py:61 msgid "host group" msgstr "" #: ipalib/plugins/hostgroup.py:62 msgid "host groups" msgstr "" #: ipalib/plugins/hostgroup.py:76 msgid "Host Group" msgstr "" #: ipalib/plugins/hostgroup.py:83 msgid "Host-group" msgstr "" #: ipalib/plugins/hostgroup.py:84 msgid "Name of host-group" msgstr "" #: ipalib/plugins/hostgroup.py:91 msgid "A description of this host-group" msgstr "" #: ipalib/plugins/hostgroup.py:118 msgid "Add a new hostgroup." msgstr "" #: ipalib/plugins/hostgroup.py:120 #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/hostgroup.py:136 #, python-format msgid "" "netgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" #: ipalib/plugins/hostgroup.py:159 msgid "Delete a hostgroup." msgstr "" #: ipalib/plugins/hostgroup.py:161 #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/hostgroup.py:167 msgid "Modify a hostgroup." msgstr "" #: ipalib/plugins/hostgroup.py:169 #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/hostgroup.py:180 msgid "Search for hostgroups." msgstr "" #: ipalib/plugins/hostgroup.py:184 #, python-format msgid "%(count)d hostgroup matched" msgid_plural "%(count)d hostgroups matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/hostgroup.py:199 msgid "Display information about a hostgroup." msgstr "" #: ipalib/plugins/hostgroup.py:210 msgid "Add members to a hostgroup." msgstr "" #: ipalib/plugins/hostgroup.py:221 msgid "Remove members from a hostgroup." msgstr "" #: ipalib/plugins/idrange.py:33 msgid "" "\n" "ID ranges\n" "\n" "Manage ID ranges used to map Posix IDs to SIDs and back.\n" "\n" "There are two type of ID ranges which are both handled by this utility:\n" "\n" " - the ID ranges of the local domain\n" " - the ID ranges of trusted remote domains\n" "\n" "Both types have the following attributes in common:\n" "\n" " - base-id: the first ID of the Posix ID range\n" " - range-size: the size of the range\n" "\n" "With those two attributes a range object can reserve the Posix IDs starting\n" "with base-id up to but not including base-id+range-size exclusively.\n" "\n" "Additionally an ID range of the local domain may set\n" " - rid-base: the first RID(*) of the corresponding RID range\n" " - secondary-rid-base: first RID of the secondary RID range\n" "\n" "and an ID range of a trusted domain must set\n" " - rid-base: the first RID of the corresponding RID range\n" " - sid: domain SID of the trusted domain\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for a trusted domain\n" "\n" "Since there might be more than one trusted domain the domain SID must be " "given\n" "while creating the ID range.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=0 \\\n" " --dom-sid=S-1-5-21-123-456-789 trusted_dom_range\n" "\n" "This ID range is then used by the IPA server and the SSSD IPA provider to\n" "assign Posix UIDs to users from the trusted domain.\n" "\n" "If e.g a range for a trusted domain is configured with the following " "values:\n" " base-id = 1200000\n" " range-size = 200000\n" " rid-base = 0\n" "the RIDs 0 to 199999 are mapped to the Posix ID from 1200000 to 13999999. " "So\n" "RID 1000 <-> Posix ID 1201000\n" "\n" "\n" "\n" "EXAMPLE: Add a new ID range for the local domain\n" "\n" "To create an ID range for the local domain it is not necessary to specify a\n" "domain SID. But since it is possible that a user and a group can have the " "same\n" "value as Posix ID a second RID interval is needed to handle conflicts.\n" "\n" " ipa idrange-add --base-id=1200000 --range-size=200000 --rid-base=1000 \\\n" " --secondary-rid-base=1000000 local_range\n" "\n" "The data from the ID ranges of the local domain are used by the IPA server\n" "internally to assign SIDs to IPA users and groups. The SID will then be " "stored\n" "in the user or group objects.\n" "\n" "If e.g. the ID range for the local domain is configured with the values " "from\n" "the example above then a new user with the UID 1200007 will get the RID " "1007.\n" "If this RID is already used by a group the RID will be 1000007. This can " "only\n" "happen if a user or a group object was created with a fixed ID because the\n" "automatic assignment will not assign the same ID twice. Since there are " "only\n" "users and groups sharing the same ID namespace it is sufficient to have " "only\n" "one fallback range to handle conflicts.\n" "\n" "To find the Posix ID for a given RID from the local domain it has to be\n" "checked first if the RID falls in the primary or secondary RID range and\n" "the rid-base or the secondary-rid-base has to be subtracted, respectively,\n" "and the base-id has to be added to get the Posix ID.\n" "\n" "Typically the creation of ID ranges happens behind the scenes and this CLI\n" "must not be used at all. The ID range for the local domain will be created\n" "during installation or upgrade from an older version. The ID range for a\n" "trusted domain will be created together with the trust by 'ipa trust-" "add ...'.\n" "\n" "USE CASES:\n" "\n" " Add an ID range from a transitively trusted domain\n" "\n" " If the trusted domain (A) trusts another domain (B) as well and this " "trust\n" " is transitive 'ipa trust-add domain-A' will only create a range for\n" " domain A. The ID range for domain B must be added manually.\n" "\n" " Add an additional ID range for the local domain\n" "\n" " If the ID range of the local domain is exhausted, i.e. no new IDs can " "be\n" " assigned to Posix users or groups by the DNA plugin, a new range has to " "be\n" " created to allow new users and groups to be added. (Currently there is " "no\n" " connection between this range CLI and the DNA plugin, but a future " "version\n" " might be able to modify the configuration of the DNS plugin as well)\n" "\n" "In general it is not necessary to modify or delete ID ranges. If there is " "no\n" "other way to achieve a certain configuration than to modify or delete an ID\n" "range it should be done with great care. Because UIDs are stored in the " "file\n" "system and are used for access control it might be possible that users are\n" "allowed to access files of other users if an ID range got deleted and " "reused\n" "for a different domain.\n" "\n" "(*) The RID is typically the last integer of a user or group SID which " "follows\n" "the domain SID. E.g. if the domain SID is S-1-5-21-123-456-789 and a user " "from\n" "this domain has the SID S-1-5-21-123-456-789-1010 then 1010 id the RID of " "the\n" "user. RIDs are unique in a domain, 32bit values and are used for users and\n" "groups.\n" "\n" "WARNING:\n" "\n" "DNA plugin in 389-ds will allocate IDs based on the ranges configured for " "the\n" "local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" "on the local ranges set via this family of commands.\n" "\n" "Manual configuration change has to be done in the DNA plugin configuration " "for\n" "the new local range. Specifically, The dnaNextRange attribute of 'cn=Posix\n" "IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has to " "be\n" "modified to match the new range.\n" msgstr "" #: ipalib/plugins/idrange.py:169 msgid "ID Ranges" msgstr "" #: ipalib/plugins/idrange.py:170 msgid "ID Range" msgstr "" #: ipalib/plugins/idrange.py:173 msgid "local domain range" msgstr "" #: ipalib/plugins/idrange.py:174 msgid "Active Directory winsync range" msgstr "" #: ipalib/plugins/idrange.py:175 ipalib/plugins/trust.py:267 msgid "Active Directory domain range" msgstr "" #: ipalib/plugins/idrange.py:176 ipalib/plugins/trust.py:268 msgid "Active Directory trust range with POSIX attributes" msgstr "" #: ipalib/plugins/idrange.py:178 msgid "IPA trust range" msgstr "" #: ipalib/plugins/idrange.py:184 msgid "Range name" msgstr "" #: ipalib/plugins/idrange.py:189 msgid "First Posix ID of the range" msgstr "" #: ipalib/plugins/idrange.py:193 msgid "Number of IDs in the range" msgstr "" #: ipalib/plugins/idrange.py:197 msgid "First RID of the corresponding RID range" msgstr "" #: ipalib/plugins/idrange.py:201 msgid "First RID of the secondary RID range" msgstr "" #: ipalib/plugins/idrange.py:206 msgid "Domain SID of the trusted domain" msgstr "" #: ipalib/plugins/idrange.py:211 msgid "Name of the trusted domain" msgstr "" #: ipalib/plugins/idrange.py:214 ipalib/plugins/internal.py:517 #: ipalib/plugins/trust.py:301 msgid "Range type" msgstr "" #: ipalib/plugins/idrange.py:216 msgid "ID range type, one of {vals}" msgstr "" #: ipalib/plugins/idrange.py:284 msgid "" "range modification leaving objects with ID out of the defined range is not " "allowed" msgstr "" #: ipalib/plugins/idrange.py:289 msgid "" "Cannot perform SID validation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA on the server" msgstr "" #: ipalib/plugins/idrange.py:296 msgid "" "Cross-realm trusts are not configured. Make sure you have run ipa-adtrust-" "install on the IPA server first" msgstr "" #: ipalib/plugins/idrange.py:308 msgid "SID is not recognized as a valid SID for a trusted domain" msgstr "" #: ipalib/plugins/idrange.py:344 msgid "" "\n" " Add new ID range.\n" "\n" " To add a new ID range you always have to specify\n" "\n" " --base-id\n" " --range-size\n" "\n" " Additionally\n" "\n" " --rid-base\n" " --secondary-rid-base\n" "\n" " may be given for a new ID range for the local domain while\n" "\n" " --rid-base\n" " --dom-sid\n" "\n" " must be given to add a new range for a trusted AD domain.\n" "\n" " WARNING:\n" "\n" " DNA plugin in 389-ds will allocate IDs based on the ranges configured " "for the\n" " local domain. Currently the DNA plugin *cannot* be reconfigured itself " "based\n" " on the local ranges set via this family of commands.\n" "\n" " Manual configuration change has to be done in the DNA plugin " "configuration for\n" " the new local range. Specifically, The dnaNextRange attribute of " "'cn=Posix\n" " IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config' has " "to be\n" " modified to match the new range.\n" " " msgstr "" #: ipalib/plugins/idrange.py:376 #, python-format msgid "Added ID range \"%(value)s\"" msgstr "" #: ipalib/plugins/idrange.py:449 ipalib/plugins/idrange.py:647 msgid "Options dom-sid and dom-name cannot be used together" msgstr "" #: ipalib/plugins/idrange.py:459 ipalib/plugins/idrange.py:659 msgid "" "SID for the specified trusted domain name could not be found. Please specify " "the SID directly using dom-sid option." msgstr "" #: ipalib/plugins/idrange.py:474 msgid "" "IPA Range type must be one of ipa-ad-trust or ipa-ad-trust-posix when SID of " "the trusted domain is specified." msgstr "" #: ipalib/plugins/idrange.py:480 msgid "Options dom-sid/dom-name and secondary-rid-base cannot be used together" msgstr "" #: ipalib/plugins/idrange.py:485 msgid "Options dom-sid/dom-name and rid-base must be used together" msgstr "" #: ipalib/plugins/idrange.py:504 msgid "" "IPA Range type must not be one of ipa-ad-trust or ipa-ad-trust-posix when " "SID of the trusted domain is not specified." msgstr "" #: ipalib/plugins/idrange.py:511 ipalib/plugins/idrange.py:689 msgid "Options secondary-rid-base and rid-base must be used together" msgstr "" #: ipalib/plugins/idrange.py:521 ipalib/plugins/idrange.py:712 msgid "Primary RID range and secondary RID range cannot overlap" msgstr "" #: ipalib/plugins/idrange.py:533 msgid "" "You must specify both rid-base and secondary-rid-base options, because ipa-" "adtrust-install has already been run." msgstr "" #: ipalib/plugins/idrange.py:548 msgid "Delete an ID range." msgstr "" #: ipalib/plugins/idrange.py:550 #, python-format msgid "Deleted ID range \"%(value)s\"" msgstr "" #: ipalib/plugins/idrange.py:583 msgid "Search for ranges." msgstr "" #: ipalib/plugins/idrange.py:586 #, python-format msgid "%(count)d range matched" msgid_plural "%(count)d ranges matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/idrange.py:604 msgid "Display information about a range." msgstr "" #: ipalib/plugins/idrange.py:618 msgid "Modify ID range." msgstr "" #: ipalib/plugins/idrange.py:620 #, python-format msgid "Modified ID range \"%(value)s\"" msgstr "" #: ipalib/plugins/idrange.py:666 msgid "Options dom-sid and secondary-rid-base cannot be used together" msgstr "" #: ipalib/plugins/idrange.py:671 msgid "Options dom-sid and rid-base must be used together" msgstr "" #: ipalib/plugins/internal.py:44 ipalib/plugins/internal.py:53 msgid "Name of object to export" msgstr "" #: ipalib/plugins/internal.py:47 ipalib/plugins/internal.py:56 msgid "Name of method to export" msgstr "" #: ipalib/plugins/internal.py:59 msgid "Name of command to export" msgstr "" #: ipalib/plugins/internal.py:64 msgid "Dict of JSON encoded IPA Objects" msgstr "" #: ipalib/plugins/internal.py:65 msgid "Dict of JSON encoded IPA Methods" msgstr "" #: ipalib/plugins/internal.py:66 msgid "Dict of JSON encoded IPA Commands" msgstr "" #: ipalib/plugins/internal.py:147 msgid "Your session has expired. Please re-login." msgstr "" #: ipalib/plugins/internal.py:151 msgid "Apply" msgstr "" #: ipalib/plugins/internal.py:152 msgid "Are you sure you want to proceed with the action." msgstr "" #: ipalib/plugins/internal.py:153 msgid "Are you sure you want to delete ${object}" msgstr "" #: ipalib/plugins/internal.py:154 msgid "Are you sure you want to disable ${object}" msgstr "" #: ipalib/plugins/internal.py:155 msgid "Are you sure you want to enable ${object}" msgstr "" #: ipalib/plugins/internal.py:156 msgid "Actions" msgstr "" #: ipalib/plugins/internal.py:160 msgid "Add RunAs ${other_entity} into ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:161 msgid "Add RunAs Groups into ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:162 msgid "Add ${other_entity} Managing ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:163 msgid "Add ${other_entity} into ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:164 msgid "Add Allow ${other_entity} into ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:165 msgid "Add Deny ${other_entity} into ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:166 msgid "Add ${entity} ${primary_key} into ${other_entity}" msgstr "" #: ipalib/plugins/internal.py:168 msgid "${count} item(s) added" msgstr "" #: ipalib/plugins/internal.py:169 msgid "Direct Membership" msgstr "" #: ipalib/plugins/internal.py:170 msgid "Indirect Membership" msgstr "" #: ipalib/plugins/internal.py:171 msgid "No entries." msgstr "" #: ipalib/plugins/internal.py:172 msgid "Showing ${start} to ${end} of ${total} entries." msgstr "" #: ipalib/plugins/internal.py:174 msgid "Remove RunAs ${other_entity} from ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:175 msgid "Remove RunAs Groups from ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:176 msgid "Remove ${other_entity} Managing ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:177 msgid "Remove ${other_entity} from ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:178 msgid "Remove Allow ${other_entity} from ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:179 msgid "Remove Deny ${other_entity} from ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:180 msgid "Remove ${entity} ${primary_key} from ${other_entity}" msgstr "" #: ipalib/plugins/internal.py:182 msgid "${count} item(s) removed" msgstr "" #: ipalib/plugins/internal.py:183 msgid "Show Results" msgstr "" #: ipalib/plugins/internal.py:186 msgid "Add" msgstr "" #: ipalib/plugins/internal.py:187 msgid "Add and Add Another" msgstr "" #: ipalib/plugins/internal.py:188 msgid "Add and Close" msgstr "" #: ipalib/plugins/internal.py:189 msgid "Add and Edit" msgstr "" #: ipalib/plugins/internal.py:190 msgid "Add Many" msgstr "" #: ipalib/plugins/internal.py:191 msgid "Back" msgstr "" #: ipalib/plugins/internal.py:192 msgid "Cancel" msgstr "" #: ipalib/plugins/internal.py:193 msgid "Close" msgstr "" #: ipalib/plugins/internal.py:194 ipalib/plugins/internal.py:655 msgid "Disable" msgstr "" #: ipalib/plugins/internal.py:195 msgid "Edit" msgstr "" #: ipalib/plugins/internal.py:196 ipalib/plugins/internal.py:657 msgid "Enable" msgstr "" #: ipalib/plugins/internal.py:197 msgid "Find" msgstr "" #: ipalib/plugins/internal.py:198 msgid "Get" msgstr "" #: ipalib/plugins/internal.py:199 msgid "Issue" msgstr "" #: ipalib/plugins/internal.py:200 msgid "OK" msgstr "" #: ipalib/plugins/internal.py:201 msgid "Refresh" msgstr "" #: ipalib/plugins/internal.py:202 msgid "Delete" msgstr "" #: ipalib/plugins/internal.py:203 msgid "Reset" msgstr "" #: ipalib/plugins/internal.py:204 msgid "Reset Password and Login" msgstr "" #: ipalib/plugins/internal.py:205 msgid "Restore" msgstr "" #: ipalib/plugins/internal.py:206 msgid "Retry" msgstr "" #: ipalib/plugins/internal.py:207 msgid "Revoke" msgstr "" #: ipalib/plugins/internal.py:208 msgid "Set" msgstr "" #: ipalib/plugins/internal.py:209 msgid "Update" msgstr "" #: ipalib/plugins/internal.py:210 msgid "View" msgstr "" #: ipalib/plugins/internal.py:213 msgid "Collapse All" msgstr "" #: ipalib/plugins/internal.py:214 msgid "Expand All" msgstr "" #: ipalib/plugins/internal.py:215 msgid "General" msgstr "" #: ipalib/plugins/internal.py:216 msgid "Identity Settings" msgstr "" #: ipalib/plugins/internal.py:217 msgid "${entity} ${primary_key} Settings" msgstr "" #: ipalib/plugins/internal.py:218 msgid "Back to Top" msgstr "" #: ipalib/plugins/internal.py:219 msgid "${entity} ${primary_key} updated" msgstr "" #: ipalib/plugins/internal.py:222 msgid "${entity} successfully added" msgstr "" #: ipalib/plugins/internal.py:223 msgid "Add ${entity}" msgstr "" #: ipalib/plugins/internal.py:224 msgid "Available" msgstr "" #: ipalib/plugins/internal.py:225 msgid "Some operations failed." msgstr "" #: ipalib/plugins/internal.py:226 msgid "Operations Error" msgstr "" #: ipalib/plugins/internal.py:227 msgid "Confirmation" msgstr "" #: ipalib/plugins/internal.py:228 msgid "This page has unsaved changes. Please save or revert." msgstr "" #: ipalib/plugins/internal.py:229 msgid "Unsaved Changes" msgstr "" #: ipalib/plugins/internal.py:230 msgid "Edit ${entity}" msgstr "" #: ipalib/plugins/internal.py:231 msgid "Hide details" msgstr "" #: ipalib/plugins/internal.py:232 msgid "Prospective" msgstr "" #: ipalib/plugins/internal.py:233 msgid "Redirection" msgstr "" #: ipalib/plugins/internal.py:234 msgid "Select entries to be removed." msgstr "" #: ipalib/plugins/internal.py:235 msgid "Remove ${entity}" msgstr "" #: ipalib/plugins/internal.py:236 msgid "Show details" msgstr "" #: ipalib/plugins/internal.py:237 msgid "Validation error" msgstr "" #: ipalib/plugins/internal.py:238 msgid "Input form contains invalid or missing values." msgstr "" #: ipalib/plugins/internal.py:241 msgid "Please try the following options:" msgstr "" #: ipalib/plugins/internal.py:242 msgid "If the problem persists please contact the system administrator." msgstr "" #: ipalib/plugins/internal.py:243 msgid "Refresh the page." msgstr "" #: ipalib/plugins/internal.py:244 msgid "Reload the browser." msgstr "" #: ipalib/plugins/internal.py:245 msgid "Return to the main page and retry the operation" msgstr "" #: ipalib/plugins/internal.py:246 msgid "An error has occurred (${error})" msgstr "" #: ipalib/plugins/internal.py:250 msgid "HTTP Error" msgstr "" #: ipalib/plugins/internal.py:251 msgid "Internal Error" msgstr "" #: ipalib/plugins/internal.py:252 msgid "IPA Error" msgstr "" #: ipalib/plugins/internal.py:253 msgid "No response" msgstr "" #: ipalib/plugins/internal.py:254 msgid "Unknown Error" msgstr "" #: ipalib/plugins/internal.py:255 msgid "URL" msgstr "" #: ipalib/plugins/internal.py:258 msgid "${primary_key} is managed by:" msgstr "" #: ipalib/plugins/internal.py:259 msgid "${primary_key} members:" msgstr "" #: ipalib/plugins/internal.py:260 msgid "${primary_key} is a member of:" msgstr "" #: ipalib/plugins/internal.py:263 msgid "Settings" msgstr "" #: ipalib/plugins/internal.py:264 msgid "Search" msgstr "" #: ipalib/plugins/internal.py:266 msgid "False" msgstr "" #: ipalib/plugins/internal.py:268 msgid "Inherited from server configuration" msgstr "" #: ipalib/plugins/internal.py:269 msgid "MS-PAC" msgstr "" #: ipalib/plugins/internal.py:270 msgid "Override inherited settings" msgstr "" #: ipalib/plugins/internal.py:271 msgid "PAD" msgstr "" #: ipalib/plugins/internal.py:274 msgid "" "To login with username and password, enter them in the fields below then " "click Login." msgstr "" #: ipalib/plugins/internal.py:275 msgid "Logged In As" msgstr "" #: ipalib/plugins/internal.py:276 msgid "" "To login with Kerberos, please make sure you have valid tickets (obtainable " "via kinit) and configured the browser correctly, then click Login." msgstr "" #: ipalib/plugins/internal.py:277 msgid "Login" msgstr "" #: ipalib/plugins/internal.py:278 msgid "Logout" msgstr "" #: ipalib/plugins/internal.py:279 msgid "Logout error" msgstr "" #: ipalib/plugins/internal.py:281 msgid "Username" msgstr "" #: ipalib/plugins/internal.py:284 msgid "number of passwords" msgstr "" #: ipalib/plugins/internal.py:285 msgid "seconds" msgstr "" #: ipalib/plugins/internal.py:289 ipalib/plugins/internal.py:294 msgid "Attribute" msgstr "" #: ipalib/plugins/internal.py:292 msgid "Add Condition into ${pkey}" msgstr "" #: ipalib/plugins/internal.py:293 msgid "Add Rule" msgstr "" #: ipalib/plugins/internal.py:295 msgid "Default host group" msgstr "" #: ipalib/plugins/internal.py:296 msgid "Default user group" msgstr "" #: ipalib/plugins/internal.py:297 msgid "Exclusive" msgstr "" #: ipalib/plugins/internal.py:298 msgid "Expression" msgstr "" #: ipalib/plugins/internal.py:299 msgid "Host group rule" msgstr "" #: ipalib/plugins/internal.py:300 msgid "Host group rules" msgstr "" #: ipalib/plugins/internal.py:301 msgid "Inclusive" msgstr "" #: ipalib/plugins/internal.py:302 msgid "User group rule" msgstr "" #: ipalib/plugins/internal.py:303 msgid "User group rules" msgstr "" #: ipalib/plugins/internal.py:308 msgid "Automount Location Settings" msgstr "" #: ipalib/plugins/internal.py:311 msgid "Map Type" msgstr "" #: ipalib/plugins/internal.py:312 msgid "Direct" msgstr "" #: ipalib/plugins/internal.py:313 msgid "Indirect" msgstr "" #: ipalib/plugins/internal.py:316 msgid "AA Compromise" msgstr "" #: ipalib/plugins/internal.py:317 msgid "Affiliation Changed" msgstr "" #: ipalib/plugins/internal.py:318 msgid "CA Compromise" msgstr "" #: ipalib/plugins/internal.py:320 ipalib/plugins/internal.py:665 msgid "Certificates" msgstr "" #: ipalib/plugins/internal.py:321 msgid "Certificate Hold" msgstr "" #: ipalib/plugins/internal.py:322 msgid "Cessation of Operation" msgstr "" #: ipalib/plugins/internal.py:323 msgid "Common Name" msgstr "" #: ipalib/plugins/internal.py:324 msgid "Expires On" msgstr "" #: ipalib/plugins/internal.py:325 msgid "Issued on from" msgstr "" #: ipalib/plugins/internal.py:326 msgid "Issued on to" msgstr "" #: ipalib/plugins/internal.py:327 msgid "Maximum serial number" msgstr "" #: ipalib/plugins/internal.py:328 msgid "Minimum serial number" msgstr "" #: ipalib/plugins/internal.py:330 msgid "Revoked on from" msgstr "" #: ipalib/plugins/internal.py:331 msgid "Revoked on to" msgstr "" #: ipalib/plugins/internal.py:333 msgid "Valid not after from" msgstr "" #: ipalib/plugins/internal.py:334 msgid "Valid not after to" msgstr "" #: ipalib/plugins/internal.py:335 msgid "Valid not before from" msgstr "" #: ipalib/plugins/internal.py:336 msgid "Valid not before to" msgstr "" #: ipalib/plugins/internal.py:337 msgid "Fingerprints" msgstr "" #: ipalib/plugins/internal.py:338 msgid "Issue New Certificate for ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:339 msgid "Issued By" msgstr "" #: ipalib/plugins/internal.py:340 msgid "Issued On" msgstr "" #: ipalib/plugins/internal.py:341 msgid "Issued To" msgstr "" #: ipalib/plugins/internal.py:342 msgid "Key Compromise" msgstr "" #: ipalib/plugins/internal.py:343 msgid "MD5 Fingerprint" msgstr "" #: ipalib/plugins/internal.py:344 msgid "No Valid Certificate" msgstr "" #: ipalib/plugins/internal.py:345 msgid "New Certificate" msgstr "" #: ipalib/plugins/internal.py:346 msgid "Note" msgstr "" #: ipalib/plugins/internal.py:347 msgid "Organization" msgstr "" #: ipalib/plugins/internal.py:348 msgid "Organizational Unit" msgstr "" #: ipalib/plugins/internal.py:349 msgid "Privilege Withdrawn" msgstr "" #: ipalib/plugins/internal.py:350 msgid "Reason for Revocation" msgstr "" #: ipalib/plugins/internal.py:351 msgid "Remove from CRL" msgstr "" #: ipalib/plugins/internal.py:352 msgid "" "
  1. Create a certificate database or use an existing one. To create a " "new database:
    # certutil -N -d <database path>
  2. " "
  3. Create a CSR with subject CN=<hostname>,O=<realm>, " "for example:
    # certutil -R -d <database path> -a -g <key " "size> -s 'CN=${hostname},O=${realm}'
  4. Copy and paste the " "CSR (from -----BEGIN NEW CERTIFICATE REQUEST----- to -----END " "NEW CERTIFICATE REQUEST-----) into the text area below:
" msgstr "" #: ipalib/plugins/internal.py:353 msgid "Certificate requested" msgstr "" #: ipalib/plugins/internal.py:354 msgid "Restore Certificate for ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:355 msgid "Restore Certificate" msgstr "" #: ipalib/plugins/internal.py:356 msgid "" "To confirm your intention to restore this certificate, click the \"Restore\" " "button." msgstr "" #: ipalib/plugins/internal.py:357 msgid "Certificate restored" msgstr "" #: ipalib/plugins/internal.py:359 msgid "Revoke Certificate for ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:360 msgid "Revoke Certificate" msgstr "" #: ipalib/plugins/internal.py:361 msgid "" "To confirm your intention to revoke this certificate, select a reason from " "the pull-down list, and click the \"Revoke\" button." msgstr "" #: ipalib/plugins/internal.py:362 msgid "Certificate Revoked" msgstr "" #: ipalib/plugins/internal.py:365 msgid "SHA1 Fingerprint" msgstr "" #: ipalib/plugins/internal.py:367 msgid "Superseded" msgstr "" #: ipalib/plugins/internal.py:368 msgid "Unspecified" msgstr "" #: ipalib/plugins/internal.py:369 msgid "Valid Certificate Present" msgstr "" #: ipalib/plugins/internal.py:370 msgid "Validity" msgstr "" #: ipalib/plugins/internal.py:371 msgid "Certificate for ${entity} ${primary_key}" msgstr "" #: ipalib/plugins/internal.py:374 msgid "Group Options" msgstr "" #: ipalib/plugins/internal.py:375 msgid "Search Options" msgstr "" #: ipalib/plugins/internal.py:376 msgid "SELinux Options" msgstr "" #: ipalib/plugins/internal.py:377 msgid "Service Options" msgstr "" #: ipalib/plugins/internal.py:378 msgid "User Options" msgstr "" #: ipalib/plugins/internal.py:383 msgid "Forward first" msgstr "" #: ipalib/plugins/internal.py:384 msgid "Forwarding disabled" msgstr "" #: ipalib/plugins/internal.py:385 msgid "Forward only" msgstr "" #: ipalib/plugins/internal.py:386 ipalib/plugins/internal.py:588 #: ipalib/plugins/internal.py:611 msgid "Options" msgstr "" #: ipalib/plugins/internal.py:389 msgid "Data" msgstr "" #: ipalib/plugins/internal.py:390 msgid "DNS record was deleted because it contained no data." msgstr "" #: ipalib/plugins/internal.py:391 msgid "Other Record Types" msgstr "" #: ipalib/plugins/internal.py:392 msgid "Address not valid, can't redirect" msgstr "" #: ipalib/plugins/internal.py:393 msgid "Create dns record" msgstr "" #: ipalib/plugins/internal.py:394 msgid "Creating record." msgstr "" #: ipalib/plugins/internal.py:395 msgid "Record creation failed." msgstr "" #: ipalib/plugins/internal.py:396 msgid "Checking if record exists." msgstr "" #: ipalib/plugins/internal.py:397 msgid "Record not found." msgstr "" #: ipalib/plugins/internal.py:398 msgid "Redirection to PTR record" msgstr "" #: ipalib/plugins/internal.py:399 msgid "Zone found: ${zone}" msgstr "" #: ipalib/plugins/internal.py:400 msgid "Target reverse zone not found." msgstr "" #: ipalib/plugins/internal.py:401 msgid "Fetching DNS zones." msgstr "" #: ipalib/plugins/internal.py:402 msgid "An error occurred while fetching dns zones." msgstr "" #: ipalib/plugins/internal.py:403 msgid "You will be redirected to DNS Zone." msgstr "" #: ipalib/plugins/internal.py:404 msgid "Standard Record Types" msgstr "" #: ipalib/plugins/internal.py:405 msgid "Records for DNS Zone" msgstr "" #: ipalib/plugins/internal.py:406 msgid "Record Type" msgstr "" #: ipalib/plugins/internal.py:409 msgid "DNS Zone Settings" msgstr "" #: ipalib/plugins/internal.py:410 msgid "Add Permission" msgstr "" #: ipalib/plugins/internal.py:411 msgid "Remove Permission" msgstr "" #: ipalib/plugins/internal.py:414 msgid "Group Settings" msgstr "" #: ipalib/plugins/internal.py:415 ipalib/plugins/internal.py:487 #: ipalib/plugins/internal.py:583 msgid "External" msgstr "" #: ipalib/plugins/internal.py:416 msgid "Change to external group" msgstr "" #: ipalib/plugins/internal.py:417 msgid "Change to POSIX group" msgstr "" #: ipalib/plugins/internal.py:418 msgid "Normal" msgstr "" #: ipalib/plugins/internal.py:419 msgid "POSIX" msgstr "" #: ipalib/plugins/internal.py:420 msgid "Group Type" msgstr "" #: ipalib/plugins/internal.py:423 ipalib/plugins/internal.py:485 #: ipalib/plugins/internal.py:537 ipalib/plugins/internal.py:579 msgid "Any Host" msgstr "" #: ipalib/plugins/internal.py:424 msgid "Any Service" msgstr "" #: ipalib/plugins/internal.py:425 ipalib/plugins/internal.py:486 #: ipalib/plugins/internal.py:538 ipalib/plugins/internal.py:580 msgid "Anyone" msgstr "" #: ipalib/plugins/internal.py:426 msgid "Accessing" msgstr "" #: ipalib/plugins/internal.py:427 ipalib/plugins/internal.py:585 msgid "Rule status" msgstr "" #: ipalib/plugins/internal.py:428 msgid "Via Service" msgstr "" #: ipalib/plugins/internal.py:429 ipalib/plugins/internal.py:492 #: ipalib/plugins/internal.py:540 ipalib/plugins/internal.py:592 msgid "Specified Hosts and Groups" msgstr "" #: ipalib/plugins/internal.py:430 msgid "Specified Services and Groups" msgstr "" #: ipalib/plugins/internal.py:431 ipalib/plugins/internal.py:493 #: ipalib/plugins/internal.py:541 ipalib/plugins/internal.py:593 msgid "Specified Users and Groups" msgstr "" #: ipalib/plugins/internal.py:432 ipalib/plugins/internal.py:594 msgid "Who" msgstr "" #: ipalib/plugins/internal.py:440 msgid "Access Denied" msgstr "" #: ipalib/plugins/internal.py:441 msgid "Access Granted" msgstr "" #: ipalib/plugins/internal.py:442 msgid "Include Disabled" msgstr "" #: ipalib/plugins/internal.py:443 msgid "Include Enabled" msgstr "" #: ipalib/plugins/internal.py:444 msgid "HBAC Test" msgstr "" #: ipalib/plugins/internal.py:445 msgid "Matched" msgstr "" #: ipalib/plugins/internal.py:446 msgid "Missing values: " msgstr "" #: ipalib/plugins/internal.py:447 msgid "New Test" msgstr "" #: ipalib/plugins/internal.py:448 msgid "Rules" msgstr "" #: ipalib/plugins/internal.py:449 msgid "Run Test" msgstr "" #: ipalib/plugins/internal.py:450 msgid "Specify external ${entity}" msgstr "" #: ipalib/plugins/internal.py:451 msgid "Unmatched" msgstr "" #: ipalib/plugins/internal.py:454 msgid "Host Certificate" msgstr "" #: ipalib/plugins/internal.py:455 ipalib/plugins/internal.py:548 msgid "Host Name" msgstr "" #: ipalib/plugins/internal.py:456 ipalib/plugins/internal.py:546 msgid "Delete Key, Unprovision" msgstr "" #: ipalib/plugins/internal.py:457 msgid "Host Settings" msgstr "" #: ipalib/plugins/internal.py:458 msgid "Enrolled" msgstr "" #: ipalib/plugins/internal.py:459 msgid "Enrollment" msgstr "" #: ipalib/plugins/internal.py:460 msgid "Fully Qualified Host Name" msgstr "" #: ipalib/plugins/internal.py:461 msgid "Kerberos Key" msgstr "" #: ipalib/plugins/internal.py:462 ipalib/plugins/internal.py:549 msgid "Kerberos Key Not Present" msgstr "" #: ipalib/plugins/internal.py:463 msgid "Kerberos Key Present, Host Provisioned" msgstr "" #: ipalib/plugins/internal.py:464 msgid "One-Time-Password" msgstr "" #: ipalib/plugins/internal.py:465 msgid "One-Time-Password Not Present" msgstr "" #: ipalib/plugins/internal.py:466 msgid "One-Time-Password Present" msgstr "" #: ipalib/plugins/internal.py:467 msgid "Reset OTP" msgstr "" #: ipalib/plugins/internal.py:468 msgid "Reset One-Time-Password" msgstr "" #: ipalib/plugins/internal.py:469 msgid "Set OTP" msgstr "" #: ipalib/plugins/internal.py:470 msgid "OTP set" msgstr "" #: ipalib/plugins/internal.py:471 msgid "Set One-Time-Password" msgstr "" #: ipalib/plugins/internal.py:473 ipalib/plugins/internal.py:553 msgid "Unprovision" msgstr "" #: ipalib/plugins/internal.py:474 msgid "Are you sure you want to unprovision this host?" msgstr "" #: ipalib/plugins/internal.py:475 ipalib/plugins/internal.py:555 msgid "Unprovisioning ${entity}" msgstr "" #: ipalib/plugins/internal.py:476 msgid "Host unprovisioned" msgstr "" #: ipalib/plugins/internal.py:479 msgid "Host Group Settings" msgstr "" #: ipalib/plugins/internal.py:482 ipalib/plugins/krbtpolicy.py:79 #: ipalib/plugins/krbtpolicy.py:80 msgid "Kerberos Ticket Policy" msgstr "" #: ipalib/plugins/internal.py:491 msgid "Netgroup Settings" msgstr "" #: ipalib/plugins/internal.py:494 ipalib/plugins/internal.py:542 #: ipalib/plugins/pwpolicy.py:444 ipalib/plugins/user.py:226 msgid "User" msgstr "" #: ipalib/plugins/internal.py:499 ipalib/plugins/internal.py:668 msgid "Identity" msgstr "" #: ipalib/plugins/internal.py:500 msgid "Permission with invalid target specification" msgstr "" #: ipalib/plugins/internal.py:505 msgid "Privilege Settings" msgstr "" #: ipalib/plugins/internal.py:508 ipalib/plugins/pwpolicy.py:224 msgid "Password Policy" msgstr "" #: ipalib/plugins/internal.py:511 msgid "Range Settings" msgstr "" #: ipalib/plugins/internal.py:512 msgid "Base ID" msgstr "" #: ipalib/plugins/internal.py:513 msgid "Primary RID base" msgstr "" #: ipalib/plugins/internal.py:514 msgid "Range size" msgstr "" #: ipalib/plugins/internal.py:515 msgid "Domain SID" msgstr "" #: ipalib/plugins/internal.py:516 msgid "Secondary RID base" msgstr "" #: ipalib/plugins/internal.py:518 ipalib/plugins/trust.py:142 msgid "Active Directory domain" msgstr "" #: ipalib/plugins/internal.py:519 msgid "Active Directory domain with POSIX attributes" msgstr "" #: ipalib/plugins/internal.py:520 msgid "Detect" msgstr "" #: ipalib/plugins/internal.py:521 msgid "Local domain" msgstr "" #: ipalib/plugins/internal.py:522 msgid "IPA trust" msgstr "" #: ipalib/plugins/internal.py:523 msgid "Active Directory winsync" msgstr "" #: ipalib/plugins/internal.py:526 ipalib/plugins/realmdomains.py:65 #: ipalib/plugins/realmdomains.py:66 msgid "Realm Domains" msgstr "" #: ipalib/plugins/internal.py:527 msgid "Check DNS" msgstr "" #: ipalib/plugins/internal.py:528 msgid "Do you also want to perform DNS check?" msgstr "" #: ipalib/plugins/internal.py:529 msgid "Force Update" msgstr "" #: ipalib/plugins/internal.py:532 msgid "Role Settings" msgstr "" #: ipalib/plugins/internal.py:545 msgid "Service Certificate" msgstr "" #: ipalib/plugins/internal.py:547 msgid "Service Settings" msgstr "" #: ipalib/plugins/internal.py:550 msgid "Provisioning" msgstr "" #: ipalib/plugins/internal.py:554 msgid "Are you sure you want to unprovision this service?" msgstr "" #: ipalib/plugins/internal.py:556 msgid "Service unprovisioned" msgstr "" #: ipalib/plugins/internal.py:557 msgid "Kerberos Key Present, Service Provisioned" msgstr "" #: ipalib/plugins/internal.py:560 msgid "SSH public keys" msgstr "" #: ipalib/plugins/internal.py:561 msgid "SSH public key:" msgstr "" #: ipalib/plugins/internal.py:562 msgid "Set SSH key" msgstr "" #: ipalib/plugins/internal.py:563 msgid "Show/Set key" msgstr "" #: ipalib/plugins/internal.py:564 msgid "Modified: key not set" msgstr "" #: ipalib/plugins/internal.py:565 msgid "Modified" msgstr "" #: ipalib/plugins/internal.py:566 msgid "New: key not set" msgstr "" #: ipalib/plugins/internal.py:567 msgid "New: key set" msgstr "" #: ipalib/plugins/internal.py:570 msgid "Groups" msgstr "" #: ipalib/plugins/internal.py:573 ipalib/plugins/sudocmdgroup.py:82 msgid "Commands" msgstr "" #: ipalib/plugins/internal.py:576 msgid "Allow" msgstr "" #: ipalib/plugins/internal.py:577 msgid "Any Command" msgstr "" #: ipalib/plugins/internal.py:578 msgid "Any Group" msgstr "" #: ipalib/plugins/internal.py:581 msgid "Run Commands" msgstr "" #: ipalib/plugins/internal.py:582 msgid "Deny" msgstr "" #: ipalib/plugins/internal.py:584 msgid "Access this host" msgstr "" #: ipalib/plugins/internal.py:586 msgid "Option added" msgstr "" #: ipalib/plugins/internal.py:587 msgid "${count} option(s) removed" msgstr "" #: ipalib/plugins/internal.py:589 msgid "As Whom" msgstr "" #: ipalib/plugins/internal.py:590 msgid "Specified Commands and Groups" msgstr "" #: ipalib/plugins/internal.py:591 msgid "Specified Groups" msgstr "" #: ipalib/plugins/internal.py:597 msgid "Account" msgstr "" #: ipalib/plugins/internal.py:598 msgid "Administrative account" msgstr "" #: ipalib/plugins/internal.py:599 msgid "SID blacklists" msgstr "" #: ipalib/plugins/internal.py:600 msgid "Trust Settings" msgstr "" #: ipalib/plugins/internal.py:601 ipalib/plugins/realmdomains.py:73 #: ipalib/plugins/trust.py:789 msgid "Domain" msgstr "" #: ipalib/plugins/internal.py:602 msgid "Establish using" msgstr "" #: ipalib/plugins/internal.py:603 ipalib/plugins/trust.py:211 msgid "Domain NetBIOS name" msgstr "" #: ipalib/plugins/internal.py:604 ipalib/plugins/trust.py:215 msgid "Domain Security Identifier" msgstr "" #: ipalib/plugins/internal.py:605 msgid "Pre-shared password" msgstr "" #: ipalib/plugins/internal.py:606 ipalib/plugins/trust.py:134 msgid "Trust direction" msgstr "" #: ipalib/plugins/internal.py:607 ipalib/plugins/trust.py:138 msgid "Trust status" msgstr "" #: ipalib/plugins/internal.py:608 ipalib/plugins/trust.py:136 msgid "Trust type" msgstr "" #: ipalib/plugins/internal.py:614 msgid "Account Settings" msgstr "" #: ipalib/plugins/internal.py:615 msgid "Account Status" msgstr "" #: ipalib/plugins/internal.py:616 msgid "Contact Settings" msgstr "" #: ipalib/plugins/internal.py:617 msgid "Employee Information" msgstr "" #: ipalib/plugins/internal.py:618 msgid "Error changing account status" msgstr "" #: ipalib/plugins/internal.py:619 msgid "Password expiration" msgstr "" #: ipalib/plugins/internal.py:620 msgid "Mailing Address" msgstr "" #: ipalib/plugins/internal.py:621 msgid "Misc. Information" msgstr "" #: ipalib/plugins/internal.py:622 msgid "" "Are you sure you want to ${action} the user?
The change will take effect " "immediately." msgstr "" #: ipalib/plugins/internal.py:623 msgid "Click to ${action}" msgstr "" #: ipalib/plugins/internal.py:627 ipalib/plugins/passwd.py:80 msgid "Current Password" msgstr "" #: ipalib/plugins/internal.py:628 msgid "Current password is required" msgstr "" #: ipalib/plugins/internal.py:629 msgid "Your password expires in ${days} days." msgstr "" #: ipalib/plugins/internal.py:630 msgid "The password or username you entered is incorrect." msgstr "" #: ipalib/plugins/internal.py:631 ipalib/plugins/passwd.py:77 msgid "New Password" msgstr "" #: ipalib/plugins/internal.py:632 msgid "New password is required" msgstr "" #: ipalib/plugins/internal.py:634 msgid "Password change complete" msgstr "" #: ipalib/plugins/internal.py:635 msgid "Passwords must match" msgstr "" #: ipalib/plugins/internal.py:636 msgid "Password reset was not successful." msgstr "" #: ipalib/plugins/internal.py:637 msgid "Reset Password" msgstr "" #: ipalib/plugins/internal.py:638 msgid "Reset your password." msgstr "" #: ipalib/plugins/internal.py:639 msgid "Verify Password" msgstr "" #: ipalib/plugins/internal.py:642 msgid "Are you sure you want to delete selected entries?" msgstr "" #: ipalib/plugins/internal.py:643 msgid "${count} item(s) deleted" msgstr "" #: ipalib/plugins/internal.py:644 msgid "Are you sure you want to disable selected entries?" msgstr "" #: ipalib/plugins/internal.py:645 msgid "${count} item(s) disabled" msgstr "" #: ipalib/plugins/internal.py:646 msgid "Are you sure you want to enable selected entries?" msgstr "" #: ipalib/plugins/internal.py:647 msgid "${count} item(s) enabled" msgstr "" #: ipalib/plugins/internal.py:648 msgid "Some entries were not deleted" msgstr "" #: ipalib/plugins/internal.py:649 msgid "Quick Links" msgstr "" #: ipalib/plugins/internal.py:650 msgid "Select All" msgstr "" #: ipalib/plugins/internal.py:651 msgid "" "Query returned more results than the configured size limit. Displaying the " "first ${counter} results." msgstr "" #: ipalib/plugins/internal.py:652 msgid "Unselect All" msgstr "" #: ipalib/plugins/internal.py:656 msgid "Disabled" msgstr "" #: ipalib/plugins/internal.py:662 msgid "Audit" msgstr "" #: ipalib/plugins/internal.py:663 msgid "Automember" msgstr "" #: ipalib/plugins/internal.py:664 msgid "Automount" msgstr "" #: ipalib/plugins/internal.py:666 msgid "DNS" msgstr "" #: ipalib/plugins/internal.py:667 msgid "Host Based Access Control" msgstr "" #: ipalib/plugins/internal.py:669 msgid "IPA Server" msgstr "" #: ipalib/plugins/internal.py:670 msgid "Policy" msgstr "" #: ipalib/plugins/internal.py:671 msgid "Role Based Access Control" msgstr "" #: ipalib/plugins/internal.py:672 msgid "Sudo" msgstr "" #: ipalib/plugins/internal.py:673 ipalib/plugins/trust.py:200 msgid "Trusts" msgstr "" #: ipalib/plugins/internal.py:675 msgid "True" msgstr "" #: ipalib/plugins/internal.py:677 msgid "Next" msgstr "" #: ipalib/plugins/internal.py:678 msgid "Page" msgstr "" #: ipalib/plugins/internal.py:679 msgid "Prev" msgstr "" #: ipalib/plugins/internal.py:680 msgid "undo" msgstr "" #: ipalib/plugins/internal.py:681 msgid "undo all" msgstr "" #: ipalib/plugins/internal.py:683 msgid "Text does not match field pattern" msgstr "" #: ipalib/plugins/internal.py:684 msgid "Must be a decimal number" msgstr "" #: ipalib/plugins/internal.py:685 msgid "Must be an integer" msgstr "" #: ipalib/plugins/internal.py:686 msgid "Not a valid IP address" msgstr "" #: ipalib/plugins/internal.py:687 msgid "Not a valid IPv4 address" msgstr "" #: ipalib/plugins/internal.py:688 msgid "Not a valid IPv6 address" msgstr "" #: ipalib/plugins/internal.py:689 msgid "Maximum value is ${value}" msgstr "" #: ipalib/plugins/internal.py:690 msgid "Minimum value is ${value}" msgstr "" #: ipalib/plugins/internal.py:691 msgid "Not a valid network address" msgstr "" #: ipalib/plugins/internal.py:692 msgid "'${port}' is not a valid port" msgstr "" #: ipalib/plugins/internal.py:693 msgid "Required field" msgstr "" #: ipalib/plugins/internal.py:694 msgid "Unsupported value" msgstr "" #: ipalib/plugins/internal.py:699 msgid "Dict of I18N messages" msgstr "" #: ipalib/plugins/krbtpolicy.py:25 msgid "" "\n" "Kerberos ticket policy\n" "\n" "There is a single Kerberos ticket policy. This policy defines the\n" "maximum ticket lifetime and the maximum renewal age, the period during\n" "which the ticket is renewable.\n" "\n" "You can also create a per-user ticket policy by specifying the user login.\n" "\n" "For changes to the global policy to take effect, restarting the KDC service\n" "is required, which can be achieved using:\n" "\n" "service krb5kdc restart\n" "\n" "Changes to per-user policies take effect immediately for newly requested\n" "tickets (e.g. when the user next runs kinit).\n" "\n" "EXAMPLES:\n" "\n" " Display the current Kerberos ticket policy:\n" " ipa krbtpolicy-show\n" "\n" " Reset the policy to the default:\n" " ipa krbtpolicy-reset\n" "\n" " Modify the policy to 8 hours max life, 1-day max renewal:\n" " ipa krbtpolicy-mod --maxlife=28800 --maxrenew=86400\n" "\n" " Display effective Kerberos ticket policy for user 'admin':\n" " ipa krbtpolicy-show admin\n" "\n" " Reset per-user policy for user 'admin':\n" " ipa krbtpolicy-reset admin\n" "\n" " Modify per-user policy for user 'admin':\n" " ipa krbtpolicy-mod admin --maxlife=3600\n" msgstr "" #: ipalib/plugins/krbtpolicy.py:75 msgid "kerberos ticket policy settings" msgstr "" #: ipalib/plugins/krbtpolicy.py:86 msgid "Manage ticket policy for specific user" msgstr "" #: ipalib/plugins/krbtpolicy.py:91 msgid "Max life" msgstr "" #: ipalib/plugins/krbtpolicy.py:92 msgid "Maximum ticket life (seconds)" msgstr "" #: ipalib/plugins/krbtpolicy.py:97 msgid "Max renew" msgstr "" #: ipalib/plugins/krbtpolicy.py:98 msgid "Maximum renewable age (seconds)" msgstr "" #: ipalib/plugins/krbtpolicy.py:112 msgid "Modify Kerberos ticket policy." msgstr "" #: ipalib/plugins/krbtpolicy.py:126 msgid "Display the current Kerberos ticket policy." msgstr "" #: ipalib/plugins/krbtpolicy.py:151 msgid "Reset Kerberos ticket policy to the default values." msgstr "" #: ipalib/plugins/migration.py:35 msgid "" "\n" "Migration to IPA\n" "\n" "Migrate users and groups from an LDAP server to IPA.\n" "\n" "This performs an LDAP query against the remote server searching for\n" "users and groups in a container. In order to migrate passwords you need\n" "to bind as a user that can read the userPassword attribute on the remote\n" "server. This is generally restricted to high-level admins such as\n" "cn=Directory Manager in 389-ds (this is the default bind user).\n" "\n" "The default user container is ou=People.\n" "\n" "The default group container is ou=Groups.\n" "\n" "Users and groups that already exist on the IPA server are skipped.\n" "\n" "Two LDAP schemas define how group members are stored: RFC2307 and\n" "RFC2307bis. RFC2307bis uses member and uniquemember to specify group\n" "members, RFC2307 uses memberUid. The default schema is RFC2307bis.\n" "\n" "The schema compat feature allows IPA to reformat data for systems that\n" "do not support RFC2307bis. It is recommended that this feature is disabled\n" "during migration to reduce system overhead. It can be re-enabled after\n" "migration. To migrate with it enabled use the \"--with-compat\" option.\n" "\n" "Migrated users do not have Kerberos credentials, they have only their\n" "LDAP password. To complete the migration process, users need to go\n" "to http://ipa.example.com/ipa/migration and authenticate using their\n" "LDAP password in order to generate their Kerberos credentials.\n" "\n" "Migration is disabled by default. Use the command ipa config-mod to\n" "enable it:\n" "\n" " ipa config-mod --enable-migration=TRUE\n" "\n" "If a base DN is not provided with --basedn then IPA will use either\n" "the value of defaultNamingContext if it is set or the first value\n" "in namingContexts set in the root of the remote LDAP server.\n" "\n" "Users are added as members to the default user group. This can be a\n" "time-intensive task so during migration this is done in a batch\n" "mode for every 100 users. As a result there will be a window in which\n" "users will be added to IPA but will not be members of the default\n" "user group.\n" "\n" "EXAMPLES:\n" "\n" " The simplest migration, accepting all defaults:\n" " ipa migrate-ds ldap://ds.example.com:389\n" "\n" " Specify the user and group container. This can be used to migrate user\n" " and group data from an IPA v1 server:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Since IPA v2 server already contain predefined groups that may collide " "with\n" " groups in migrated (IPA v1) server (for example admins, ipausers), users\n" " having colliding group as their primary group may happen to belong to\n" " an unknown group on new IPA v2 server.\n" " Use --group-overwrite-gid option to overwrite GID of already existing " "groups\n" " to prevent this issue:\n" " ipa migrate-ds --group-overwrite-gid \\\n" " --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " ldap://ds.example.com:389\n" "\n" " Migrated users or groups may have object class and accompanied attributes\n" " unknown to the IPA v2 server. These object classes and attributes may be\n" " left out of the migration process:\n" " ipa migrate-ds --user-container='cn=users,cn=accounts' \\\n" " --group-container='cn=groups,cn=accounts' \\\n" " --user-ignore-objectclass=radiusprofile \\\n" " --user-ignore-attribute=radiusgroupname \\\n" " ldap://ds.example.com:389\n" "\n" "LOGGING\n" "\n" "Migration will log warnings and errors to the Apache error log. This\n" "file should be evaluated post-migration to correct or investigate any\n" "issues that were discovered.\n" "\n" "For every 100 users migrated an info-level message will be displayed to\n" "give the current progress and duration to make it possible to track\n" "the progress of migration.\n" "\n" "If the log level is debug, either by setting debug = True in\n" "/etc/ipa/default.conf or /etc/ipa/server.conf, then an entry will be " "printed\n" "for each user added plus a summary when the default user group is\n" "updated.\n" msgstr "" #: ipalib/plugins/migration.py:130 #, python-format msgid "" "Kerberos principal %s already exists. Use 'ipa user-mod' to set it manually." msgstr "" #: ipalib/plugins/migration.py:131 #, python-format msgid "" "Unable to determine if Kerberos principal %s already exists. Use 'ipa user-" "mod' to set it manually." msgstr "" #: ipalib/plugins/migration.py:132 msgid "" "Failed to add user to the default group. Use 'ipa group-add-member' to add " "manually." msgstr "" #: ipalib/plugins/migration.py:133 msgid "Migration of LDAP search reference is not supported." msgstr "" #: ipalib/plugins/migration.py:134 msgid "Malformed DN" msgstr "" #: ipalib/plugins/migration.py:151 #, python-format msgid "%(user)s is not a POSIX user" msgstr "" #: ipalib/plugins/migration.py:419 msgid "" ". Check GID of the existing group. Use --group-overwrite-gid option to " "overwrite the GID" msgstr "" #: ipalib/plugins/migration.py:434 msgid "Invalid LDAP URI." msgstr "" #: ipalib/plugins/migration.py:439 msgid "Migrate users and groups from DS to IPA." msgstr "" #: ipalib/plugins/migration.py:486 msgid "LDAP URI" msgstr "" #: ipalib/plugins/migration.py:487 msgid "LDAP URI of DS server to migrate from" msgstr "" #: ipalib/plugins/migration.py:493 msgid "bind password" msgstr "" #: ipalib/plugins/migration.py:500 msgid "Bind DN" msgstr "" #: ipalib/plugins/migration.py:506 msgid "User container" msgstr "" #: ipalib/plugins/migration.py:507 msgid "DN of container for users in DS relative to base DN" msgstr "" #: ipalib/plugins/migration.py:513 msgid "Group container" msgstr "" #: ipalib/plugins/migration.py:514 msgid "DN of container for groups in DS relative to base DN" msgstr "" #: ipalib/plugins/migration.py:520 msgid "User object class" msgstr "" #: ipalib/plugins/migration.py:521 msgid "Objectclasses used to search for user entries in DS" msgstr "" #: ipalib/plugins/migration.py:528 msgid "Group object class" msgstr "" #: ipalib/plugins/migration.py:529 msgid "Objectclasses used to search for group entries in DS" msgstr "" #: ipalib/plugins/migration.py:536 msgid "Ignore user object class" msgstr "" #: ipalib/plugins/migration.py:537 msgid "Objectclasses to be ignored for user entries in DS" msgstr "" #: ipalib/plugins/migration.py:544 msgid "Ignore user attribute" msgstr "" #: ipalib/plugins/migration.py:545 msgid "Attributes to be ignored for user entries in DS" msgstr "" #: ipalib/plugins/migration.py:552 msgid "Ignore group object class" msgstr "" #: ipalib/plugins/migration.py:553 msgid "Objectclasses to be ignored for group entries in DS" msgstr "" #: ipalib/plugins/migration.py:560 msgid "Ignore group attribute" msgstr "" #: ipalib/plugins/migration.py:561 msgid "Attributes to be ignored for group entries in DS" msgstr "" #: ipalib/plugins/migration.py:568 msgid "Overwrite GID" msgstr "" #: ipalib/plugins/migration.py:569 msgid "" "When migrating a group already existing in IPA domain overwrite the group " "GID and report as success" msgstr "" #: ipalib/plugins/migration.py:574 msgid "LDAP schema" msgstr "" #: ipalib/plugins/migration.py:575 msgid "" "The schema used on the LDAP server. Supported values are RFC2307 and " "RFC2307bis. The default is RFC2307bis" msgstr "" #: ipalib/plugins/migration.py:581 msgid "Continue" msgstr "" #: ipalib/plugins/migration.py:582 msgid "" "Continuous operation mode. Errors are reported but the process continues" msgstr "" #: ipalib/plugins/migration.py:587 msgid "Base DN" msgstr "" #: ipalib/plugins/migration.py:588 msgid "Base DN on remote LDAP server" msgstr "" #: ipalib/plugins/migration.py:592 msgid "Ignore compat plugin" msgstr "" #: ipalib/plugins/migration.py:593 msgid "Allows migration despite the usage of compat plugin" msgstr "" #: ipalib/plugins/migration.py:601 msgid "Lists of objects migrated; categorized by type." msgstr "" #: ipalib/plugins/migration.py:605 msgid "Lists of objects that could not be migrated; categorized by type." msgstr "" #: ipalib/plugins/migration.py:609 msgid "False if migration mode was disabled." msgstr "" #: ipalib/plugins/migration.py:613 msgid "False if migration fails because the compatibility plug-in is enabled." msgstr "" #: ipalib/plugins/migration.py:617 #, python-format msgid "%s to exclude from migration" msgstr "" #: ipalib/plugins/migration.py:619 msgid "" "search results for objects to be migrated\n" "have been truncated by the server;\n" "migration process might be incomplete\n" msgstr "" #: ipalib/plugins/migration.py:624 msgid "Migration mode is disabled. Use 'ipa config-mod' to enable it." msgstr "" #: ipalib/plugins/migration.py:627 msgid "" "Passwords have been migrated in pre-hashed format.\n" "IPA is unable to generate Kerberos keys unless provided\n" "with clear text passwords. All migrated users need to\n" "login at https://your.domain/ipa/migration/ before they\n" "can use their Kerberos accounts." msgstr "" #: ipalib/plugins/migration.py:713 #, python-format msgid "" "%(container)s LDAP search did not return any result (search base: " "%(search_base)s, objectclass: %(objectclass)s)" msgstr "" #: ipalib/plugins/migration.py:745 ipalib/plugins/user.py:519 msgid "Default group for new users not found" msgstr "" #: ipalib/plugins/misc.py:25 msgid "" "\n" "Misc plug-ins\n" msgstr "" #: ipalib/plugins/misc.py:36 msgid "Show environment variables." msgstr "" #: ipalib/plugins/misc.py:38 #, python-format msgid "%(count)d variables" msgstr "" #: ipalib/plugins/misc.py:47 ipalib/plugins/misc.py:115 msgid "" "retrieve and print all attributes from the server. Affects command output." msgstr "" #: ipalib/plugins/misc.py:61 msgid "Total number of variables env (>= count)" msgstr "" #: ipalib/plugins/misc.py:66 msgid "Number of variables returned (<= total)" msgstr "" #: ipalib/plugins/misc.py:106 msgid "Show all loaded plugins." msgstr "" #: ipalib/plugins/misc.py:109 #, python-format msgid "%(count)d plugin loaded" msgid_plural "%(count)d plugins loaded" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/misc.py:126 msgid "Number of plugins loaded" msgstr "" #: ipalib/plugins/netgroup.py:28 msgid "" "\n" "Netgroups\n" "\n" "A netgroup is a group used for permission checking. It can contain both\n" "user and host values.\n" "\n" "EXAMPLES:\n" "\n" " Add a new netgroup:\n" " ipa netgroup-add --desc=\"NFS admins\" admins\n" "\n" " Add members to the netgroup:\n" " ipa netgroup-add-member --users=tuser1 --users=tuser2 admins\n" "\n" " Remove a member from the netgroup:\n" " ipa netgroup-remove-member --users=tuser2 admins\n" "\n" " Display information about a netgroup:\n" " ipa netgroup-show admins\n" "\n" " Delete a netgroup:\n" " ipa netgroup-del admins\n" msgstr "" #: ipalib/plugins/netgroup.py:69 msgid "Member Host" msgstr "" #: ipalib/plugins/netgroup.py:81 msgid "netgroup" msgstr "" #: ipalib/plugins/netgroup.py:82 msgid "netgroups" msgstr "" #: ipalib/plugins/netgroup.py:108 msgid "Netgroups" msgstr "" #: ipalib/plugins/netgroup.py:109 msgid "Netgroup" msgstr "" #: ipalib/plugins/netgroup.py:116 msgid "Netgroup name" msgstr "" #: ipalib/plugins/netgroup.py:123 msgid "Netgroup description" msgstr "" #: ipalib/plugins/netgroup.py:129 msgid "NIS domain name" msgstr "" #: ipalib/plugins/netgroup.py:134 msgid "IPA unique ID" msgstr "" #: ipalib/plugins/netgroup.py:156 msgid "Add a new netgroup." msgstr "" #: ipalib/plugins/netgroup.py:159 #, python-format msgid "Added netgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/netgroup.py:161 #, python-format msgid "" "hostgroup with name \"%s\" already exists. Hostgroups and netgroups share a " "common namespace" msgstr "" #: ipalib/plugins/netgroup.py:193 msgid "Delete a netgroup." msgstr "" #: ipalib/plugins/netgroup.py:195 #, python-format msgid "Deleted netgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/netgroup.py:201 msgid "Modify a netgroup." msgstr "" #: ipalib/plugins/netgroup.py:204 #, python-format msgid "Modified netgroup \"%(value)s\"" msgstr "" #: ipalib/plugins/netgroup.py:222 msgid "Search for a netgroup." msgstr "" #: ipalib/plugins/netgroup.py:227 #, python-format msgid "%(count)d netgroup matched" msgid_plural "%(count)d netgroups matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/netgroup.py:237 msgid "search for managed groups" msgstr "" #: ipalib/plugins/netgroup.py:260 msgid "Display information about a netgroup." msgstr "" #: ipalib/plugins/netgroup.py:268 msgid "Add members to a netgroup." msgstr "" #: ipalib/plugins/netgroup.py:284 msgid "Remove members from a netgroup." msgstr "" #: ipalib/plugins/passwd.py:29 msgid "" "\n" "Set a user's password\n" "\n" "If someone other than a user changes that user's password (e.g., Helpdesk\n" "resets it) then the password will need to be changed the first time it\n" "is used. This is so the end-user is the only one who knows the password.\n" "\n" "The IPA password policy controls how often a password may be changed,\n" "what strength requirements exist, and the length of the password history.\n" "\n" "EXAMPLES:\n" "\n" " To reset your own password:\n" " ipa passwd\n" "\n" " To change another user's password:\n" " ipa passwd tuser1\n" msgstr "" #: ipalib/plugins/passwd.py:65 msgid "Set a user's password." msgstr "" #: ipalib/plugins/passwd.py:89 #, python-format msgid "Changed password for \"%(value)s\"" msgstr "" #: ipalib/plugins/passwd.py:115 msgid "Invalid credentials" msgstr "" #: ipalib/plugins/permission.py:27 msgid "" "\n" "Permissions\n" "\n" "A permission enables fine-grained delegation of rights. A permission is\n" "a human-readable form of a 389-ds Access Control Rule, or instruction " "(ACI).\n" "A permission grants the right to perform a specific task such as adding a\n" "user, modifying a group, etc.\n" "\n" "A permission may not contain other permissions.\n" "\n" "* A permission grants access to read, write, add or delete.\n" "* A privilege combines similar permissions (for example all the permissions\n" " needed to add a user).\n" "* A role grants a set of privileges to users, groups, hosts or hostgroups.\n" "\n" "A permission is made up of a number of different parts:\n" "\n" "1. The name of the permission.\n" "2. The target of the permission.\n" "3. The rights granted by the permission.\n" "\n" "Rights define what operations are allowed, and may be one or more\n" "of the following:\n" "1. write - write one or more attributes\n" "2. read - read one or more attributes\n" "3. add - add a new entry to the tree\n" "4. delete - delete an existing entry\n" "5. all - all permissions are granted\n" "\n" "Read permission is granted for most attributes by default so the read\n" "permission is not expected to be used very often.\n" "\n" "Note the distinction between attributes and entries. The permissions are\n" "independent, so being able to add a user does not mean that the user will\n" "be editable.\n" "\n" "There are a number of allowed targets:\n" "1. type: a type of object (user, group, etc).\n" "2. memberof: a member of a group or hostgroup\n" "3. filter: an LDAP filter\n" "4. subtree: an LDAP filter specifying part of the LDAP DIT. This is a\n" " super-set of the \"type\" target.\n" "5. targetgroup: grant access to modify a specific group (such as granting\n" " the rights to manage group membership)\n" "\n" "EXAMPLES:\n" "\n" " Add a permission that grants the creation of users:\n" " ipa permission-add --type=user --permissions=add \"Add Users\"\n" "\n" " Add a permission that grants the ability to manage group membership:\n" " ipa permission-add --attrs=member --permissions=write --type=group " "\"Manage Group Members\"\n" msgstr "" #: ipalib/plugins/permission.py:85 msgid "Permission Type" msgstr "" #: ipalib/plugins/permission.py:107 msgid "permission" msgstr "" #: ipalib/plugins/permission.py:108 msgid "permissions" msgstr "" #: ipalib/plugins/permission.py:128 msgid "Permission name" msgstr "" #: ipalib/plugins/permission.py:136 msgid "Permissions to grant (read, write, add, delete, all)" msgstr "" #: ipalib/plugins/permission.py:151 msgid "" "Type of IPA object (user, group, host, hostgroup, service, netgroup, dns)" msgstr "" #: ipalib/plugins/permission.py:157 msgid "Member of group" msgstr "" #: ipalib/plugins/permission.py:158 msgid "Target members of a group" msgstr "" #: ipalib/plugins/permission.py:170 msgid "Subtree to apply permissions to" msgstr "" #: ipalib/plugins/permission.py:176 msgid "User group to apply permissions to" msgstr "" #: ipalib/plugins/permission.py:201 msgid "Add a new permission." msgstr "" #: ipalib/plugins/permission.py:203 ipalib/plugins/permission.py:259 #, python-format msgid "Added permission \"%(value)s\"" msgstr "" #: ipalib/plugins/permission.py:257 msgid "Add a system permission without an ACI" msgstr "" #: ipalib/plugins/permission.py:265 msgid "Permission type" msgstr "" #: ipalib/plugins/permission.py:292 msgid "Delete a permission." msgstr "" #: ipalib/plugins/permission.py:294 #, python-format msgid "Deleted permission \"%(value)s\"" msgstr "" #: ipalib/plugins/permission.py:300 msgid "force delete of SYSTEM permissions" msgstr "" #: ipalib/plugins/permission.py:308 msgid "A SYSTEM permission may not be removed" msgstr "" #: ipalib/plugins/permission.py:320 msgid "Modify a permission." msgstr "" #: ipalib/plugins/permission.py:322 #, python-format msgid "Modified permission \"%(value)s\"" msgstr "" #: ipalib/plugins/permission.py:329 msgid "A SYSTEM permission may not be modified" msgstr "" #: ipalib/plugins/permission.py:354 msgid "New name can not be empty" msgstr "" #: ipalib/plugins/permission.py:410 msgid "Search for permissions." msgstr "" #: ipalib/plugins/permission.py:413 #, python-format msgid "%(count)d permission matched" msgid_plural "%(count)d permissions matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/permission.py:492 msgid "Display information about a permission." msgstr "" #: ipalib/plugins/ping.py:26 msgid "" "\n" "Ping the remote IPA server to ensure it is running.\n" "\n" "The ping command sends an echo request to an IPA server. The server\n" "returns its version information. This is used by an IPA client\n" "to confirm that the server is available and accepting requests.\n" "\n" "The server from xmlrpc_uri in /etc/ipa/default.conf is contacted first.\n" "If it does not respond then the client will contact any servers defined\n" "by ldap SRV records in DNS.\n" "\n" "EXAMPLES:\n" "\n" " Ping an IPA server:\n" " ipa ping\n" " ------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " ------------------------------------------\n" "\n" " Ping an IPA server verbosely:\n" " ipa -v ping\n" " ipa: INFO: trying https://ipa.example.com/ipa/xml\n" " ipa: INFO: Forwarding 'ping' to server 'https://ipa.example.com/ipa/xml'\n" " -----------------------------------------------------\n" " IPA server version 2.1.9. API version 2.20\n" " -----------------------------------------------------\n" msgstr "" #: ipalib/plugins/ping.py:55 msgid "Ping a remote server." msgstr "" #: ipalib/plugins/pkinit.py:26 msgid "" "\n" "Kerberos pkinit options\n" "\n" "Enable or disable anonymous pkinit using the principal\n" "WELLKNOWN/ANONYMOUS@REALM. The server must have been installed with\n" "pkinit support.\n" "\n" "EXAMPLES:\n" "\n" " Enable anonymous pkinit:\n" " ipa pkinit-anonymous enable\n" "\n" " Disable anonymous pkinit:\n" " ipa pkinit-anonymous disable\n" "\n" "For more information on anonymous pkinit see:\n" "\n" "http://k5wiki.kerberos.org/wiki/Projects/Anonymous_pkinit\n" msgstr "" #: ipalib/plugins/pkinit.py:50 msgid "pkinit" msgstr "" #: ipalib/plugins/pkinit.py:52 msgid "PKINIT" msgstr "" #: ipalib/plugins/pkinit.py:64 #, python-format msgid "Unknown command %s" msgstr "" #: ipalib/plugins/pkinit.py:68 msgid "Enable or Disable Anonymous PKINIT." msgstr "" #: ipalib/plugins/privilege.py:23 msgid "" "\n" "Privileges\n" "\n" "A privilege combines permissions into a logical task. A permission provides\n" "the rights to do a single task. There are some IPA operations that require\n" "multiple permissions to succeed. A privilege is where permissions are\n" "combined in order to perform a specific task.\n" "\n" "For example, adding a user requires the following permissions:\n" " * Creating a new user entry\n" " * Resetting a user password\n" " * Adding the new user to the default IPA users group\n" "\n" "Combining these three low-level tasks into a higher level task in the\n" "form of a privilege named \"Add User\" makes it easier to manage Roles.\n" "\n" "A privilege may not contain other privileges.\n" "\n" "See role and permission for additional information.\n" msgstr "" #: ipalib/plugins/privilege.py:49 msgid "privilege" msgstr "" #: ipalib/plugins/privilege.py:50 msgid "privileges" msgstr "" #: ipalib/plugins/privilege.py:62 msgid "Privileges" msgstr "" #: ipalib/plugins/privilege.py:63 msgid "Privilege" msgstr "" #: ipalib/plugins/privilege.py:68 msgid "Privilege name" msgstr "" #: ipalib/plugins/privilege.py:74 msgid "Privilege description" msgstr "" #: ipalib/plugins/privilege.py:82 msgid "Add a new privilege." msgstr "" #: ipalib/plugins/privilege.py:84 #, python-format msgid "Added privilege \"%(value)s\"" msgstr "" #: ipalib/plugins/privilege.py:90 msgid "Delete a privilege." msgstr "" #: ipalib/plugins/privilege.py:92 #, python-format msgid "Deleted privilege \"%(value)s\"" msgstr "" #: ipalib/plugins/privilege.py:98 msgid "Modify a privilege." msgstr "" #: ipalib/plugins/privilege.py:100 #, python-format msgid "Modified privilege \"%(value)s\"" msgstr "" #: ipalib/plugins/privilege.py:106 msgid "Search for privileges." msgstr "" #: ipalib/plugins/privilege.py:109 #, python-format msgid "%(count)d privilege matched" msgid_plural "%(count)d privileges matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/privilege.py:116 msgid "Display information about a privilege." msgstr "" #: ipalib/plugins/privilege.py:122 msgid "Add members to a privilege." msgstr "" #: ipalib/plugins/privilege.py:139 msgid "Add permissions to a privilege." msgstr "" #: ipalib/plugins/privilege.py:154 msgid "Number of permissions added" msgstr "" #: ipalib/plugins/privilege.py:162 msgid "Remove permissions from a privilege." msgstr "" #: ipalib/plugins/privilege.py:179 msgid "Number of permissions removed" msgstr "" #: ipalib/plugins/pwpolicy.py:30 msgid "" "\n" "Password policy\n" "\n" "A password policy sets limitations on IPA passwords, including maximum\n" "lifetime, minimum lifetime, the number of passwords to save in\n" "history, the number of character classes required (for stronger passwords)\n" "and the minimum password length.\n" "\n" "By default there is a single, global policy for all users. You can also\n" "create a password policy to apply to a group. Each user is only subject\n" "to one password policy, either the group policy or the global policy. A\n" "group policy stands alone; it is not a super-set of the global policy plus\n" "custom settings.\n" "\n" "Each group password policy requires a unique priority setting. If a user\n" "is in multiple groups that have password policies, this priority determines\n" "which password policy is applied. A lower value indicates a higher priority\n" "policy.\n" "\n" "Group password policies are automatically removed when the groups they\n" "are associated with are removed.\n" "\n" "EXAMPLES:\n" "\n" " Modify the global policy:\n" " ipa pwpolicy-mod --minlength=10\n" "\n" " Add a new group password policy:\n" " ipa pwpolicy-add --maxlife=90 --minlife=1 --history=10 --minclasses=3 --" "minlength=8 --priority=10 localadmins\n" "\n" " Display the global password policy:\n" " ipa pwpolicy-show\n" "\n" " Display a group password policy:\n" " ipa pwpolicy-show localadmins\n" "\n" " Display the policy that would be applied to a given user:\n" " ipa pwpolicy-show --user=tuser1\n" "\n" " Modify a group password policy:\n" " ipa pwpolicy-mod --minclasses=2 localadmins\n" msgstr "" #: ipalib/plugins/pwpolicy.py:90 #, python-format msgid "priority must be a unique value (%(prio)d already used by %(gname)s)" msgstr "" #: ipalib/plugins/pwpolicy.py:180 msgid "password policy" msgstr "" #: ipalib/plugins/pwpolicy.py:181 msgid "password policies" msgstr "" #: ipalib/plugins/pwpolicy.py:205 msgid "Max failures" msgstr "" #: ipalib/plugins/pwpolicy.py:206 msgid "Consecutive failures before lockout" msgstr "" #: ipalib/plugins/pwpolicy.py:211 msgid "Failure reset interval" msgstr "" #: ipalib/plugins/pwpolicy.py:212 msgid "Period after which failure count will be reset (seconds)" msgstr "" #: ipalib/plugins/pwpolicy.py:217 msgid "Lockout duration" msgstr "" #: ipalib/plugins/pwpolicy.py:218 msgid "Period for which lockout is enforced (seconds)" msgstr "" #: ipalib/plugins/pwpolicy.py:223 msgid "Password Policies" msgstr "" #: ipalib/plugins/pwpolicy.py:229 msgid "Group" msgstr "" #: ipalib/plugins/pwpolicy.py:230 msgid "Manage password policy for specific group" msgstr "" #: ipalib/plugins/pwpolicy.py:235 msgid "Max lifetime (days)" msgstr "" #: ipalib/plugins/pwpolicy.py:236 msgid "Maximum password lifetime (in days)" msgstr "" #: ipalib/plugins/pwpolicy.py:242 msgid "Min lifetime (hours)" msgstr "" #: ipalib/plugins/pwpolicy.py:243 msgid "Minimum password lifetime (in hours)" msgstr "" #: ipalib/plugins/pwpolicy.py:248 msgid "History size" msgstr "" #: ipalib/plugins/pwpolicy.py:249 msgid "Password history size" msgstr "" #: ipalib/plugins/pwpolicy.py:254 msgid "Character classes" msgstr "" #: ipalib/plugins/pwpolicy.py:255 msgid "Minimum number of character classes" msgstr "" #: ipalib/plugins/pwpolicy.py:261 msgid "Min length" msgstr "" #: ipalib/plugins/pwpolicy.py:262 msgid "Minimum length of password" msgstr "" #: ipalib/plugins/pwpolicy.py:268 msgid "Priority of the policy (higher number means lower priority" msgstr "" #: ipalib/plugins/pwpolicy.py:322 msgid "Maximum password life must be greater than minimum." msgstr "" #: ipalib/plugins/pwpolicy.py:341 msgid "Add a new group password policy." msgstr "" #: ipalib/plugins/pwpolicy.py:368 msgid "Delete a group password policy." msgstr "" #: ipalib/plugins/pwpolicy.py:380 msgid "cannot delete global password policy" msgstr "" #: ipalib/plugins/pwpolicy.py:396 msgid "Modify a group password policy." msgstr "" #: ipalib/plugins/pwpolicy.py:407 msgid "priority cannot be set on global policy" msgstr "" #: ipalib/plugins/pwpolicy.py:440 msgid "Display information about password policy." msgstr "" #: ipalib/plugins/pwpolicy.py:445 msgid "Display effective policy for a specific user" msgstr "" #: ipalib/plugins/pwpolicy.py:470 msgid "Search for group password policies." msgstr "" #: ipalib/plugins/realmdomains.py:30 msgid "" "\n" "Realm domains\n" "\n" "Manage the list of domains associated with IPA realm.\n" "\n" "EXAMPLES:\n" "\n" " Display the current list of realm domains:\n" " ipa realmdomains-show\n" "\n" " Replace the list of realm domains:\n" " ipa realmdomains-mod --domain=example.com\n" " ipa realmdomains-mod --domain={example1.com,example2.com,example3.com}\n" "\n" " Add a domain to the list of realm domains:\n" " ipa realmdomains-mod --add-domain=newdomain.com\n" "\n" " Delete a domain from the list of realm domains:\n" " ipa realmdomains-mod --del-domain=olddomain.com\n" msgstr "" #: ipalib/plugins/realmdomains.py:61 msgid "Realm domains" msgstr "" #: ipalib/plugins/realmdomains.py:79 msgid "Add domain" msgstr "" #: ipalib/plugins/realmdomains.py:85 msgid "Delete domain" msgstr "" #: ipalib/plugins/realmdomains.py:93 msgid "Modify realm domains." msgstr "" #: ipalib/plugins/realmdomains.py:98 msgid "Force adding domain even if not in DNS" msgstr "" #: ipalib/plugins/realmdomains.py:111 msgid "" "you cannot specify the --domain option together with --add-domain or --del-" "domain" msgstr "" #: ipalib/plugins/realmdomains.py:113 ipalib/plugins/realmdomains.py:133 msgid "cannot delete domain of IPA server" msgstr "" #: ipalib/plugins/realmdomains.py:118 #, python-format msgid "no SOA or NS records found for domains: %s" msgstr "" #: ipalib/plugins/realmdomains.py:127 #, python-format msgid "no SOA or NS records found for domain %s" msgstr "" #: ipalib/plugins/realmdomains.py:190 msgid "Display the list of realm domains." msgstr "" #: ipalib/plugins/role.py:26 msgid "" "\n" "Roles\n" "\n" "A role is used for fine-grained delegation. A permission grants the ability\n" "to perform given low-level tasks (add a user, modify a group, etc.). A\n" "privilege combines one or more permissions into a higher-level abstraction\n" "such as useradmin. A useradmin would be able to add, delete and modify " "users.\n" "\n" "Privileges are assigned to Roles.\n" "\n" "Users, groups, hosts and hostgroups may be members of a Role.\n" "\n" "Roles can not contain other roles.\n" "\n" "EXAMPLES:\n" "\n" " Add a new role:\n" " ipa role-add --desc=\"Junior-level admin\" junioradmin\n" "\n" " Add some privileges to this role:\n" " ipa role-add-privilege --privileges=addusers junioradmin\n" " ipa role-add-privilege --privileges=change_password junioradmin\n" " ipa role-add-privilege --privileges=add_user_to_default_group " "junioradmin\n" "\n" " Add a group of users to this role:\n" " ipa group-add --desc=\"User admins\" useradmins\n" " ipa role-add-member --groups=useradmins junioradmin\n" "\n" " Display information about a role:\n" " ipa role-show junioradmin\n" "\n" " The result of this is that any users in the group 'junioradmin' can\n" " add users, reset passwords or add a user to the default IPA user group.\n" msgstr "" #: ipalib/plugins/role.py:66 msgid "role" msgstr "" #: ipalib/plugins/role.py:67 msgid "roles" msgstr "" #: ipalib/plugins/role.py:82 msgid "Role" msgstr "" #: ipalib/plugins/role.py:87 msgid "Role name" msgstr "" #: ipalib/plugins/role.py:93 msgid "A description of this role-group" msgstr "" #: ipalib/plugins/role.py:101 msgid "Add a new role." msgstr "" #: ipalib/plugins/role.py:103 #, python-format msgid "Added role \"%(value)s\"" msgstr "" #: ipalib/plugins/role.py:109 msgid "Delete a role." msgstr "" #: ipalib/plugins/role.py:111 #, python-format msgid "Deleted role \"%(value)s\"" msgstr "" #: ipalib/plugins/role.py:117 msgid "Modify a role." msgstr "" #: ipalib/plugins/role.py:119 #, python-format msgid "Modified role \"%(value)s\"" msgstr "" #: ipalib/plugins/role.py:125 msgid "Search for roles." msgstr "" #: ipalib/plugins/role.py:128 #, python-format msgid "%(count)d role matched" msgid_plural "%(count)d roles matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/role.py:135 msgid "Display information about a role." msgstr "" #: ipalib/plugins/role.py:141 msgid "Add members to a role." msgstr "" #: ipalib/plugins/role.py:147 msgid "Remove members from a role." msgstr "" #: ipalib/plugins/role.py:153 msgid "Add privileges to a role." msgstr "" #: ipalib/plugins/role.py:168 msgid "Number of privileges added" msgstr "" #: ipalib/plugins/role.py:176 msgid "Remove privileges from a role." msgstr "" #: ipalib/plugins/role.py:191 msgid "Number of privileges removed" msgstr "" #: ipalib/plugins/selfservice.py:28 msgid "" "\n" "Self-service Permissions\n" "\n" "A permission enables fine-grained delegation of permissions. Access Control\n" "Rules, or instructions (ACIs), grant permission to permissions to perform\n" "given tasks such as adding a user, modifying a group, etc.\n" "\n" "A Self-service permission defines what an object can change in its own " "entry.\n" "\n" "\n" "EXAMPLES:\n" "\n" " Add a self-service rule to allow users to manage their address (using Bash\n" " brace expansion):\n" " ipa selfservice-add --permissions=write --attrs={street,postalCode,l,c," "st} \"Users manage their own address\"\n" "\n" " When managing the list of attributes you need to include all attributes\n" " in the list, including existing ones.\n" " Add telephoneNumber to the list (using Bash brace expansion):\n" " ipa selfservice-mod --attrs={street,postalCode,l,c,st,telephoneNumber} " "\"Users manage their own address\"\n" "\n" " Display our updated rule:\n" " ipa selfservice-show \"Users manage their own address\"\n" "\n" " Delete a rule:\n" " ipa selfservice-del \"Users manage their own address\"\n" msgstr "" #: ipalib/plugins/selfservice.py:71 msgid "self service permission" msgstr "" #: ipalib/plugins/selfservice.py:72 msgid "self service permissions" msgstr "" #: ipalib/plugins/selfservice.py:73 msgid "Self Service Permissions" msgstr "" #: ipalib/plugins/selfservice.py:74 msgid "Self Service Permission" msgstr "" #: ipalib/plugins/selfservice.py:79 ipalib/plugins/selfservice.py:80 msgid "Self-service name" msgstr "" #: ipalib/plugins/selfservice.py:94 msgid "Attributes to which the permission applies." msgstr "" #: ipalib/plugins/selfservice.py:123 msgid "Add a new self-service permission." msgstr "" #: ipalib/plugins/selfservice.py:125 #, python-format msgid "Added selfservice \"%(value)s\"" msgstr "" #: ipalib/plugins/selfservice.py:145 msgid "Delete a self-service permission." msgstr "" #: ipalib/plugins/selfservice.py:148 #, python-format msgid "Deleted selfservice \"%(value)s\"" msgstr "" #: ipalib/plugins/selfservice.py:163 msgid "Modify a self-service permission." msgstr "" #: ipalib/plugins/selfservice.py:165 #, python-format msgid "Modified selfservice \"%(value)s\"" msgstr "" #: ipalib/plugins/selfservice.py:185 msgid "Search for a self-service permission." msgstr "" #: ipalib/plugins/selfservice.py:188 #, python-format msgid "%(count)d selfservice matched" msgid_plural "%(count)d selfservices matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/selfservice.py:212 msgid "Display information about a self-service permission." msgstr "" #: ipalib/plugins/selinuxusermap.py:26 msgid "" "\n" "SELinux User Mapping\n" "\n" "Map IPA users to SELinux users by host.\n" "\n" "Hosts, hostgroups, users and groups can be either defined within\n" "the rule or it may point to an existing HBAC rule. When using\n" "--hbacrule option to selinuxusermap-find an exact match is made on the\n" "HBAC rule name, so only one or zero entries will be returned.\n" "\n" "EXAMPLES:\n" "\n" " Create a rule, \"test1\", that sets all users to xguest_u:s0 on the host " "\"server\":\n" " ipa selinuxusermap-add --usercat=all --selinuxuser=xguest_u:s0 test1\n" " ipa selinuxusermap-add-host --hosts=server.example.com test1\n" "\n" " Create a rule, \"test2\", that sets all users to guest_u:s0 and uses an " "existing HBAC rule for users and hosts:\n" " ipa selinuxusermap-add --usercat=all --hbacrule=webserver --" "selinuxuser=guest_u:s0 test2\n" "\n" " Display the properties of a rule:\n" " ipa selinuxusermap-show test2\n" "\n" " Create a rule for a specific user. This sets the SELinux context for\n" " user john to unconfined_u:s0-s0:c0.c1023 on any machine:\n" " ipa selinuxusermap-add --hostcat=all --selinuxuser=unconfined_u:s0-s0:c0." "c1023 john_unconfined\n" " ipa selinuxusermap-add-user --users=john john_unconfined\n" "\n" " Disable a rule:\n" " ipa selinuxusermap-disable test1\n" "\n" " Enable a rule:\n" " ipa selinuxusermap-enable test1\n" "\n" " Find a rule referencing a specific HBAC rule:\n" " ipa selinuxusermap-find --hbacrule=allow_some\n" "\n" " Remove a rule:\n" " ipa selinuxusermap-del john_unconfined\n" "\n" "SEEALSO:\n" "\n" " The list controlling the order in which the SELinux user map is applied\n" " and the default SELinux user are available in the config-show command.\n" msgstr "" #: ipalib/plugins/selinuxusermap.py:71 msgid "HBAC rule and local members cannot both be set" msgstr "" #: ipalib/plugins/selinuxusermap.py:98 msgid "Invalid SELinux user name, only a-Z and _ are allowed" msgstr "" #: ipalib/plugins/selinuxusermap.py:100 msgid "Invalid MLS value, must match s[0-15](-s[0-15])" msgstr "" #: ipalib/plugins/selinuxusermap.py:103 msgid "" "Invalid MCS value, must match c[0-1023].c[0-1023] and/or c[0-1023]-c[0-c0123]" msgstr "" #: ipalib/plugins/selinuxusermap.py:118 msgid "SELinux user map list not found in configuration" msgstr "" #: ipalib/plugins/selinuxusermap.py:123 #, python-format msgid "SELinux user %(user)s not found in ordering list (in config)" msgstr "" #: ipalib/plugins/selinuxusermap.py:134 msgid "SELinux User Map rule" msgstr "" #: ipalib/plugins/selinuxusermap.py:135 msgid "SELinux User Map rules" msgstr "" #: ipalib/plugins/selinuxusermap.py:152 msgid "SELinux User Maps" msgstr "" #: ipalib/plugins/selinuxusermap.py:153 msgid "SELinux User Map" msgstr "" #: ipalib/plugins/selinuxusermap.py:163 msgid "SELinux User" msgstr "" #: ipalib/plugins/selinuxusermap.py:168 msgid "HBAC Rule that defines the users, groups and hostgroups" msgstr "" #: ipalib/plugins/selinuxusermap.py:228 #, python-format msgid "HBAC rule %(rule)s not found" msgstr "" #: ipalib/plugins/selinuxusermap.py:247 msgid "Create a new SELinux User Map." msgstr "" #: ipalib/plugins/selinuxusermap.py:249 #, python-format msgid "Added SELinux User Map \"%(value)s\"" msgstr "" #: ipalib/plugins/selinuxusermap.py:284 msgid "Delete a SELinux User Map." msgstr "" #: ipalib/plugins/selinuxusermap.py:286 #, python-format msgid "Deleted SELinux User Map \"%(value)s\"" msgstr "" #: ipalib/plugins/selinuxusermap.py:292 msgid "Modify a SELinux User Map." msgstr "" #: ipalib/plugins/selinuxusermap.py:294 #, python-format msgid "Modified SELinux User Map \"%(value)s\"" msgstr "" #: ipalib/plugins/selinuxusermap.py:348 msgid "Search for SELinux User Maps." msgstr "" #: ipalib/plugins/selinuxusermap.py:351 #, python-format msgid "%(count)d SELinux User Map matched" msgid_plural "%(count)d SELinux User Maps matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/selinuxusermap.py:381 msgid "Display the properties of a SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:392 msgid "Enable an SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:394 #, python-format msgid "Enabled SELinux User Map \"%(value)s\"" msgstr "" #: ipalib/plugins/selinuxusermap.py:419 msgid "Disable an SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:421 #, python-format msgid "Disabled SELinux User Map \"%(value)s\"" msgstr "" #: ipalib/plugins/selinuxusermap.py:446 msgid "Add users and groups to an SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:469 msgid "Remove users and groups from an SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:478 msgid "Add target hosts and hostgroups to an SELinux User Map rule." msgstr "" #: ipalib/plugins/selinuxusermap.py:501 msgid "Remove target hosts and hostgroups from an SELinux User Map rule." msgstr "" #: ipalib/plugins/service.py:35 msgid "" "\n" "Services\n" "\n" "A IPA service represents a service that runs on a host. The IPA service\n" "record can store a Kerberos principal, an SSL certificate, or both.\n" "\n" "An IPA service can be managed directly from a machine, provided that\n" "machine has been given the correct permission. This is true even for\n" "machines other than the one the service is associated with. For example,\n" "requesting an SSL certificate using the host service principal credentials\n" "of the host. To manage a service using host credentials you need to\n" "kinit as the host:\n" "\n" " # kinit -kt /etc/krb5.keytab host/ipa.example.com@EXAMPLE.COM\n" "\n" "Adding an IPA service allows the associated service to request an SSL\n" "certificate or keytab, but this is performed as a separate step; they\n" "are not produced as a result of adding the service.\n" "\n" "Only the public aspect of a certificate is stored in a service record;\n" "the private key is not stored.\n" "\n" "EXAMPLES:\n" "\n" " Add a new IPA service:\n" " ipa service-add HTTP/web.example.com\n" "\n" " Allow a host to manage an IPA service certificate:\n" " ipa service-add-host --hosts=web.example.com HTTP/web.example.com\n" " ipa role-add-member --hosts=web.example.com certadmin\n" "\n" " Override a default list of supported PAC types for the service:\n" " ipa service-mod HTTP/web.example.com --pac-type=MS-PAC\n" "\n" " A typical use case where overriding the PAC type is needed is NFS.\n" " Currently the related code in the Linux kernel can only handle Kerberos\n" " tickets up to a maximal size. Since the PAC data can become quite large " "it\n" " is recommended to set --pac-type=NONE for NFS services.\n" "\n" " Delete an IPA service:\n" " ipa service-del HTTP/web.example.com\n" "\n" " Find all IPA services associated with a host:\n" " ipa service-find web.example.com\n" "\n" " Find all HTTP services:\n" " ipa service-find HTTP\n" "\n" " Disable the service Kerberos key and SSL certificate:\n" " ipa service-disable HTTP/web.example.com\n" "\n" " Request a certificate for an IPA service:\n" " ipa cert-request --principal=HTTP/web.example.com example.csr\n" "\n" " Generate and retrieve a keytab for an IPA service:\n" " ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/" "httpd.keytab\n" "\n" msgstr "" #: ipalib/plugins/service.py:133 msgid "Requires pre-authentication" msgstr "" #: ipalib/plugins/service.py:134 msgid "Pre-authentication is required for the service" msgstr "" #: ipalib/plugins/service.py:139 msgid "Trusted for delegation" msgstr "" #: ipalib/plugins/service.py:140 msgid "Client credentials may be delegated to the service" msgstr "" #: ipalib/plugins/service.py:159 msgid "missing service" msgstr "" #: ipalib/plugins/service.py:163 msgid "blank service" msgstr "" #: ipalib/plugins/service.py:167 msgid "unable to determine realm" msgstr "" #: ipalib/plugins/service.py:240 msgid "This principal is required by the IPA master" msgstr "" #: ipalib/plugins/service.py:295 msgid "service" msgstr "" #: ipalib/plugins/service.py:296 msgid "services" msgstr "" #: ipalib/plugins/service.py:322 msgid "Service principal" msgstr "" #: ipalib/plugins/service.py:334 msgid "PAC type" msgstr "" #: ipalib/plugins/service.py:335 msgid "" "Override default list of supported PAC types. Use 'NONE' to disable PAC " "support for this service, e.g. this might be necessary for NFS services." msgstr "" #: ipalib/plugins/service.py:356 msgid "NONE value cannot be combined with other PAC types" msgstr "" #: ipalib/plugins/service.py:362 msgid "Add a new IPA new service." msgstr "" #: ipalib/plugins/service.py:364 #, python-format msgid "Added service \"%(value)s\"" msgstr "" #: ipalib/plugins/service.py:370 msgid "force principal name even if not in DNS" msgstr "" #: ipalib/plugins/service.py:384 #, python-format msgid "The host '%s' does not exist to add a service to." msgstr "" #: ipalib/plugins/service.py:424 msgid "Delete an IPA service." msgstr "" #: ipalib/plugins/service.py:426 #, python-format msgid "Deleted service \"%(value)s\"" msgstr "" #: ipalib/plugins/service.py:469 msgid "Modify an existing IPA service." msgstr "" #: ipalib/plugins/service.py:471 #, python-format msgid "Modified service \"%(value)s\"" msgstr "" #: ipalib/plugins/service.py:517 msgid "Search for IPA services." msgstr "" #: ipalib/plugins/service.py:520 #, python-format msgid "%(count)d service matched" msgid_plural "%(count)d services matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/service.py:555 msgid "Display information about an IPA service." msgstr "" #: ipalib/plugins/service.py:590 msgid "Add hosts that can manage this service." msgstr "" #: ipalib/plugins/service.py:599 msgid "Remove hosts that can manage this service." msgstr "" #: ipalib/plugins/service.py:608 msgid "Disable the Kerberos key and SSL certificate of a service." msgstr "" #: ipalib/plugins/service.py:611 #, python-format msgid "Disabled service \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmd.py:29 msgid "" "\n" "Sudo Commands\n" "\n" "Commands used as building blocks for sudo\n" "\n" "EXAMPLES:\n" "\n" " Create a new command\n" " ipa sudocmd-add --desc='For reading log files' /usr/bin/less\n" "\n" " Remove a command\n" " ipa sudocmd-del /usr/bin/less\n" "\n" msgstr "" #: ipalib/plugins/sudocmd.py:44 ipalib/plugins/sudocmdgroup.py:48 msgid "commands for controlling sudo configuration" msgstr "" #: ipalib/plugins/sudocmd.py:51 msgid "sudo command" msgstr "" #: ipalib/plugins/sudocmd.py:52 msgid "sudo commands" msgstr "" #: ipalib/plugins/sudocmd.py:66 msgid "Sudo Commands" msgstr "" #: ipalib/plugins/sudocmd.py:67 ipalib/plugins/sudocmd.py:72 msgid "Sudo Command" msgstr "" #: ipalib/plugins/sudocmd.py:78 msgid "A description of this command" msgstr "" #: ipalib/plugins/sudocmd.py:101 msgid "Create new Sudo Command." msgstr "" #: ipalib/plugins/sudocmd.py:103 #, python-format msgid "Added Sudo Command \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmd.py:108 msgid "Delete Sudo Command." msgstr "" #: ipalib/plugins/sudocmd.py:110 #, python-format msgid "Deleted Sudo Command \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmd.py:141 msgid "Modify Sudo Command." msgstr "" #: ipalib/plugins/sudocmd.py:143 #, python-format msgid "Modified Sudo Command \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmd.py:148 msgid "Search for Sudo Commands." msgstr "" #: ipalib/plugins/sudocmd.py:151 #, python-format msgid "%(count)d Sudo Command matched" msgid_plural "%(count)d Sudo Commands matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/sudocmd.py:157 msgid "Display Sudo Command." msgstr "" #: ipalib/plugins/sudocmdgroup.py:25 msgid "" "\n" "Groups of Sudo Commands\n" "\n" "Manage groups of Sudo Commands.\n" "\n" "EXAMPLES:\n" "\n" " Add a new Sudo Command Group:\n" " ipa sudocmdgroup-add --desc='administrators commands' admincmds\n" "\n" " Remove a Sudo Command Group:\n" " ipa sudocmdgroup-del admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa sudocmdgroup-add-member --sudocmds=/usr/bin/less --sudocmds=/usr/bin/" "vim admincmds\n" "\n" " Manage Sudo Command Group membership, commands:\n" " ipa group-remove-member --sudocmds=/usr/bin/less admincmds\n" "\n" " Show a Sudo Command Group:\n" " ipa group-show localadmins\n" msgstr "" #: ipalib/plugins/sudocmdgroup.py:55 msgid "sudo command group" msgstr "" #: ipalib/plugins/sudocmdgroup.py:56 msgid "sudo command groups" msgstr "" #: ipalib/plugins/sudocmdgroup.py:67 ipalib/plugins/sudocmdgroup.py:72 msgid "Sudo Command Group" msgstr "" #: ipalib/plugins/sudocmdgroup.py:95 msgid "Create new Sudo Command Group." msgstr "" #: ipalib/plugins/sudocmdgroup.py:97 #, python-format msgid "Added Sudo Command Group \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmdgroup.py:103 msgid "Delete Sudo Command Group." msgstr "" #: ipalib/plugins/sudocmdgroup.py:105 #, python-format msgid "Deleted Sudo Command Group \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmdgroup.py:111 msgid "Modify Sudo Command Group." msgstr "" #: ipalib/plugins/sudocmdgroup.py:113 #, python-format msgid "Modified Sudo Command Group \"%(value)s\"" msgstr "" #: ipalib/plugins/sudocmdgroup.py:119 msgid "Search for Sudo Command Groups." msgstr "" #: ipalib/plugins/sudocmdgroup.py:122 #, python-format msgid "%(count)d Sudo Command Group matched" msgid_plural "%(count)d Sudo Command Groups matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/sudocmdgroup.py:130 msgid "Display Sudo Command Group." msgstr "" #: ipalib/plugins/sudocmdgroup.py:136 msgid "Add members to Sudo Command Group." msgstr "" #: ipalib/plugins/sudocmdgroup.py:142 msgid "Remove members from Sudo Command Group." msgstr "" #: ipalib/plugins/sudorule.py:26 msgid "" "\n" "Sudo Rules\n" "\n" "Sudo (su \"do\") allows a system administrator to delegate authority to\n" "give certain users (or groups of users) the ability to run some (or all)\n" "commands as root or another user while providing an audit trail of the\n" "commands and their arguments.\n" "\n" "FreeIPA provides a means to configure the various aspects of Sudo:\n" " Users: The user(s)/group(s) allowed to invoke Sudo.\n" " Hosts: The host(s)/hostgroup(s) which the user is allowed to to invoke " "Sudo.\n" " Allow Command: The specific command(s) permitted to be run via Sudo.\n" " Deny Command: The specific command(s) prohibited to be run via Sudo.\n" " RunAsUser: The user(s) or group(s) of users whose rights Sudo will be " "invoked with.\n" " RunAsGroup: The group(s) whose gid rights Sudo will be invoked with.\n" " Options: The various Sudoers Options that can modify Sudo's behavior.\n" "\n" "An order can be added to a sudorule to control the order in which they\n" "are evaluated (if the client supports it). This order is an integer and\n" "must be unique.\n" "\n" "FreeIPA provides a designated binddn to use with Sudo located at:\n" "uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com\n" "\n" "To enable the binddn run the following command to set the password:\n" "LDAPTLS_CACERT=/etc/ipa/ca.crt /usr/bin/ldappasswd -S -W -h ipa.example.com -" "ZZ -D \"cn=Directory Manager\" uid=sudo,cn=sysaccounts,cn=etc,dc=example," "dc=com\n" "\n" "For more information, see the FreeIPA Documentation to Sudo.\n" msgstr "" #: ipalib/plugins/sudorule.py:58 msgid "Commands for controlling sudo configuration" msgstr "" #: ipalib/plugins/sudorule.py:61 msgid "this option has been deprecated." msgstr "" #: ipalib/plugins/sudorule.py:77 msgid "sudo rule" msgstr "" #: ipalib/plugins/sudorule.py:78 msgid "sudo rules" msgstr "" #: ipalib/plugins/sudorule.py:100 msgid "Sudo Rules" msgstr "" #: ipalib/plugins/sudorule.py:101 msgid "Sudo Rule" msgstr "" #: ipalib/plugins/sudorule.py:131 msgid "Command category" msgstr "" #: ipalib/plugins/sudorule.py:132 msgid "Command category the rule applies to" msgstr "" #: ipalib/plugins/sudorule.py:137 msgid "RunAs User category" msgstr "" #: ipalib/plugins/sudorule.py:138 msgid "RunAs User category the rule applies to" msgstr "" #: ipalib/plugins/sudorule.py:143 msgid "RunAs Group category" msgstr "" #: ipalib/plugins/sudorule.py:144 msgid "RunAs Group category the rule applies to" msgstr "" #: ipalib/plugins/sudorule.py:149 msgid "Sudo order" msgstr "" #: ipalib/plugins/sudorule.py:150 msgid "integer to order the Sudo rules" msgstr "" #: ipalib/plugins/sudorule.py:171 msgid "Sudo Allow Commands" msgstr "" #: ipalib/plugins/sudorule.py:175 msgid "Sudo Deny Commands" msgstr "" #: ipalib/plugins/sudorule.py:179 msgid "Sudo Allow Command Groups" msgstr "" #: ipalib/plugins/sudorule.py:183 msgid "Sudo Deny Command Groups" msgstr "" #: ipalib/plugins/sudorule.py:187 msgid "RunAs Users" msgstr "" #: ipalib/plugins/sudorule.py:188 msgid "Run as a user" msgstr "" #: ipalib/plugins/sudorule.py:192 msgid "Groups of RunAs Users" msgstr "" #: ipalib/plugins/sudorule.py:193 msgid "Run as any user within a specified group" msgstr "" #: ipalib/plugins/sudorule.py:198 msgid "External User" msgstr "" #: ipalib/plugins/sudorule.py:199 msgid "External User the rule applies to (sudorule-find only)" msgstr "" #: ipalib/plugins/sudorule.py:203 msgid "RunAs External User" msgstr "" #: ipalib/plugins/sudorule.py:204 msgid "External User the commands can run as (sudorule-find only)" msgstr "" #: ipalib/plugins/sudorule.py:208 msgid "RunAs External Group" msgstr "" #: ipalib/plugins/sudorule.py:209 msgid "External Group the commands can run as (sudorule-find only)" msgstr "" #: ipalib/plugins/sudorule.py:212 ipalib/plugins/sudorule.py:612 #: ipalib/plugins/sudorule.py:665 msgid "Sudo Option" msgstr "" #: ipalib/plugins/sudorule.py:216 msgid "RunAs Groups" msgstr "" #: ipalib/plugins/sudorule.py:217 msgid "Run with the gid of a specified POSIX group" msgstr "" #: ipalib/plugins/sudorule.py:224 #, python-format msgid "order must be a unique value (%(order)d already used by %(rule)s)" msgstr "" #: ipalib/plugins/sudorule.py:246 msgid "Create new Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:255 #, python-format msgid "Added Sudo Rule \"%(value)s\"" msgstr "" #: ipalib/plugins/sudorule.py:261 msgid "Delete Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:263 #, python-format msgid "Deleted Sudo Rule \"%(value)s\"" msgstr "" #: ipalib/plugins/sudorule.py:269 msgid "Modify Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:271 #, python-format msgid "Modified Sudo Rule \"%(value)s\"" msgstr "" #: ipalib/plugins/sudorule.py:294 msgid "" "command category cannot be set to 'all' while there are allow or deny " "commands" msgstr "" #: ipalib/plugins/sudorule.py:296 msgid "user runAs category cannot be set to 'all' while there are users" msgstr "" #: ipalib/plugins/sudorule.py:298 msgid "group runAs category cannot be set to 'all' while there are groups" msgstr "" #: ipalib/plugins/sudorule.py:306 msgid "Search for Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:309 #, python-format msgid "%(count)d Sudo Rule matched" msgid_plural "%(count)d Sudo Rules matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/sudorule.py:316 msgid "Display Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:322 msgid "Enable a Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:340 #, python-format msgid "Enabled Sudo Rule \"%s\"" msgstr "" #: ipalib/plugins/sudorule.py:346 msgid "Disable a Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:364 #, python-format msgid "Disabled Sudo Rule \"%s\"" msgstr "" #: ipalib/plugins/sudorule.py:370 ipalib/plugins/sudorule.py:399 msgid "Add commands and sudo command groups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:382 ipalib/plugins/sudorule.py:411 msgid "commands cannot be added when command category='all'" msgstr "" #: ipalib/plugins/sudorule.py:390 ipalib/plugins/sudorule.py:418 msgid "Remove commands and sudo command groups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:427 msgid "Add users and groups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:450 msgid "Remove users and groups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:463 msgid "Add hosts and hostgroups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:486 msgid "Remove hosts and hostgroups affected by Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:498 msgid "Add users and groups for Sudo to execute as." msgstr "" #: ipalib/plugins/sudorule.py:517 ipalib/plugins/sudorule.py:574 msgid "users cannot be added when runAs user or runAs group category='all'" msgstr "" #: ipalib/plugins/sudorule.py:523 #, python-format msgid "RunAsUser does not accept '%(name)s' as a user name" msgstr "" #: ipalib/plugins/sudorule.py:529 #, python-format msgid "RunAsUser does not accept '%(name)s' as a group name" msgstr "" #: ipalib/plugins/sudorule.py:542 msgid "Remove users and groups for Sudo to execute as." msgstr "" #: ipalib/plugins/sudorule.py:555 msgid "Add group for Sudo to execute as." msgstr "" #: ipalib/plugins/sudorule.py:580 #, python-format msgid "RunAsGroup does not accept '%(name)s' as a group name" msgstr "" #: ipalib/plugins/sudorule.py:593 msgid "Remove group for Sudo to execute as." msgstr "" #: ipalib/plugins/sudorule.py:606 msgid "Add an option to the Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:649 #, python-format msgid "Added option \"%(option)s\" to Sudo Rule \"%(rule)s\"" msgstr "" #: ipalib/plugins/sudorule.py:659 msgid "Remove an option from Sudo Rule." msgstr "" #: ipalib/plugins/sudorule.py:705 #, python-format msgid "Removed option \"%(option)s\" from Sudo Rule \"%(rule)s\"" msgstr "" #: ipalib/plugins/trust.py:49 msgid "" "\n" "Cross-realm trusts\n" "\n" "Manage trust relationship between IPA and Active Directory domains.\n" "\n" "In order to allow users from a remote domain to access resources in IPA\n" "domain, trust relationship needs to be established. Currently IPA supports\n" "only trusts between IPA and Active Directory domains under control of " "Windows\n" "Server 2008 or later, with functional level 2008 or later.\n" "\n" "Please note that DNS on both IPA and Active Directory domain sides should " "be\n" "configured properly to discover each other. Trust relationship relies on\n" "ability to discover special resources in the other domain via DNS records.\n" "\n" "Examples:\n" "\n" "1. Establish cross-realm trust with Active Directory using AD administrator\n" " credentials:\n" "\n" " ipa trust-add --type=ad --admin --" "password\n" "\n" "2. List all existing trust relationships:\n" "\n" " ipa trust-find\n" "\n" "3. Show details of the specific trust relationship:\n" "\n" " ipa trust-show \n" "\n" "4. Delete existing trust relationship:\n" "\n" " ipa trust-del \n" "\n" "Once trust relationship is established, remote users will need to be mapped\n" "to local POSIX groups in order to actually use IPA resources. The mapping " "should\n" "be done via use of external membership of non-POSIX group and then this " "group\n" "should be included into one of local POSIX groups.\n" "\n" "Example:\n" "\n" "1. Create group for the trusted domain admins' mapping and their local POSIX " "group:\n" "\n" " ipa group-add --desc=' admins external map' ad_admins_external " "--external\n" " ipa group-add --desc=' admins' ad_admins\n" "\n" "2. Add security identifier of Domain Admins of the to the " "ad_admins_external\n" " group:\n" "\n" " ipa group-add-member ad_admins_external --external 'AD\\Domain Admins'\n" "\n" "3. Allow members of ad_admins_external group to be associated with ad_admins " "POSIX group:\n" "\n" " ipa group-add-member ad_admins --groups ad_admins_external\n" "\n" "4. List members of external members of ad_admins_external group to see their " "SIDs:\n" "\n" " ipa group-show ad_admins_external\n" "\n" "\n" "GLOBAL TRUST CONFIGURATION\n" "\n" "When IPA AD trust subpackage is installed and ipa-adtrust-install is run,\n" "a local domain configuration (SID, GUID, NetBIOS name) is generated. These\n" "identifiers are then used when communicating with a trusted domain of the\n" "particular type.\n" "\n" "1. Show global trust configuration for Active Directory type of trusts:\n" "\n" " ipa trustconfig-show --type ad\n" "\n" "2. Modify global configuration for all trusts of Active Directory type and " "set\n" " a different fallback primary group (fallback primary group GID is used " "as\n" " a primary user GID if user authenticating to IPA domain does not have any " "other\n" " primary GID already set):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"alternative AD " "group\"\n" "\n" "3. Change primary fallback group back to default hidden group (any group " "with\n" " posixGroup object class is allowed):\n" "\n" " ipa trustconfig-mod --type ad --fallback-primary-group \"Default SMB Group" "\"\n" msgstr "" #: ipalib/plugins/trust.py:141 msgid "Non-Active Directory domain" msgstr "" #: ipalib/plugins/trust.py:143 msgid "RFC4120-compliant Kerberos realm" msgstr "" #: ipalib/plugins/trust.py:144 msgid "Trusting forest" msgstr "" #: ipalib/plugins/trust.py:145 msgid "Trusted forest" msgstr "" #: ipalib/plugins/trust.py:146 msgid "Two-way trust" msgstr "" #: ipalib/plugins/trust.py:147 msgid "Established and verified" msgstr "" #: ipalib/plugins/trust.py:148 msgid "Waiting for confirmation by remote side" msgstr "" #: ipalib/plugins/trust.py:149 msgid "Unknown" msgstr "" #: ipalib/plugins/trust.py:153 msgid "Trust type (ad for Active Directory, default)" msgstr "" #: ipalib/plugins/trust.py:190 msgid "trust" msgstr "" #: ipalib/plugins/trust.py:191 msgid "trusts" msgstr "" #: ipalib/plugins/trust.py:201 msgid "Trust" msgstr "" #: ipalib/plugins/trust.py:206 ipa-client/ipa-rmkeytab.c:176 msgid "Realm name" msgstr "" #: ipalib/plugins/trust.py:220 msgid "SID blacklist incoming" msgstr "" #: ipalib/plugins/trust.py:225 msgid "SID blacklist outgoing" msgstr "" #: ipalib/plugins/trust.py:242 #, python-format msgid "invalid SID: %(value)s" msgstr "" #: ipalib/plugins/trust.py:252 msgid "" "\n" "Add new trust to use.\n" "\n" "This command establishes trust relationship to another domain\n" "which becomes 'trusted'. As result, users of the trusted domain\n" "may access resources of this domain.\n" "\n" "Only trusts to Active Directory domains are supported right now.\n" "\n" "The command can be safely run multiple times against the same domain,\n" "this will cause change to trust relationship credentials on both\n" "sides.\n" " " msgstr "" #: ipalib/plugins/trust.py:276 msgid "Active Directory domain administrator" msgstr "" #: ipalib/plugins/trust.py:280 msgid "Active directory domain administrator's password" msgstr "" #: ipalib/plugins/trust.py:285 msgid "Domain controller for the Active Directory domain (optional)" msgstr "" #: ipalib/plugins/trust.py:289 msgid "Shared secret for the trust" msgstr "" #: ipalib/plugins/trust.py:294 msgid "First Posix ID of the range reserved for the trusted domain" msgstr "" #: ipalib/plugins/trust.py:298 msgid "Size of the ID range reserved for the trusted domain" msgstr "" #: ipalib/plugins/trust.py:303 msgid "Type of trusted domain ID range, one of {vals}" msgstr "" #: ipalib/plugins/trust.py:309 #, python-format msgid "Added Active Directory trust for realm \"%(value)s\"" msgstr "" #: ipalib/plugins/trust.py:337 ipalib/plugins/trust.py:366 #: ipalib/plugins/trust.py:386 ipalib/plugins/trust.py:396 #: ipalib/plugins/trust.py:621 ipalib/plugins/trust.py:647 msgid "AD Trust setup" msgstr "" #: ipalib/plugins/trust.py:339 msgid "" "Cannot perform join operation without Samba 4 support installed. Make sure " "you have installed server-trust-ad sub-package of IPA" msgstr "" #: ipalib/plugins/trust.py:347 msgid "missing base_id" msgstr "" #: ipalib/plugins/trust.py:349 msgid "pysss_murmur is not available on the server and no base-id is given." msgstr "" #: ipalib/plugins/trust.py:355 ipalib/plugins/trust.py:359 msgid "trust type" msgstr "" #: ipalib/plugins/trust.py:360 msgid "only \"ad\" is supported" msgstr "" #: ipalib/plugins/trust.py:388 msgid "Trusted domain and administrator account use different realms" msgstr "" #: ipalib/plugins/trust.py:397 msgid "Realm administrator password should be specified" msgstr "" #: ipalib/plugins/trust.py:418 msgid "id range type" msgstr "" #: ipalib/plugins/trust.py:420 msgid "" "Only the ipa-ad-trust and ipa-ad-trust-posix are allowed values for --range-" "type when adding an AD trust." msgstr "" #: ipalib/plugins/trust.py:430 msgid "id range" msgstr "" #: ipalib/plugins/trust.py:432 msgid "" "An id range already exists for this trust. You should either delete the old " "range, or exclude --base-id/--range-size options from the command." msgstr "" #: ipalib/plugins/trust.py:454 msgid "range exists" msgstr "" #: ipalib/plugins/trust.py:456 msgid "" "ID range with the same name but different domain SID already exists. The ID " "range for the new trusted domain must be created manually." msgstr "" #: ipalib/plugins/trust.py:463 msgid "range type change" msgstr "" #: ipalib/plugins/trust.py:464 msgid "" "ID range for the trusted domain already exists, but it has a different type. " "Please remove the old range manually, or do not enforce type via --range-" "type option." msgstr "" #: ipalib/plugins/trust.py:581 #, python-format msgid "Re-established trust to domain \"%(value)s\"" msgstr "" #: ipalib/plugins/trust.py:596 #, python-format msgid "Unable to resolve domain controller for '%s' domain. " msgstr "" #: ipalib/plugins/trust.py:602 msgid "" "Forward policy is defined for it in IPA DNS, perhaps forwarder points to " "incorrect host?" msgstr "" #: ipalib/plugins/trust.py:605 #, python-format msgid "" "IPA manages DNS, please verify your DNS configuration and make sure that " "service records of the '%(domain)s' domain can be resolved. Examples how to " "configure DNS with CLI commands or the Web UI can be found in the " "documentation. " msgstr "" #: ipalib/plugins/trust.py:615 #, python-format msgid "" "Since IPA does not manage DNS records, ensure DNS is configured to resolve " "'%(domain)s' domain from IPA hosts and back." msgstr "" #: ipalib/plugins/trust.py:622 msgid "Unable to verify write permissions to the AD" msgstr "" #: ipalib/plugins/trust.py:648 msgid "Not enough arguments specified to perform trust setup" msgstr "" #: ipalib/plugins/trust.py:651 msgid "Delete a trust." msgstr "" #: ipalib/plugins/trust.py:653 #, python-format msgid "Deleted trust \"%(value)s\"" msgstr "" #: ipalib/plugins/trust.py:664 msgid "" "\n" " Modify a trust (for future use).\n" "\n" " Currently only the default option to modify the LDAP attributes is\n" " available. More specific options will be added in coming releases.\n" " " msgstr "" #: ipalib/plugins/trust.py:671 #, python-format msgid "Modified trust \"%(value)s\" (change will be effective in 60 seconds)" msgstr "" #: ipalib/plugins/trust.py:688 msgid "Search for trusts." msgstr "" #: ipalib/plugins/trust.py:693 #, python-format msgid "%(count)d trust matched" msgid_plural "%(count)d trusts matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/trust.py:717 msgid "Display information about a trust." msgstr "" #: ipalib/plugins/trust.py:778 msgid "trust configuration" msgstr "" #: ipalib/plugins/trust.py:784 ipalib/plugins/trust.py:785 msgid "Global Trust Configuration" msgstr "" #: ipalib/plugins/trust.py:793 msgid "Security Identifier" msgstr "" #: ipalib/plugins/trust.py:797 msgid "NetBIOS name" msgstr "" #: ipalib/plugins/trust.py:801 msgid "Domain GUID" msgstr "" #: ipalib/plugins/trust.py:806 msgid "Fallback primary group" msgstr "" #: ipalib/plugins/trust.py:818 msgid "unsupported trust type" msgstr "" #: ipalib/plugins/trust.py:881 msgid "Modify global trust configuration." msgstr "" #: ipalib/plugins/trust.py:884 #, python-format msgid "Modified \"%(value)s\" trust configuration" msgstr "" #: ipalib/plugins/trust.py:903 msgid "Show global trust configuration." msgstr "" #: ipalib/plugins/trust.py:929 msgid "Resolve security identifiers of users and groups in trusted domains" msgstr "" #: ipalib/plugins/trust.py:933 msgid "Security Identifiers (SIDs)" msgstr "" #: ipalib/plugins/trust.py:939 msgid "Name" msgstr "" #: ipalib/plugins/trust.py:940 msgid "SID" msgstr "" #: ipalib/plugins/trust.py:971 msgid "Determine whether ipa-adtrust-install has been run on this system" msgstr "" #: ipalib/plugins/trust.py:998 msgid "" "Determine whether Schema Compatibility plugin is configured to serve trusted " "domain users and groups" msgstr "" #: ipalib/plugins/trust.py:1051 msgid "Determine whether ipa-adtrust-install has been run with sidgen task" msgstr "" #: ipalib/plugins/trust.py:1067 msgid "sidgen_was_run" msgstr "" #: ipalib/plugins/trust.py:1069 msgid "" "This command relies on the existence of the \"editors\" group, but this " "group was not found." msgstr "" #: ipalib/plugins/user.py:41 msgid "" "\n" "Users\n" "\n" "Manage user entries. All users are POSIX users.\n" "\n" "IPA supports a wide range of username formats, but you need to be aware of " "any\n" "restrictions that may apply to your particular environment. For example,\n" "usernames that start with a digit or usernames that exceed a certain length\n" "may cause problems for some UNIX systems.\n" "Use 'ipa config-mod' to change the username format allowed by IPA tools.\n" "\n" "Disabling a user account prevents that user from obtaining new Kerberos\n" "credentials. It does not invalidate any credentials that have already\n" "been issued.\n" "\n" "Password management is not a part of this module. For more information\n" "about this topic please see: ipa help passwd\n" "\n" "Account lockout on password failure happens per IPA master. The user-status\n" "command can be used to identify which master the user is locked out on.\n" "It is on that master the administrator must unlock the user.\n" "\n" "EXAMPLES:\n" "\n" " Add a new user:\n" " ipa user-add --first=Tim --last=User --password tuser1\n" "\n" " Find all users whose entries include the string \"Tim\":\n" " ipa user-find Tim\n" "\n" " Find all users with \"Tim\" as the first name:\n" " ipa user-find --first=Tim\n" "\n" " Disable a user account:\n" " ipa user-disable tuser1\n" "\n" " Enable a user account:\n" " ipa user-enable tuser1\n" "\n" " Delete a user:\n" " ipa user-del tuser1\n" msgstr "" #: ipalib/plugins/user.py:89 msgid "Kerberos keys available" msgstr "" #: ipalib/plugins/user.py:98 msgid "Server" msgstr "" #: ipalib/plugins/user.py:101 msgid "Failed logins" msgstr "" #: ipalib/plugins/user.py:104 msgid "Last successful authentication" msgstr "" #: ipalib/plugins/user.py:107 msgid "Last failed authentication" msgstr "" #: ipalib/plugins/user.py:110 msgid "Time now" msgstr "" #: ipalib/plugins/user.py:125 msgid "must be TRUE or FALSE" msgstr "" #: ipalib/plugins/user.py:197 msgid "user" msgstr "" #: ipalib/plugins/user.py:198 msgid "users" msgstr "" #: ipalib/plugins/user.py:234 msgid "User login" msgstr "" #: ipalib/plugins/user.py:241 msgid "First name" msgstr "" #: ipalib/plugins/user.py:245 msgid "Last name" msgstr "" #: ipalib/plugins/user.py:248 msgid "Full name" msgstr "" #: ipalib/plugins/user.py:253 msgid "Display name" msgstr "" #: ipalib/plugins/user.py:258 msgid "Initials" msgstr "" #: ipalib/plugins/user.py:264 msgid "Home directory" msgstr "" #: ipalib/plugins/user.py:267 msgid "GECOS" msgstr "" #: ipalib/plugins/user.py:273 msgid "Login shell" msgstr "" #: ipalib/plugins/user.py:277 msgid "Kerberos principal" msgstr "" #: ipalib/plugins/user.py:285 msgid "Email address" msgstr "" #: ipalib/plugins/user.py:290 msgid "Prompt to set the user password" msgstr "" #: ipalib/plugins/user.py:296 msgid "Generate a random user password" msgstr "" #: ipalib/plugins/user.py:306 msgid "UID" msgstr "" #: ipalib/plugins/user.py:307 msgid "User ID Number (system will assign one if not provided)" msgstr "" #: ipalib/plugins/user.py:312 msgid "Group ID Number" msgstr "" #: ipalib/plugins/user.py:317 msgid "Street address" msgstr "" #: ipalib/plugins/user.py:321 msgid "City" msgstr "" #: ipalib/plugins/user.py:325 msgid "State/Province" msgstr "" #: ipalib/plugins/user.py:328 msgid "ZIP" msgstr "" #: ipalib/plugins/user.py:332 msgid "Telephone Number" msgstr "" #: ipalib/plugins/user.py:335 msgid "Mobile Telephone Number" msgstr "" #: ipalib/plugins/user.py:338 msgid "Pager Number" msgstr "" #: ipalib/plugins/user.py:342 msgid "Fax Number" msgstr "" #: ipalib/plugins/user.py:346 msgid "Org. Unit" msgstr "" #: ipalib/plugins/user.py:349 msgid "Job Title" msgstr "" #: ipalib/plugins/user.py:352 msgid "Manager" msgstr "" #: ipalib/plugins/user.py:355 msgid "Car License" msgstr "" #: ipalib/plugins/user.py:358 msgid "Account disabled" msgstr "" #: ipalib/plugins/user.py:385 ipalib/plugins/user.py:389 #, python-format msgid "invalid e-mail format: %(email)s" msgstr "" #: ipalib/plugins/user.py:415 #, python-format msgid "manager %(manager)s not found" msgstr "" #: ipalib/plugins/user.py:434 msgid "Add a new user." msgstr "" #: ipalib/plugins/user.py:436 #, python-format msgid "Added user \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:443 msgid "Don't create user private group" msgstr "" #: ipalib/plugins/user.py:487 ipalib/plugins/user.py:623 #, python-format msgid "can be at most %(len)d characters" msgstr "" #: ipalib/plugins/user.py:522 msgid "Default group for new users is not POSIX" msgstr "" #: ipalib/plugins/user.py:596 msgid "Delete a user." msgstr "" #: ipalib/plugins/user.py:598 #, python-format msgid "Deleted user \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:609 msgid "Modify a user." msgstr "" #: ipalib/plugins/user.py:611 #, python-format msgid "Modified user \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:664 msgid "Search for users." msgstr "" #: ipalib/plugins/user.py:671 msgid "Self" msgstr "" #: ipalib/plugins/user.py:672 msgid "Display user record for current Kerberos principal" msgstr "" #: ipalib/plugins/user.py:703 #, python-format msgid "%(count)d user matched" msgid_plural "%(count)d users matched" msgstr[0] "" msgstr[1] "" #: ipalib/plugins/user.py:710 msgid "Display information about a user." msgstr "" #: ipalib/plugins/user.py:726 msgid "Disable a user account." msgstr "" #: ipalib/plugins/user.py:729 #, python-format msgid "Disabled user account \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:748 msgid "Enable a user account." msgstr "" #: ipalib/plugins/user.py:752 #, python-format msgid "Enabled user account \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:769 msgid "" "\n" " Unlock a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator." msgstr "" #: ipalib/plugins/user.py:778 #, python-format msgid "Unlocked account \"%(value)s\"" msgstr "" #: ipalib/plugins/user.py:794 msgid "" "\n" " Lockout status of a user account\n" "\n" " An account may become locked if the password is entered incorrectly too\n" " many times within a specific time period as controlled by password\n" " policy. A locked account is a temporary condition and may be unlocked " "by\n" " an administrator.\n" "\n" " This connects to each IPA master and displays the lockout status on\n" " each one.\n" "\n" " To determine whether an account is locked on a given server you need\n" " to compare the number of failed logins and the time of the last " "failure.\n" " For an account to be locked it must exceed the maxfail failures within\n" " the failinterval duration as specified in the password policy " "associated\n" " with the user.\n" "\n" " The failed login counter is modified only when a user attempts a log in\n" " so it is possible that an account may appear locked but the last failed\n" " login attempt is older than the lockouttime of the password policy. " "This\n" " means that the user may attempt a login again. " msgstr "" #: ipalib/plugins/user.py:852 #, python-format msgid "%(host)s failed: %(error)s" msgstr "" #: ipalib/plugins/user.py:888 #, python-format msgid "%(host)s failed" msgstr "" #: ipalib/plugins/user.py:898 #, python-format msgid "Account disabled: %(disabled)s" msgstr "" #: ipalib/plugins/virtual.py:52 msgid "operation not defined" msgstr "" #: ipalib/plugins/virtual.py:65 msgid "not allowed to perform this command" msgstr "" #: ipalib/plugins/virtual.py:67 msgid "No such virtual command" msgstr "" #: ipalib/rpc.py:673 msgid "any of the configured servers" msgstr "" #: ipalib/session.py:776 ipalib/session.py:879 msgid "could not allocate unique new session_id" msgstr "" #: ipalib/util.py:186 msgid "Filename is empty" msgstr "" #: ipalib/util.py:190 #, python-format msgid "Permission denied: %(file)s" msgstr "" #: ipalib/util.py:228 msgid "empty DNS label" msgstr "" #: ipalib/util.py:231 msgid "DNS label cannot be longer that 63 characters" msgstr "" #: ipalib/util.py:234 #, python-format msgid "" "only letters, numbers,%(underscore)s and - are allowed. DNS label may not " "start or end with -" msgstr "" #: ipalib/util.py:252 msgid "" "mail account may only include letters, numbers, -, _ and a dot. There may " "not be consecutive -, _ and . characters. Its parts may not start or end " "with - or _" msgstr "" #: ipalib/util.py:258 ipalib/util.py:297 msgid "cannot be longer that 255 characters" msgstr "" #: ipalib/util.py:266 msgid "too many '@' characters" msgstr "" #: ipalib/util.py:279 msgid "missing address domain" msgstr "" #: ipalib/util.py:284 msgid "missing mail account" msgstr "" #: ipalib/util.py:303 msgid "hostname contains empty label (consecutive dots)" msgstr "" #: ipalib/util.py:307 msgid "not fully qualified" msgstr "" #: ipalib/util.py:319 ipalib/util.py:325 msgid "invalid SSH public key" msgstr "" #: ipalib/util.py:328 msgid "options are not allowed" msgstr "" #: ipalib/x509.py:207 msgid "improperly formatted DER-encoded certificate" msgstr "" #: ipalib/x509.py:244 #, python-format msgid "Issuer \"%(issuer)s\" does not match the expected issuer" msgstr "" #: ipapython/dogtag.py:176 #, python-format msgid "Retrieving CA cert chain failed: %s" msgstr "" #: ipapython/dogtag.py:182 #, python-format msgid "request failed with HTTP status %d" msgstr "" #: ipapython/dogtag.py:205 ipapython/dogtag.py:212 #, python-format msgid "Retrieving CA status failed: %s" msgstr "" #: ipapython/ipaldap.py:1000 #, python-format msgid "objectclass %s not found" msgstr "" #: ipaserver/dcerpc.py:59 msgid "" "\n" "Classes to manage trust joins using DCE-RPC calls\n" "\n" "The code in this module relies heavily on samba4-python package\n" "and Samba4 python bindings.\n" msgstr "" #: ipaserver/dcerpc.py:76 msgid "CIFS server denied your credentials" msgstr "" #: ipaserver/dcerpc.py:79 msgid "communication with CIFS server was unsuccessful" msgstr "" #: ipaserver/dcerpc.py:84 msgid "AD domain controller" msgstr "" #: ipaserver/dcerpc.py:84 msgid "unsupported functional level" msgstr "" #: ipaserver/dcerpc.py:89 msgid "Cannot find specified domain or server name" msgstr "" #: ipaserver/dcerpc.py:91 msgid "At least the domain or IP address should be specified" msgstr "" #: ipaserver/dcerpc.py:103 #, python-format msgid "" "CIFS server communication error: code \"%(num)s\",\n" " message \"%(message)s\" (both may be \"None\")" msgstr "" #: ipaserver/dcerpc.py:194 msgid "" "communication with trusted domains is allowed for Trusts administrator group " "members only" msgstr "" #: ipaserver/dcerpc.py:214 msgid "no trusted domain is configured" msgstr "" #: ipaserver/dcerpc.py:221 msgid "domain is not configured" msgstr "" #: ipaserver/dcerpc.py:228 msgid "SID is not valid" msgstr "" #: ipaserver/dcerpc.py:243 msgid "SID does not match exactlywith any trusted domain's SID" msgstr "" #: ipaserver/dcerpc.py:254 msgid "SID does not match any trusted domain" msgstr "" #: ipaserver/dcerpc.py:294 ipaserver/dcerpc.py:300 ipaserver/dcerpc.py:562 msgid "Trust setup" msgstr "" #: ipaserver/dcerpc.py:295 msgid "Our domain is not configured" msgstr "" #: ipaserver/dcerpc.py:301 msgid "No trusted domain is not configured" msgstr "" #: ipaserver/dcerpc.py:306 ipaserver/dcerpc.py:321 ipaserver/dcerpc.py:338 #: ipaserver/dcerpc.py:350 ipaserver/dcerpc.py:357 ipaserver/dcerpc.py:402 msgid "trusted domain object" msgstr "" #: ipaserver/dcerpc.py:307 msgid "domain is not trusted" msgstr "" #: ipaserver/dcerpc.py:322 msgid "no trusted domain matched the specified flat name" msgstr "" #: ipaserver/dcerpc.py:324 msgid "trusted domain object not found" msgstr "" #: ipaserver/dcerpc.py:339 ipaserver/dcerpc.py:403 msgid "Ambiguous search, user domain was not specified" msgstr "" #: ipaserver/dcerpc.py:351 msgid "Trusted domain did not return a unique object" msgstr "" #: ipaserver/dcerpc.py:358 msgid "Trusted domain did not return a valid SID for the object" msgstr "" #: ipaserver/dcerpc.py:388 ipaserver/dcerpc.py:398 msgid "trusted domain user not found" msgstr "" #: ipaserver/dcerpc.py:498 #, python-format msgid "" "KDC for %(domain)s denied trust account for IPA domain with a message " "'%(message)s'" msgstr "" #: ipaserver/dcerpc.py:563 msgid "Cannot retrieve trusted domain GC list" msgstr "" #: ipaserver/dcerpc.py:704 msgid "CIFS credentials object" msgstr "" #: ipaserver/dcerpc.py:737 #, python-format msgid "CIFS server %(host)s denied your credentials" msgstr "" #: ipaserver/dcerpc.py:741 #, python-format msgid "Cannot establish LSA connection to %(host)s. Is CIFS server running?" msgstr "" #: ipaserver/dcerpc.py:899 #, python-format msgid "" "the IPA server and the remote domain cannot share the same NetBIOS name: %s" msgstr "" #: ipaserver/install/certs.py:639 #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "" #: ipaserver/plugins/dogtag.py:1252 msgid "Unable to communicate with CMS" msgstr "" #: ipaserver/plugins/dogtag.py:1834 msgid "find not supported on CAs upgraded from 9 to 10" msgstr "" #: ipaserver/plugins/join.py:59 msgid "The hostname to register as" msgstr "" #: ipaserver/plugins/join.py:68 msgid "The IPA realm" msgstr "" #: ipaserver/plugins/join.py:74 msgid "Hardware platform of the host (e.g. Lenovo T61)" msgstr "" #: ipaserver/plugins/join.py:78 msgid "Operating System and version of the host (e.g. Fedora 9)" msgstr "" #: ipaserver/plugins/join.py:118 #, python-format msgid "" "Insufficient 'write' privilege to the 'krbLastPwdChange' attribute of entry " "'%s'." msgstr "" #: ipaserver/rpcserver.py:538 msgid "Request must be a dict" msgstr "" #: ipaserver/rpcserver.py:540 msgid "Request is missing \"method\"" msgstr "" #: ipaserver/rpcserver.py:542 msgid "Request is missing \"params\"" msgstr "" #: ipaserver/rpcserver.py:548 msgid "params must be a list" msgstr "" #: ipaserver/rpcserver.py:550 msgid "params must contain [args, options]" msgstr "" #: ipaserver/rpcserver.py:553 msgid "params[0] (aka args) must be a list" msgstr "" #: ipaserver/rpcserver.py:556 msgid "params[1] (aka options) must be a dict" msgstr "" #: ipa-client/config.c:56 #, c-format msgid "cannot open configuration file %s\n" msgstr "" #: ipa-client/config.c:63 #, c-format msgid "cannot stat() configuration file %s\n" msgstr "" #: ipa-client/config.c:69 #, c-format msgid "out of memory\n" msgstr "" #: ipa-client/config.c:80 #, c-format msgid "read error\n" msgstr "" #: ipa-client/ipa-getkeytab.c:61 #, c-format msgid "Kerberos context initialization failed: %1$s (%2$d)\n" msgstr "" #: ipa-client/ipa-getkeytab.c:72 #, c-format msgid "Unable to parse principal: %1$s (%2$d)\n" msgstr "" #: ipa-client/ipa-getkeytab.c:127 #, c-format msgid "No keys accepted by KDC\n" msgstr "" #: ipa-client/ipa-getkeytab.c:142 #, c-format msgid "Out of memory \n" msgstr "" #: ipa-client/ipa-getkeytab.c:181 #, c-format msgid "Out of Memory!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:188 #, c-format msgid "Failed to create control!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:212 #, c-format msgid "Unable to initialize ldap library!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:220 ipa-client/ipa-join.c:240 #, c-format msgid "Unable to set LDAP_OPT_X_SASL_NOCANON\n" msgstr "" #: ipa-client/ipa-getkeytab.c:228 #, c-format msgid "Unable to set ldap options!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:241 #, c-format msgid "Simple bind failed\n" msgstr "" #: ipa-client/ipa-getkeytab.c:273 ipa-client/ipa-getkeytab.c:286 #: ipa-client/ipa-getkeytab.c:293 ipa-client/ipa-getkeytab.c:300 #, c-format msgid "Operation failed! %s\n" msgstr "" #: ipa-client/ipa-getkeytab.c:306 ipa-client/ipa-getkeytab.c:316 #, c-format msgid "Missing reply control!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:323 #, c-format msgid "ber_init() failed, Invalid control ?!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:342 #, c-format msgid "ber_scanf() failed, unable to find kvno ?!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:354 #, c-format msgid "Failed to retrieve encryption type type #%d\n" msgstr "" #: ipa-client/ipa-getkeytab.c:358 #, c-format msgid "Failed to retrieve encryption type %1$s (#%2$d)\n" msgstr "" #: ipa-client/ipa-getkeytab.c:368 #, c-format msgid "Failed to retrieve any keys" msgstr "" #: ipa-client/ipa-getkeytab.c:405 msgid "New Principal Password" msgstr "" #: ipa-client/ipa-getkeytab.c:411 msgid "Verify Principal Password" msgstr "" #: ipa-client/ipa-getkeytab.c:445 msgid "Print as little as possible" msgstr "" #: ipa-client/ipa-getkeytab.c:445 msgid "Output only on errors" msgstr "" #: ipa-client/ipa-getkeytab.c:447 msgid "Contact this specific KDC Server" msgstr "" #: ipa-client/ipa-getkeytab.c:448 msgid "Server Name" msgstr "" #: ipa-client/ipa-getkeytab.c:450 ipa-client/ipa-rmkeytab.c:171 msgid "The principal to get a keytab for (ex: ftp/ftp.example.com@EXAMPLE.COM)" msgstr "" #: ipa-client/ipa-getkeytab.c:451 ipa-client/ipa-rmkeytab.c:172 msgid "Kerberos Service Principal Name" msgstr "" #: ipa-client/ipa-getkeytab.c:453 ipa-client/ipa-rmkeytab.c:174 msgid "File were to store the keytab information" msgstr "" #: ipa-client/ipa-getkeytab.c:454 ipa-client/ipa-rmkeytab.c:174 msgid "Keytab File Name" msgstr "" #: ipa-client/ipa-getkeytab.c:456 msgid "Encryption types to request" msgstr "" #: ipa-client/ipa-getkeytab.c:457 msgid "Comma separated encryption types list" msgstr "" #: ipa-client/ipa-getkeytab.c:459 msgid "Show the list of permitted encryption types and exit" msgstr "" #: ipa-client/ipa-getkeytab.c:460 msgid "Permitted Encryption Types" msgstr "" #: ipa-client/ipa-getkeytab.c:462 msgid "Asks for a non-random password to use for the principal" msgstr "" #: ipa-client/ipa-getkeytab.c:464 msgid "LDAP DN" msgstr "" #: ipa-client/ipa-getkeytab.c:464 msgid "DN to bind as if not using kerberos" msgstr "" #: ipa-client/ipa-getkeytab.c:466 msgid "LDAP password" msgstr "" #: ipa-client/ipa-getkeytab.c:466 msgid "password to use if not using kerberos" msgstr "" #: ipa-client/ipa-getkeytab.c:491 ipa-client/ipa-rmkeytab.c:190 #, c-format msgid "Kerberos context initialization failed\n" msgstr "" #: ipa-client/ipa-getkeytab.c:504 util/ipa_krb5.c:792 #, c-format msgid "No system preferred enctypes ?!\n" msgstr "" #: ipa-client/ipa-getkeytab.c:507 #, c-format msgid "Supported encryption types:\n" msgstr "" #: ipa-client/ipa-getkeytab.c:511 #, c-format msgid "Warning: failed to convert type (#%d)\n" msgstr "" #: ipa-client/ipa-getkeytab.c:530 #, c-format msgid "Bind password required when using a bind DN.\n" msgstr "" #: ipa-client/ipa-getkeytab.c:543 #, c-format msgid "" "Warning: salt types are not honored with randomized passwords (see opt. -P)\n" msgstr "" #: ipa-client/ipa-getkeytab.c:555 #, c-format msgid "Invalid Service Principal Name\n" msgstr "" #: ipa-client/ipa-getkeytab.c:563 #, c-format msgid "Kerberos Credential Cache not found. Do you have a Kerberos Ticket?\n" msgstr "" #: ipa-client/ipa-getkeytab.c:571 #, c-format msgid "" "Kerberos User Principal not found. Do you have a valid Credential Cache?\n" msgstr "" #: ipa-client/ipa-getkeytab.c:579 #, c-format msgid "Failed to open Keytab\n" msgstr "" #: ipa-client/ipa-getkeytab.c:589 #, c-format msgid "Failed to create key material\n" msgstr "" #: ipa-client/ipa-getkeytab.c:608 #, c-format msgid "Failed to add key to the keytab\n" msgstr "" #: ipa-client/ipa-getkeytab.c:617 #, c-format msgid "Failed to close the keytab\n" msgstr "" #: ipa-client/ipa-getkeytab.c:623 #, c-format msgid "Keytab successfully retrieved and stored in: %s\n" msgstr "" #: ipa-client/ipa-join.c:65 #, c-format msgid "No permission to join this host to the IPA domain.\n" msgstr "" #: ipa-client/ipa-join.c:94 ipa-client/ipa-join.c:106 #, c-format msgid "No write permissions on keytab file '%s'\n" msgstr "" #: ipa-client/ipa-join.c:111 #, c-format msgid "access() on %1$s failed: errno = %2$d\n" msgstr "" #: ipa-client/ipa-join.c:134 ipa-client/ipa-join.c:163 #: ipa-client/ipa-join.c:220 #, c-format msgid "Out of memory!" msgstr "" #: ipa-client/ipa-join.c:227 #, c-format msgid "Unable to initialize connection to ldap server: %s" msgstr "" #: ipa-client/ipa-join.c:233 #, c-format msgid "Unable to enable SSL in LDAP\n" msgstr "" #: ipa-client/ipa-join.c:246 #, c-format msgid "Unable to set LDAP version\n" msgstr "" #: ipa-client/ipa-join.c:266 #, c-format msgid "Bind failed: %s\n" msgstr "" #: ipa-client/ipa-join.c:337 #, c-format msgid "Search for %1$s on rootdse failed with error %2$d\n" msgstr "" #: ipa-client/ipa-join.c:357 ipa-client/ipa-join.c:428 #, c-format msgid "No values for %s" msgstr "" #: ipa-client/ipa-join.c:367 #, c-format msgid "Search for IPA namingContext failed with error %d\n" msgstr "" #: ipa-client/ipa-join.c:373 #, c-format msgid "IPA namingContext not found\n" msgstr "" #: ipa-client/ipa-join.c:408 ipa-client/ipa-join.c:483 #: ipa-client/ipa-join.c:501 ipa-client/ipa-join.c:602 #: ipa-client/ipa-join.c:808 ipa-client/ipa-join.c:869 util/ipa_krb5.c:973 #: util/ipa_krb5.c:1007 #, c-format msgid "Out of memory!\n" msgstr "" #: ipa-client/ipa-join.c:419 #, c-format msgid "Search for ipaCertificateSubjectBase failed with error %d" msgstr "" #: ipa-client/ipa-join.c:490 #, c-format msgid "Unable to determine root DN of %s\n" msgstr "" #: ipa-client/ipa-join.c:508 #, c-format msgid "Incorrect password.\n" msgstr "" #: ipa-client/ipa-join.c:516 #, c-format msgid "Unable to determine certificate subject of %s\n" msgstr "" #: ipa-client/ipa-join.c:532 #, c-format msgid "Enrollment failed. %s\n" msgstr "" #: ipa-client/ipa-join.c:661 #, c-format msgid "principal not found in XML-RPC response\n" msgstr "" #: ipa-client/ipa-join.c:676 #, c-format msgid "Host is already joined.\n" msgstr "" #: ipa-client/ipa-join.c:751 ipa-client/ipa-join.c:955 #, c-format msgid "Unable to determine IPA server from %s\n" msgstr "" #: ipa-client/ipa-join.c:772 ipa-client/ipa-join.c:970 #, c-format msgid "The hostname must be fully-qualified: %s\n" msgstr "" #: ipa-client/ipa-join.c:781 ipa-client/ipa-join.c:986 #, c-format msgid "Unable to join host: Kerberos context initialization failed\n" msgstr "" #: ipa-client/ipa-join.c:789 #, c-format msgid "Error resolving keytab: %s.\n" msgstr "" #: ipa-client/ipa-join.c:798 #, c-format msgid "Error getting default Kerberos realm: %s.\n" msgstr "" #: ipa-client/ipa-join.c:816 #, c-format msgid "Error parsing \"%1$s\": %2$s.\n" msgstr "" #: ipa-client/ipa-join.c:834 #, c-format msgid "Error obtaining initial credentials: %s.\n" msgstr "" #: ipa-client/ipa-join.c:845 #, c-format msgid "Unable to generate Kerberos Credential Cache\n" msgstr "" #: ipa-client/ipa-join.c:853 #, c-format msgid "Error storing creds in credential cache: %s.\n" msgstr "" #: ipa-client/ipa-join.c:900 #, c-format msgid "Unenrollment successful.\n" msgstr "" #: ipa-client/ipa-join.c:903 #, c-format msgid "Unenrollment failed.\n" msgstr "" #: ipa-client/ipa-join.c:908 #, c-format msgid "result not found in XML-RPC response\n" msgstr "" #: ipa-client/ipa-join.c:976 #, c-format msgid "The hostname must not be: %s\n" msgstr "" #: ipa-client/ipa-join.c:993 #, c-format msgid "Unable to join host: Kerberos Credential Cache not found\n" msgstr "" #: ipa-client/ipa-join.c:1001 #, c-format msgid "" "Unable to join host: Kerberos User Principal not found and host password not " "provided.\n" msgstr "" #: ipa-client/ipa-join.c:1016 #, c-format msgid "fork() failed\n" msgstr "" #: ipa-client/ipa-join.c:1045 #, c-format msgid "ipa-getkeytab not found\n" msgstr "" #: ipa-client/ipa-join.c:1048 #, c-format msgid "ipa-getkeytab has bad permissions?\n" msgstr "" #: ipa-client/ipa-join.c:1051 #, c-format msgid "executing ipa-getkeytab failed, errno %d\n" msgstr "" #: ipa-client/ipa-join.c:1063 #, c-format msgid "child exited with %d\n" msgstr "" #: ipa-client/ipa-join.c:1069 #, c-format msgid "Certificate subject base is: %s\n" msgstr "" #: ipa-client/ipa-join.c:1107 msgid "Print the raw XML-RPC output in GSSAPI mode" msgstr "" #: ipa-client/ipa-join.c:1109 msgid "Quiet mode. Only errors are displayed." msgstr "" #: ipa-client/ipa-join.c:1111 msgid "Unenroll this host from IPA server" msgstr "" #: ipa-client/ipa-join.c:1113 msgid "Hostname of this server" msgstr "" #: ipa-client/ipa-join.c:1113 ipa-client/ipa-join.c:1115 msgid "hostname" msgstr "" #: ipa-client/ipa-join.c:1115 msgid "IPA Server to use" msgstr "" #: ipa-client/ipa-join.c:1117 msgid "Specifies where to store keytab information." msgstr "" #: ipa-client/ipa-join.c:1117 msgid "filename" msgstr "" #: ipa-client/ipa-join.c:1119 msgid "Force the host join. Rejoin even if already joined." msgstr "" #: ipa-client/ipa-join.c:1121 msgid "LDAP password (if not using Kerberos)" msgstr "" #: ipa-client/ipa-join.c:1121 msgid "password" msgstr "" #: ipa-client/ipa-join.c:1123 msgid "LDAP basedn" msgstr "" #: ipa-client/ipa-join.c:1123 msgid "basedn" msgstr "" #: ipa-client/ipa-rmkeytab.c:43 #, c-format msgid "Unable to parse principal name\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:45 #, c-format msgid "krb5_parse_name %1$d: %2$s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:55 #, c-format msgid "Removing principal %s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:68 #, c-format msgid "Failed to open keytab\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:72 #, c-format msgid "principal not found\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:74 #, c-format msgid "krb5_kt_get_entry %1$d: %2$s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:82 #, c-format msgid "Unable to remove entry\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:84 #, c-format msgid "kvno %d\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:85 #, c-format msgid "krb5_kt_remove_entry %1$d: %2$s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:119 #, c-format msgid "Unable to parse principal\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:121 #, c-format msgid "krb5_unparse_name %1$d: %2$s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:143 #, c-format msgid "realm not found\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:169 msgid "Print debugging information" msgstr "" #: ipa-client/ipa-rmkeytab.c:169 msgid "Debugging output" msgstr "" #: ipa-client/ipa-rmkeytab.c:176 msgid "Remove all principals in this realm" msgstr "" #: ipa-client/ipa-rmkeytab.c:230 ipa-client/ipa-rmkeytab.c:237 #, c-format msgid "Failed to open keytab '%1$s': %2$s\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:253 #, c-format msgid "Closing keytab failed\n" msgstr "" #: ipa-client/ipa-rmkeytab.c:255 #, c-format msgid "krb5_kt_close %1$d: %2$s\n" msgstr "" #: util/ipa_krb5.c:800 msgid "Out of memory!?\n" msgstr "" #: util/ipa_krb5.c:818 util/ipa_krb5.c:833 msgid "Out of memory\n" msgstr "" #: util/ipa_krb5.c:847 msgid "Warning unrecognized encryption type.\n" msgstr "" #: util/ipa_krb5.c:861 msgid "Warning unrecognized salt type.\n" msgstr "" #: util/ipa_krb5.c:888 msgid "Enctype comparison failed!\n" msgstr "" #: util/ipa_krb5.c:953 msgid "Failed to create random key!\n" msgstr "" #: util/ipa_krb5.c:966 util/ipa_krb5.c:984 util/ipa_krb5.c:992 #: util/ipa_krb5.c:1032 msgid "Failed to create key!\n" msgstr "" #: util/ipa_krb5.c:1018 msgid "Bad or unsupported salt type.\n" msgstr "" freeipa-3.3.4/install/po/tg.po0000664000175000017500000001272212271663206015551 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Petr Viktorin , 2012 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Tajik (http://www.transifex.com/projects/p/fedora/language/" "tg/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: tg\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #, c-format msgid "Passwords do not match!" msgstr "Паролҳо номувофиқанд!" msgid "Passwords do not match" msgstr "Паролҳо номувофиқанд" #, python-format msgid "%(info)s" msgstr "%(info)s" msgid "Already registered" msgstr "Ðаллакай қайд карда шуд" #, python-format msgid "Syntax Error: %(error)s" msgstr "Хатогии ÑинтакÑиÑÓ£: %(error)s" msgid "ACI prefix" msgstr "ПрефикÑи ACI" msgid "ACIs" msgstr "ACIs" msgid "ACI name" msgstr "Ðоми ACI" msgid "Permission" msgstr "Иҷозат" msgid "User group" msgstr "Гурӯҳи корбар" msgid "Permissions" msgstr "Иҷозатҳо" msgid "Attributes" msgstr "Ðттрибутҳо" msgid "Type" msgstr "Ðамуд" msgid "Filter" msgstr "Полоишгар" msgid "Description" msgstr "Шарҳ" msgid "Location" msgstr "Макон" #, python-format msgid "File %(file)s not found" msgstr "Файли %(file)s пайдо нашуд." msgid "Key" msgstr "Тугма" msgid "description" msgstr "шарҳ" msgid "Password" msgstr "Парол" msgid "Entry" msgstr "Вуруд" msgid "Rename" msgstr "Ðзнавномгузорӣ" msgid "Principal" msgstr "ÐÑоÑÓ£" msgid "Subject" msgstr "Мавзӯъ" msgid "Issuer" msgstr "Диҳанда" msgid "Serial number" msgstr "Рақами ÑилÑилавӣ" msgid "Error" msgstr "Хатогӣ" msgid "Status" msgstr "Ҳолат" msgid "Configuration" msgstr "ҶӯрÑозӣ" msgid "Hostname" msgstr "Ðоми мизбон" msgid "Target" msgstr "МақÑад" msgid "Service" msgstr "Хидмат" msgid "Force" msgstr "Маҷбурӣ" msgid "Class" msgstr "Синф" msgid "Delete all?" msgstr "Ҳамаро неÑÑ‚ мекунед?" msgid "Enabled" msgstr "Фаъолшуда" msgid "User name" msgstr "Ðоми корбар" msgid "Serial Number" msgstr "Рақами ÑилÑилавӣ" msgid "Host name" msgstr "Ðоми мизбон" msgid "Add" msgstr "Илова кардан" msgid "Cancel" msgstr "Бекор кардан" msgid "Close" msgstr "Пӯшидан" msgid "Find" msgstr "Ðфтан" msgid "Get" msgstr "Гирифтан" msgid "Issue" msgstr "Барориш" msgid "OK" msgstr "Хуб" msgid "Delete" msgstr "ÐеÑÑ‚ кардан" msgid "Reset" msgstr "БозÑозӣ" msgid "Restore" msgstr "Барқароркунӣ" msgid "Retry" msgstr "Кӯшиш" msgid "Update" msgstr "ҶадидÑозӣ" msgid "View" msgstr "Ðамоиш" msgid "General" msgstr "Умумӣ" msgid "Available" msgstr "ДаÑтраÑ" msgid "Settings" msgstr "Танзимотҳо" msgid "Search" msgstr "ҶуÑтуҷӯ" msgid "Username" msgstr "Ðоми корбар" msgid "Attribute" msgstr "Ðттрибут" msgid "Issued By" msgstr "ДодааÑÑ‚:" msgid "Issued To" msgstr "ДодашудааÑÑ‚ ба:" msgid "Note" msgstr "Эзоҳ" msgid "Organization" msgstr "Ташкилот" msgid "Validity" msgstr "СаҳеҳиÑÑ‚" msgid "Data" msgstr "Маълумот" msgid "Host Name" msgstr "Ðоми мизбон" msgid "User" msgstr "Корбар" msgid "Groups" msgstr "Гуруҳҳо" msgid "Commands" msgstr "Фармонҳо" msgid "Allow" msgstr "Иҷозат додан" msgid "New Password" msgstr "Пароли нав" msgid "Select All" msgstr "Интихоби ҳама" msgid "Audit" msgstr "Ðазорат" msgid "IPA Server" msgstr "Сервери IPA" msgid "Policy" msgstr "СиёÑат" msgid "Sudo" msgstr "Sudo" msgid "Group" msgstr "Гурӯҳ" msgid "First name" msgstr "Ðом" msgid "Last name" msgstr "ÐаÑаб" msgid "Display name" msgstr "Ðоми намоишӣ" msgid "Initials" msgstr "Ðому наÑаб" msgid "City" msgstr "Шаҳр" msgid "ZIP" msgstr "Рамзи ZIP" msgid "Fax Number" msgstr "Рақами факÑ" msgid "Job Title" msgstr "Вазифа" msgid "Manager" msgstr "ДиÑпетчер" #, c-format msgid "out of memory\n" msgstr "берун аз хотира\n" #, c-format msgid "read error\n" msgstr "хатогии хониш\n" #, c-format msgid "Out of memory \n" msgstr "Берун аз хотира \n" #, c-format msgid "Out of Memory!\n" msgstr "Берун аз хотира!\n" msgid "Server Name" msgstr "Ðоми Ñервер" msgid "LDAP DN" msgstr "LDAP DN" msgid "LDAP password" msgstr "Пароли LDAP" #, c-format msgid "Out of memory!" msgstr "Берун аз хотира!" #, c-format msgid "Out of memory!\n" msgstr "Берун аз хотира!\n" #, c-format msgid "Incorrect password.\n" msgstr "Пароли нодуруÑÑ‚.\n" msgid "hostname" msgstr "номи мизбон" msgid "filename" msgstr "номи файл" msgid "password" msgstr "парол" msgid "Out of memory!?\n" msgstr "Ðз хотира берун шуд!?\n" msgid "Out of memory\n" msgstr "Берун аз хотира \n" freeipa-3.3.4/install/po/LINGUAS0000664000175000017500000000045412271663206015623 0ustar mkosekmkosekbn_IN # Bengali (India) de # German ca # Catalan cs # Czech es # Spanish eu # Basque fr # French id # Indonesian ja # Japanese kn # Kannada nl # Dutch pl # Polish ru # Russian tg # Tajik uk # Ukrainian zh_CN # Chinese (China) freeipa-3.3.4/install/po/kn.po0000664000175000017500000005536712271663206015563 0ustar mkosekmkosek# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Red Hat # This file is distributed under the same license as the PACKAGE package. # # Translators: # Chandru , 2010 # jdennis , 2011 msgid "" msgstr "" "Project-Id-Version: FreeIPA\n" "Report-Msgid-Bugs-To: https://bugzilla.redhat.com/enter_bug.cgi?" "product=freeIPA\n" "POT-Creation-Date: 2013-08-01 16:02+0200\n" "PO-Revision-Date: 2013-08-01 14:06+0000\n" "Last-Translator: Petr Viktorin \n" "Language-Team: Kannada (http://www.transifex.com/projects/p/fedora/language/" "kn/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: kn\n" "Plural-Forms: nplurals=1; plural=0;\n" #, python-format msgid "Enter %(label)s again to verify: " msgstr "ಮತà³à²¤à³Šà²®à³à²®à³† ಪರಿಶೀಲಿಸಲೠ%(label)s ಎಂಟರೠಮಾಡಿ:" #, c-format msgid "Passwords do not match!" msgstr "ಗà³à²ªà³à²¤à²ªà²¦à²—ಳೠಹೊಂದಾಣಿಕೆಯಾಗà³à²¤à³à²¤à²¿à²²à³à²²!" #, python-format msgid "unknown error %(code)d from %(server)s: %(error)s" msgstr "%(server)s ಸರà³à²µà²°à³â€Œà²¨à²¿à²‚ದ ಅಜà³à²žà²¾à²¤ ದೋಷ %(code)d: %(error)s" msgid "an internal error has occurred" msgstr "ಆಂತರಿಕ ದೋಷ ಉಂಟಾಗಿದೆ" #, python-format msgid "Invalid JSON-RPC request: %(error)s" msgstr "ಅಸಿಂಧà³à²µà²¾à²¦ JSON-RPC ಬೇಡಿಕೆ: %(error)s" #, python-format msgid "Kerberos error: %(major)s/%(minor)s" msgstr "Kerberos ದೋಷ: %(major)s/%(minor)s" msgid "did not receive Kerberos credentials" msgstr "Kerberos ಯೋಗà³à²¯à²¤à²¾à²ªà²¤à³à²°à²—ಳನà³à²¨à³ ಪಡೆದಿಲà³à²²" msgid "No credentials cache found" msgstr "ಕà³à²¯à²¾à²¶à³â€Œà²¨à²²à³à²²à²¿ ಯೋಗà³à²¯à²¤à²¾à²ªà²¤à³à²°à²—ಳೠಸಿಗà³à²¤à³à²¤à²¿à²²à³à²²" msgid "Ticket expired" msgstr "ಟಿಕೆಟà³â€Œà²¨ ಅವಧಿ ಮà³à²—ಿದಿದೆ" msgid "Credentials cache permissions incorrect" msgstr "ಯೋಗà³à²¯à²¤à²¾à²ªà²¤à³à²°à²—ಳ ಕà³à²¯à²¾à²¶à³â€Œà²¨ ಅನà³à²®à²¤à²¿à²—ಳೠಸರಿಯಿಲà³à²²" msgid "Bad format in credentials cache" msgstr "ಯೋಗà³à²¯à²¤à²¾à²ªà²¤à³à²°à²—ಳ ಕà³à²¯à²¾à²¶à³â€Œà²¨à²²à³à²²à²¿ ಜೋಡಣೆ ಸರಿಯಿಲà³à²²" msgid "Cannot resolve KDC for requested realm" msgstr "ಕೋರಿದ ಕà³à²·à³‡à²¤à³à²°(ರೆಲà³à²®à³)ಕà³à²•ಾಗಿ KDC ಯನà³à²¨à³ ಬಗೆಹರಿಸಲೠಆಗà³à²¤à³à²¤à²¿à²²à³à²²" #, python-format msgid "Insufficient access: %(info)s" msgstr "ನಿಲà³à²•ಣೆ(ಆಕà³à²¸à³†à²¸à³) ಸಾಲದಾಗಿದೆ: %(info)s" msgid "Passwords do not match" msgstr "ಗà³à²ªà³à²¤à²ªà²¦à²—ಳೠಹೊಂದಾಣಿಕೆಯಾಗà³à²¤à³à²¤à²¿à²²à³à²²" msgid "Command not implemented" msgstr "ಆಜà³à²žà³†(ಕಮà³à²¯à²¾à²‚ಡà³)ಯನà³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸಲಾಗಿಲà³à²²" #, python-format msgid "%(reason)s" msgstr "%(reason)s" msgid "This entry already exists" msgstr "ಈ ನಮೂದೠಈಗಾಗಲೇ ಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿à²¦à³†" msgid "You must enroll a host in order to create a host service" msgstr "" "ಒಂದೠಹೋಸà³à²Ÿà³ ಸೇವೆ(ಸರà³à²µà²¿à²¸à³)ಯನà³à²¨à³ ರಚಿಸà³à²µ ಸಲà³à²µà²¾à²—ಿ ನೀವೠಒಂದೠಹೋಸà³à²Ÿà³ ಅನà³à²¨à³ ಸೇರಿಸಲೇಬೇಕಾಗಿದೆ" #, python-format msgid "" "Service principal is not of the form: service/fully-qualified host name: " "%(reason)s" msgstr "" "Service principalನ ಸà³à²µà²°à³‚ಪ ಹೀಗಿಲà³à²²: service/fully-qualified host name: " "%(reason)s" msgid "" "The realm for the principal does not match the realm for this IPA server" msgstr "principalನ ಕà³à²·à³‡à²¤à³à²°(ರೆಲà³à²®à³)ವೠಈ IPA ಸರà³à²µà²°à³â€Œà²¨ ಕà³à²·à³‡à²¤à³à²°(ರೆಲà³à²®à³)ಕà³à²•ೆ ತಾಳೆಯಾಗà³à²¤à³à²¤à²¿à²²à³à²²" msgid "This command requires root access" msgstr "ಈ ಆಜà³à²žà³†(ಕಮà³à²¯à²¾à²‚ಡà³) ರೂಟà³(root) ನಿಲà³à²•ಣೆ(ಆಕà³à²¸à³†à²¸à³) ಕೋರà³à²¤à³à²¤à²¦à³†" msgid "This is already a posix group" msgstr "ಇದೠಈಗಾಗಲೇ posix ಗà³à²‚ಪà³" msgid "A group may not be a member of itself" msgstr "ಒಂದೠಗà³à²‚ಪೠಅದರ ಒಂದೠಸದಸà³à²¯ ಆಗದಿರಬಹà³à²¦à³" #, python-format msgid "Base64 decoding failed: %(reason)s" msgstr "Base64 ಡೆಕೋಡಿಂಗೠವಿಫಲಗೊಂಡಿದೆ: %(reason)s" msgid "A group may not be added as a member of itself" msgstr "ಒಂದೠಗà³à²‚ಪೠಅದರ ಒಂದೠಸದಸà³à²¯à²¨à²‚ತೆ ಸೇರಿಸಲೠಆಗದಿರಬಹà³à²¦à³" msgid "The default users group cannot be removed" msgstr "ಡಿಫಾಲà³à²Ÿà³ ಬಳಕೆದಾರರ ಗà³à²‚ಪನà³à²¨à³ ತೆಗೆದà³à²¹à²¾à²•ಲೠಆಗà³à²µà³à²¦à²¿à²²à³à²²" msgid "change collided with another change" msgstr "ಬದಲಾವಣೆ ಮತà³à²¤à³Šà²‚ದೠಬದಲಾವಣೆಯೊಂದಿಗೆ ಡಿಕà³à²•ಿಹೊಡೆದಿದೆ" msgid "no modifications to be performed" msgstr "ಯಾವà³à²¦à³‡ ಬದಲಾವಣೆಗಳೠನಡೆಯಬಾರದà³" msgid "limits exceeded for this query" msgstr "ಈ ಕà³à²µà³‡à²°à²¿à²—ೆ ಮಿತಿಗಳೠಮೀರಿವೆ" #, python-format msgid "%(info)s" msgstr "%(info)s" #, python-format msgid "Certificate operation cannot be completed: %(error)s" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಕಾರà³à²¯à²¾à²šà²°à²£à³†à²¯à²¨à³à²¨à³ ಪೂರà³à²£à²—ೊಳಿಸಲೠಆಗà³à²¤à³à²¤à²¿à²²à³à²²: %(error)s" msgid "Results are truncated, try a more specific search" msgstr "ಫಲಿತಾಂಶಗಳೠಕತà³à²¤à²°à²¿à²¸à²²à³à²ªà²Ÿà³à²Ÿà²¿à²µà³†, ಹೆಚà³à²šà³à²¹à³ ನಿರà³à²¦à²¿à²·à³à²Ÿà²µà²¾à²¦ ಶೋಧನೆ ಪà³à²°à²¯à²¤à³à²¨à²¿à²¸à²¿" msgid "incorrect type" msgstr "ಸರಿಯಲà³à²²à²¦ ಬಗೆ" msgid "Only one value is allowed" msgstr "ಕೇವಲ ಒಂದೠಬೆಲೆ ಮಾತà³à²° ಅನà³à²®à³‹à²¦à²¿à²¸à²²à²¾à²—ಿದೆ" msgid "must be True or False" msgstr "ನಿಜ (True) ಅಥವಾ ಸà³à²³à³à²³à³ (False) ಆಗಿರಲೇಬೇಕà³" msgid "must be an integer" msgstr "ಇನà³à²Ÿà³€à²œà²°à³ ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "must be at least %(minvalue)d" msgstr "ಕನಿಷà³à² à²µà²¾à²—ಿ %(minvalue)d ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "can be at most %(maxvalue)d" msgstr "ಗರಿಷà³à² à²µà²¾à²—ಿ %(maxvalue)d ಆಗಿರಬಹà³à²¦à³" msgid "must be a decimal number" msgstr "ದಶಾಂಶ ಸಂಖà³à²¯à³† ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "must match pattern \"%(pattern)s\"" msgstr "ನಮೂನೆ \"%(pattern)s\" ಹೊಂದಾಣಿಕೆಯಾಗಲೇಬೇಕà³" msgid "must be binary data" msgstr "ಬೈನರಿ ಡಾಟಾ ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "must be at least %(minlength)d bytes" msgstr "ಕನಿಷà³à² à²µà²¾à²—ಿ %(minlength)d ಬೈಟà³à²¸à³ ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "can be at most %(maxlength)d bytes" msgstr "ಗರಿಷà³à² à²µà²¾à²—ಿ %(maxlength)d ಬೈಟà³à²¸à³ ಆಗಿರಬಹà³à²¦à³" #, python-format msgid "must be exactly %(length)d bytes" msgstr "ನಿಖರವಾಗಿ %(length)d ಬೈಟà³à²¸à³ ಆಗಿರಲೇಬೇಕà³" msgid "must be Unicode text" msgstr "ಯà³à²¨à²¿à²•ೋಡೠಪಠà³à²¯ ಆಗಿರಲೇಬೇಕà³" #, python-format msgid "must be at least %(minlength)d characters" msgstr "ಕನಿಷà³à² à²µà²¾à²—ಿ %(minlength)d ಅಕà³à²·à²°à²—ಳೠಇರಲೇಬೇಕà³" #, python-format msgid "can be at most %(maxlength)d characters" msgstr "ಗರಿಷà³à² à²µà²¾à²—ಿ %(maxlength)d ಅಕà³à²·à²°à²—ಳೠಇರಬಹà³à²¦à³" #, python-format msgid "must be exactly %(length)d characters" msgstr "ನಿಖರವಾಗಿ %(length)d ಅಕà³à²·à²°à²—ಳೠಇರಲೇಬೇಕà³" msgid "type, filter, subtree and targetgroup are mutually exclusive" msgstr " ಬಗೆ, ಫಿಲà³à²Ÿà²°à³, ಸಬà³â€Œà²Ÿà³à²°à³€ ಮತà³à²¤à³ ಟಾರà³à²—ೆಟà³â€Œà²—à³à²°à³‚ಪೠಗಳೠಪರಸà³à²ªà²° ಪà³à²°à²¤à³à²¯à³‡à²•" msgid "" "at least one of: type, filter, subtree, targetgroup, attrs or memberof are " "required" msgstr "" "ಕನಿಷà³à²Ÿ ಒಂದೠ: ಬಗೆ, ಫಿಲà³à²Ÿà²°à³, ಸಬà³â€Œà²Ÿà³à²°à³€, ಟಾರà³à²—ೆಟà³â€Œà²—à³à²°à³‚ಪà³, attrs ಅಥವಾ memberof ಗಳ ಅಗತà³à²¯à²µà²¿à²¦à³†" #, python-format msgid "Group '%s' does not exist" msgstr " '%s' ಗà³à²‚ಪೠಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿à²²à³à²²" #, python-format msgid "ACI with name \"%s\" not found" msgstr "\"%s\" ಹೆಸರೠಹೊಂದಿರà³à²µ ACI ಪತà³à²¤à³†à²¯à²¾à²—ಿಲà³à²²" msgid "ACIs" msgstr "ACIs" msgid "ACI name" msgstr "ACI ಹೆಸರà³" msgid "User group" msgstr "ಬಳಕೆದಾರ ಗà³à²‚ಪà³" msgid "User group ACI grants access to" msgstr "User group ACI grants access to" msgid "Permissions" msgstr "ಅನà³à²®à²¤à²¿à²—ಳà³" msgid "Attributes" msgstr "ವೈಶಿಷà³à²Ÿà³à²¯à²—ಳà³" msgid "Type" msgstr "ಬಗೆ" msgid "Member of" msgstr "ಸದಸà³à²¯" msgid "Member of a group" msgstr "ಒಂದೠಗà³à²‚ಪಿನ ಸದಸà³à²¯" msgid "Filter" msgstr "ಶೋಧಕ (ಫಿಲà³à²Ÿà²°à³)" msgid "Legal LDAP filter (e.g. ou=Engineering)" msgstr "Legal LDAP filter (e.g. ou=Engineering)" msgid "Subtree" msgstr "ಉಪವೃಕà³à²·" msgid "Subtree to apply ACI to" msgstr "Subtree to apply ACI to" msgid "Target group" msgstr "Target ಗà³à²‚ಪà³" msgid "Group to apply ACI to" msgstr "Group to apply ACI to" #, python-format msgid "Created ACI \"%(value)s\"" msgstr "\"%(value)s\" ACIವನà³à²¨à³ ರಚಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted ACI \"%(value)s\"" msgstr "\"%(value)s\" ACIವನà³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" #, python-format msgid "Modified ACI \"%(value)s\"" msgstr "\"%(value)s\" ACIವನà³à²¨à³ ಬದಲಾಯಿಸಲಾಗಿದೆ" msgid "Description" msgstr "ವಿವರಣೆ" msgid "Location" msgstr "ಸà³à²¥à²³" msgid "Map" msgstr "ನಕà³à²·à³†" msgid "Automount Maps" msgstr "ಮà³à²¯à²¾à²ªà³â€Œà²—ಳ ಆಟೋಮೌಂಟà³" msgid "Key" msgstr "ಕೀ" msgid "Mount information" msgstr "ಮೌಂಟೠಮಾಹಿತಿ" msgid "description" msgstr "ವಿವರಣೆ" msgid "Automount Keys" msgstr "ಕೀಗಳ ಆಟೋಮೌಂಟà³" msgid "Mount point" msgstr "ಮೌಂಟೠಪಾಯಂಟà³" msgid "Parent map" msgstr "Parent map" msgid "Password" msgstr "ಗà³à²ªà³à²¤à²ªà²¦" msgid "Failed members" msgstr "ವಿಫಲಗೊಂಡ ಸದಸà³à²¯à²°à³" msgid "Member users" msgstr "ಸದಸà³à²¯ ಬಳಕೆದಾರರà³" msgid "Member groups" msgstr "ಸದಸà³à²¯ ಗà³à²‚ಪà³à²—ಳà³" msgid "Member hosts" msgstr "ಸದಸà³à²¯ ಹೋಸà³à²Ÿà³â€Œà²—ಳà³" msgid "Member host-groups" msgstr "ಸದಸà³à²¯ ಹೋಸà³à²Ÿà³-ಗà³à²°à³‚ಪà³â€Œà²—ಳà³" msgid "Member of host-groups" msgstr "ಹೋಸà³à²Ÿà³-ಗà³à²‚ಪಿನ ಸದಸà³à²¯" msgid "External host" msgstr "ಹೊರಗಿನ ಹೋಸà³à²Ÿà³" msgid "Failure decoding Certificate Signing Request" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಸಹಿಯ ಕೋರಿಕೆಯ ಡಿಕೋಡಿಂಗà³â€Œà²¨ ವಿಫಲತೆ" #, python-format msgid "Failure decoding Certificate Signing Request: %s" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ಸಹಿಯ ಕೋರಿಕೆಯ ಡಿಕೋಡಿಂಗà³â€Œà²¨ ವಿಫಲತೆ: %s" msgid "Principal" msgstr "Principal" msgid "Service principal for this certificate (e.g. HTTP/test.example.com)" msgstr "ಈ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²•à³à²•ಾಗಿ Service principal (e.g. HTTP/test.example.com)" msgid "automatically add the principal if it doesn't exist" msgstr "ಸà³à²µà²¯à²‚ಚಾಲಿತವಾಗಿ principal ಸೇರಿಸಿ ಅದೠಅಸà³à²¤à²¿à²¤à³à²µà²¦à²²à³à²²à²¿ ಇಲà³à²²à²¦à²¿à²¦à³à²¦à²²à³à²²à²¿" msgid "Certificate" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°" msgid "Subject" msgstr "ವಿಷಯ" msgid "Serial number" msgstr "ಅನà³à²•à³à²°à²® ಸಂಖà³à²¯à³†" msgid "Request id" msgstr "ಬೇಡಿಕೆ ID" msgid "Request status" msgstr "ಬೇಡಿಕೆ ಸà³à²¥à²¿à²¤à²¿" msgid "Serial number in decimal or if prefixed with 0x in hexadecimal" msgstr "ಕà³à²°à²® ಸಂಖà³à²¯à³† ಡೆಸಿಮಲà³â€Œà²¨à²²à³à²²à²¿ ಅಥವಾ 0x ಮೊದಲೠಸೇರಿಸಿದà³à²¦à²²à³à²²à²¿ ಹೆಕà³à²¸à²¾à²¡à³†à²¸à²¿à²®à²²à³â€Œà²¨à²²à³à²²à²¿" msgid "Revocation reason" msgstr "ರದà³à²¦à³ ಮಾಡà³à²µà³à²¦à²•à³à²•ೆ ಕಾರಣ" msgid "Revoked" msgstr "ರದà³à²¦à³ ಮಾಡಲಾಗಿದೆ" msgid "Reason" msgstr "ಕಾರಣ" msgid "Reason for revoking the certificate (0-10)" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²µà²¨à³à²¨à³ (0-10) ರದà³à²¦à³ ಮಾಡಲೠಕಾರಣ" msgid "Unrevoked" msgstr "ರದà³à²¦à³ ಮಾಡಲಾಗಿಲà³à²²" msgid "Error" msgstr "ದೋಷ" msgid "Home directory base" msgstr "ಹೋಮೠಡೈರೆಕà³à²Ÿà²°à³€ ಮೂಲ" msgid "Default shell" msgstr "ಡೀಫಾಲà³à²Ÿà³ ಶೆಲà³" msgid "Default users group" msgstr "ಡಿಫಾಲà³à²Ÿà³ ಬಳಕೆದಾರರ ಗà³à²‚ಪà³" msgid "Search time limit" msgstr "ಹà³à²¡à³à²•ೠಸಮಯ ಮಿತಿ" msgid "Search size limit" msgstr "ಹà³à²¡à³à²•ೠಗಾತà³à²° ಮಿತಿ" msgid "User search fields" msgstr "ಬಳಕೆದಾರನ ಶೋಧ ಫೀಲà³à²¡à³â€Œà²—ಳà³" msgid "Certificate Subject base" msgstr "ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°à²¦ ವಿಷಯ ಮೂಲ" msgid "Priority" msgstr "ಆದà³à²¯à²¤à³†" msgid "Zone name" msgstr "ವಲಯದ ಹೆಸರà³" msgid "Zone name (FQDN)" msgstr "ವಲಯದ ಹೆಸರೠ(FQDN)" msgid "SOA serial" msgstr "SOA serial" msgid "SOA refresh" msgstr "SOA refresh" msgid "SOA retry" msgstr "SOA retry" msgid "SOA expire" msgstr "SOA expire" msgid "SOA minimum" msgstr "SOA minimum" msgid "SOA time to live" msgstr "SOA time to live" msgid "SOA class" msgstr "SOA class" msgid "BIND update policy" msgstr "BIND update policy" msgid "Time to live" msgstr "ಉಳಿದಿರಬೇಕಾದ ಸಮಯ" msgid "Class" msgstr "ವರà³à²—" msgid "User Groups" msgstr "ಬಳಕೆದಾರರ ಗà³à²‚ಪà³à²—ಳà³" msgid "Group name" msgstr "ಗà³à²‚ಪಿನ ಹೆಸರà³" msgid "Group description" msgstr "ಗà³à²‚ಪಿನ ವಿವರಣೆ" msgid "GID" msgstr "GID" msgid "GID (use this option to set it manually)" msgstr "GID (ಇದನà³à²¨à³ ಮà³à²¯à²¾à²¨à³à²¯à³‚ವಲೠಆಗಿ ಸೆಟೠಮಾಡಲೠಈ ಆಯà³à²•ೆಯನà³à²¨à³ ಬಳಸಿ)" #, python-format msgid "Added group \"%(value)s\"" msgstr "\"%(value)s\" ಗà³à²‚ಪನà³à²¨à³ ಸೇರಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted group \"%(value)s\"" msgstr "\"%(value)s\" ಗà³à²‚ಪನà³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" #, python-format msgid "Modified group \"%(value)s\"" msgstr "\"%(value)s\" ಗà³à²‚ಪನà³à²¨à³ ಬದಲಾಯಿಸಲಾಗಿದೆ" msgid "Rule name" msgstr "ನಿಯಮದ ಹೆಸರà³" msgid "User category" msgstr "ಬಳಕೆದಾರನ ವರà³à²—" msgid "User category the rule applies to" msgstr "ನಿಯಮ ಅನà³à²µà²¯à²¿à²¸à³à²µà²‚ತಹ ಬಳಕೆದಾರನ ವರà³à²—" msgid "Host category" msgstr "ಹೋಸà³à²Ÿà³ ವರà³à²—" msgid "Host category the rule applies to" msgstr "ನಿಯಮ ಅನà³à²µà²¯à²¿à²¸à³à²µà²‚ತಹ ಹೋಸà³à²Ÿà³ ವರà³à²—" msgid "Users" msgstr "ಬಳಕೆದಾರರà³" msgid "Hosts" msgstr "ಹೋಸà³à²Ÿà³â€Œà²—ಳà³" msgid "Host Groups" msgstr "ಹೋಸà³à²Ÿà³ ಗà³à²‚ಪà³à²—ಳà³" msgid "Services" msgstr "ಸೇವೆಗಳà³(ಸರà³à²µà³€à²¸à²¸à³)" msgid "Access time" msgstr "ಪà³à²°à²µà³‡à²¶à²¦ ಸಮಯ" msgid "Service name" msgstr "ಸೇವೆಯ ಹೆಸರà³" msgid "User name" msgstr "ಬಳಕೆದಾರನ ಹೆಸರà³" msgid "Host name" msgstr "ಹೋಸà³à²Ÿà³ ಹೆಸರà³" msgid "A description of this host" msgstr "ಈ ಹೋಸà³à²Ÿà³â€Œà²¨ ವಿವರಣೆ" msgid "Locality" msgstr "ಪà³à²°à²¦à³‡à²¶" msgid "Host locality (e.g. \"Baltimore, MD\")" msgstr "ಹೋಸà³à²Ÿà³ ತಾಣ (e.g. \"Baltimore, MD\")" msgid "Host location (e.g. \"Lab 2\")" msgstr "ಹೋಸà³à²Ÿà³ ತಾಣ (e.g. \"Lab 2\")" msgid "Platform" msgstr "ಪà³à²²à²¾à²Ÿà³â€Œà²«à²¾à²°à³à²®à³" msgid "Host hardware platform (e.g. \"Lenovo T61\")" msgstr "ಹೋಸà³à²Ÿà³ ಹಾರà³à²¡à³â€Œà²µà³‡à²°à³ ಪà³à²²à³à²¯à²¾à²Ÿà³â€Œà²«à²¾à²°à³à²®à³ (e.g. \"Lenovo T61\")" msgid "Operating system" msgstr "ಕಾರà³à²¯à²•ಾರಿ ವà³à²¯à²µà²¸à³à²¥à³†" msgid "Host operating system and version (e.g. \"Fedora 9\")" msgstr "ಹೋಸà³à²Ÿà³ ಕಾರà³à²¯à²•ಾರಿ ವà³à²¯à²µà²¸à³à²¥à³† ಮತà³à²¤à³ ಆವೃತà³à²¤à²¿ (e.g. \"Fedora 9\")" msgid "User password" msgstr "ಬಳಕೆದಾರನ ಗà³à²ªà³à²¤à²ªà²¦" msgid "Password used in bulk enrollment" msgstr "ದೊಡà³à²¡ ಪà³à²°à²®à²¾à²£à²¦ ದಾಖಲಾತಿಯಲà³à²²à²¿ ಬಳಸಲಾದ ಗà³à²ªà³à²¤à²ªà²¦" msgid "Base-64 encoded server certificate" msgstr "Base-64 ಎನà³â€Œà²•ೋಡೆಡೠಸರà³à²µà²°à³ ಪà³à²°à²®à²¾à²£à²ªà²¤à³à²°" msgid "Principal name" msgstr "Principal ಹೆಸರà³" #, python-format msgid "Added host \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà²¨à³à²¨à³ ಸೇರಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted host \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà²¨à³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" #, python-format msgid "Modified host \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà²¨à³à²¨à³ ಬದಲಾಯಿಸಲಾಗಿದೆ" msgid "Kerberos principal name for this host" msgstr "ಈ ಹೋಸà³à²Ÿà³â€Œà²—ೆ Kerberos principalನ ಹೆಸರà³" msgid "Host-group" msgstr "ಹೋಸà³à²Ÿà³-ಗà³à²‚ಪà³" msgid "Name of host-group" msgstr "ಹೋಸà³à²Ÿà³-ಗà³à²‚ಪಿನ ಹೆಸರà³" msgid "A description of this host-group" msgstr "ಈ ಹೋಸà³à²Ÿà³-ಗà³à²°à³‚ಪà³â€Œà²¨ ವಿವರಣೆ" #, python-format msgid "Added hostgroup \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà³â€Œà²—à³à²°à³‚ಪನà³à²¨à³ ಸೇರಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted hostgroup \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà³â€Œà²—à³à²°à³‚ಪನà³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" #, python-format msgid "Modified hostgroup \"%(value)s\"" msgstr "\"%(value)s\" ಹೋಸà³à²Ÿà³â€Œà²—à³à²°à³‚ಪನà³à²¨à³ ಬದಲಾಯಿಸಲಾಗಿದೆ" msgid "Data" msgstr "ದತà³à²¤à²¾à²‚ಶ" msgid "User" msgstr "ಬಳಕೆದಾರ" msgid "Groups" msgstr "ಗà³à²‚ಪà³à²—ಳà³" msgid "DNS" msgstr "DNS" msgid "Manage ticket policy for specific user" msgstr "ನಿಗದಿತ ಬಳಕೆದಾರನಿಗೆ ಟಿಕೆಟೠಪಾಲಿಸಿಯನà³à²¨à³ ನಿರà³à²µà²¹à²¿à²¸à³" msgid "Max life" msgstr "ಗರಿಷà³à²Ÿ ಜೀವಿತಾವಧಿ" msgid "Max renew" msgstr "ಗರಿಷà³à²Ÿ ನವೀಕರಣ" msgid "LDAP URI" msgstr "LDAP URI" msgid "LDAP URI of DS server to migrate from" msgstr "LDAP URI of DS server to migrate from" msgid "Bind DN" msgstr "ಬೈಂಡೠDN" msgid "User container" msgstr "ಬಳಕೆದಾರನ ಕಂಟೇನರà³" msgid "Group container" msgstr "ಗà³à²‚ಪಿನ ಕಂಟೇನರà³" #, python-format msgid "%(count)d variables" msgstr "%(count)d ವೇರಿಯೇಬಲà³â€Œà²—ಳà³" msgid "Netgroups" msgstr "ನೆಟà³â€Œà²—à³à²°à³‚ಪà³â€Œà²—ಳà³" msgid "Netgroup name" msgstr "ನೆಟà³â€Œà²—à³à²°à³‚ಪೠಹೆಸರà³" msgid "Netgroup description" msgstr "ನೆಟà³â€Œà²—à³à²°à³‚ಪೠವಿವರಣೆ" msgid "NIS domain name" msgstr "NIS ಡೊಮೇನೠಹೆಸರà³" msgid "Group" msgstr "ಗà³à²‚ಪà³" msgid "Max lifetime (days)" msgstr "ಗರಿಷà³à²Ÿ ಜೀವಿತಾವಧಿ (ದಿನಗಳà³)" msgid "Maximum password lifetime (in days)" msgstr "ಗà³à²ªà³à²¤à²ªà²¦à²¦ ಗರಿಷà³à²Ÿ ಜೀವಿತಾವಧಿ (ದಿನಗಳಲà³à²²à²¿)" msgid "Min lifetime (hours)" msgstr "ಕನಿಷà³à²Ÿ ಜೀವಿತಾವಧಿ (ಘಂಟೆಗಳà³)" msgid "Minimum password lifetime (in hours)" msgstr "ಗà³à²ªà³à²¤à²ªà²¦à²¦ ಕನಿಷà³à²Ÿ ಜೀವಿತಾವಧಿ (ಘಂಟೆಗಳಲà³à²²à²¿)" msgid "History size" msgstr "ಇತಿಹಾಸದ ಗಾತà³à²°" msgid "Password history size" msgstr "ಗà³à²ªà³à²¤à²ªà²¦ ಇತಿಹಾಸದ ಗಾತà³à²°" msgid "Character classes" msgstr "ಕà³à²¯à²¾à²°à³†à²•à³à²Ÿà²°à³ ಕà³à²²à²¾à²¸à³â€Œà²—ಳà³" msgid "Minimum number of character classes" msgstr "ಕನಿಷà³à²Ÿ ಸಂಖà³à²¯à³†à²¯ ಕà³à²¯à²¾à²°à²•à³à²Ÿà²°à³ ಕà³à²²à²¾à²¸à³â€Œà²—ಳà³" msgid "Min length" msgstr "ಕನಿಷà³à²Ÿ ಉದà³à²¦" msgid "Minimum length of password" msgstr "ಗà³à²ªà³à²¤à²ªà²¦à²¦ ಕನಿಷà³à²Ÿ ಉದà³à²¦" msgid "priority cannot be set on global policy" msgstr "ಗà³à²²à³‹à²¬à²²à³ ಪಾಲಿಸಿಯಲà³à²²à²¿ ಆದà³à²¯à²¤à³†à²¯à²¨à³à²¨à³ ಸೆಟೠಮಾಡಲಾಗà³à²µà³à²¦à²¿à²²à³à²²" msgid "A description of this role-group" msgstr "ಈ ರೋಲà³-ಗà³à²°à³‚ಪà³â€Œà²¨ ವಿವರಣೆ" msgid "Service principal" msgstr "Service principal" #, python-format msgid "Added service \"%(value)s\"" msgstr "\"%(value)s\" ಸೇವೆ(ಸರà³à²µà³€à²¸à³)ಯನà³à²¨à³ ಸೇರಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted service \"%(value)s\"" msgstr "\"%(value)s\" ಸೇವೆ(ಸರà³à²µà³€à²¸à³)ಯನà³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" msgid "User login" msgstr "ಬಳಕೆದಾರನ ಪà³à²°à²µà³‡à²¶" msgid "First name" msgstr "ಮೊದಲ ಹೆಸರà³" msgid "Last name" msgstr "ಕೊನೆಯ ಹೆಸರà³" msgid "Login shell" msgstr "ಪà³à²°à²µà³‡à²¶ ಶೆಲà³" msgid "Kerberos principal" msgstr "Kerberos principal" msgid "Email address" msgstr "ಇಮೇಲೠವಿಳಾಸ" msgid "UID" msgstr "UID" msgid "Street address" msgstr "ಕೇರಿ ವಿಳಾಸ" #, python-format msgid "Added user \"%(value)s\"" msgstr "\"%(value)s\" ಬಳಕೆದಾರನನà³à²¨à³ ಸೇರಿಸಲಾಗಿದೆ" #, python-format msgid "Deleted user \"%(value)s\"" msgstr "\"%(value)s\" ಬಳಕೆದಾರನನà³à²¨à³ ಅಳಿಸಲಾಗಿದೆ" #, python-format msgid "Modified user \"%(value)s\"" msgstr "\"%(value)s\" ಬಳಕೆದಾರನನà³à²¨à³ ಬದಲಾಯಿಸಲಾಗಿದೆ" #, python-format msgid "Unable to communicate with CMS (%s)" msgstr "CMS (%s) ಜೊತೆ ಸಂಪರà³à²•ಿಸಲೠಸಾಧà³à²¯à²µà²¾à²—à³à²¤à³à²¤à²¿à²²à³à²²" freeipa-3.3.4/install/po/Makefile.in0000664000175000017500000001544412271663206016650 0ustar mkosekmkosekprefix = @prefix@ exec_prefix = ${prefix} datarootdir = ${prefix}/share datadir = ${datarootdir} localedir = ${datarootdir}/locale INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL@ -m 644 AWK = @AWK@ SED = @SED@ MKDIR_P = @MKDIR_P@ XGETTEXT = @XGETTEXT@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ MSGCMP = @MSGCMP@ MSGATTRIB = @MSGATTRIB@ TX = @TX@ IPA_TEST_I18N = ../../ipatests/i18n.py DOMAIN = @GETTEXT_DOMAIN@ MSGMERGE_UPDATE = $(MSGMERGE) --update COPYRIGHT_HOLDER = Red Hat PACKAGE_NAME = $(DOMAIN) PACKAGE_BUGREPORT = https://hosted.fedoraproject.org/projects/freeipa/newticket XGETTEXT_OPTIONS = \ --add-comments="TRANSLATORS:" \ --copyright-holder="$(COPYRIGHT_HOLDER)" \ --package-name="$(PACKAGE_NAME)" \ --msgid-bugs-address="$(PACKAGE_BUGREPORT)" languages = $(shell $(SED) 's/\#.*//' LINGUAS) # The sed command removes comments po_files = $(patsubst %, %.po, $(languages)) mo_files = $(patsubst %.po, %.mo, $(po_files)) po_count=$(words $(po_files)) PY_FILES = $(shell cd ../..; git ls-files | grep -v -e "^ipatests/" -e "^doc/" -e "^install/po/" -e "^ipapython/test/" -e "setup.py" -e "setup-client.py" | grep "\.py$$" | tr '\n' ' '; cd install/po) C_FILES = $(shell cd ../..; git ls-files | grep "\.c$$" | tr '\n' ' '; cd install/po) H_FILES = $(shell cd ../..; git ls-files | grep "\.h$$" | tr '\n' ' '; cd install/po) # Please keep this list sorted! PY_EXPLICIT_FILES = \ install/tools/ipa-adtrust-install \ install/tools/ipa-ca-install \ install/tools/ipa-compat-manage \ install/tools/ipa-csreplica-manage \ install/tools/ipactl \ install/tools/ipa-dns-install \ install/tools/ipa-ldap-updater \ install/tools/ipa-managed-entries \ install/tools/ipa-nis-manage \ install/tools/ipa-replica-conncheck \ install/tools/ipa-replica-install \ install/tools/ipa-replica-manage \ install/tools/ipa-replica-prepare \ install/tools/ipa-server-certinstall \ install/tools/ipa-server-install \ install/tools/ipa-upgradeconfig \ ipa \ ipa-client/ipa-install/ipa-client-install PYTHON_POTFILES = $(PY_FILES) $(PY_EXPLICIT_FILES) 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 strip-po merge-po $(po_files) all: SUFFIXES = .po .mo .po.mo: @echo Creating $@; \ $(MSGFMT) -c -o t-$@ $< && mv t-$@ $@ $(po_files): $(DOMAIN).pot @if [ ! -f $@ ]; then \ lang=`echo $@ | $(SED) -r -e 's/\.po$$//'` # Strip .po suffix ; \ echo Creating nonexistent $@, you should add this file to your SCM repository; \ $(MSGINIT) --locale $$lang --no-translator -i $(DOMAIN).pot -o $@; \ fi; \ 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 \ lang=`echo $$po_file | $(SED) -r -e 's/\.po$$//'` # Strip .po suffix ; \ echo Creating nonexistent $$po_file, you should add this file to your SCM repository; \ $(MSGINIT) --locale $$lang --no-translator -i $(DOMAIN).pot -o $$po_file; \ fi; \ done pull-po: cd ../..; $(TX) pull -f $(MAKE) strip-po merge-po: update-pot $(MAKE) $(po_files) update-po: merge-po $(MAKE) strip-po update-pot: @rm -f $(DOMAIN).pot.update @pushd ../.. ; \ $(XGETTEXT) $(XGETTEXT_OPTIONS) \ --output install/po/$(DOMAIN).pot.update \ --language="python" \ $(PYTHON_POTFILES) \ && \ $(XGETTEXT) $(XGETTEXT_OPTIONS) \ --output install/po/$(DOMAIN).pot.update \ --join-existing \ --language="c" \ --from-code="UTF-8" \ --keyword='_' \ $(C_POTFILES) ; \ popd ; \ $(SED) '/^"POT-Creation-Date: .*"$$/d' $(DOMAIN).pot.update > $(DOMAIN).pot.update.tmp ; \ $(SED) -i -r -e 's%("Content-Type: text/plain; charset=)(.*)(\\n")%\1UTF-8\3%' $(DOMAIN).pot.update.tmp ; \ $(SED) '/^"POT-Creation-Date: .*"$$/d' $(DOMAIN).pot > $(DOMAIN).pot.tmp ; \ if ! cmp -s $(DOMAIN).pot.update.tmp $(DOMAIN).pot.tmp ; then \ echo "$(DOMAIN).pot updated" ; \ mv $(DOMAIN).pot.update $(DOMAIN).pot ; \ # Replace the charset with UTF-8 ; \ $(SED) -i -r -e 's%("Content-Type: text/plain; charset=)(.*)(\\n")%\1UTF-8\3%' $(DOMAIN).pot ; \ else \ echo "$(DOMAIN).pot unmodified" ; \ fi || : @rm -f $(DOMAIN).pot.update $(DOMAIN).pot.update.tmp $(DOMAIN).pot.tmp $(IPA_TEST_I18N) --show-strings --validate-pot $(DOMAIN).pot msg-stats: @pot_count=`$(MSGFMT) --statistics $(DOMAIN).pot 2>&1 | \ $(AWK) '{match($$0, /([0-9]+) translated messages, ([0-9]+) untranslated messages/, groups); \ printf "%s\n", groups[2];}'` ; \ echo "$(DOMAIN).pot has $$pot_count messages. There are $(po_count) po translation files." ; \ for po_file in $(po_files); do \ $(MSGFMT) --statistics $$po_file 2>&1 | \ $(AWK) -v po_file=$$po_file -v pot_count=$$pot_count -v pot_file=$(DOMAIN).pot \ 'BEGIN {po_name = gensub(/\.po$$/, "", 1, po_file);} \ match($$0, /([[:digit:]]+) translated/, group) {translated = group[1]} \ match($$0, /([[:digit:]]+) untranslated/, group) {untranslated = group[1]} \ match($$0, /([[:digit:]]+) fuzzy/, group) {fuzzy = group[1]} \ END {pot_untranslated = pot_count - translated; \ ratio = sprintf("%d/%d", translated, pot_count); \ printf "%-7s %11s %5.1f%% %5d untranslated, %5d fuzzy\n", \ po_name ":", ratio, translated/pot_count*100.0, pot_untranslated, fuzzy;}'; \ done mo-files: $(mo_files) install: $(mo_files) @for lang in $(languages); do \ dstdir=$(DESTDIR)$(localedir)/$$lang/LC_MESSAGES; \ $(MKDIR_P) $$dstdir; \ $(INSTALL) $$lang.mo $$dstdir/$(DOMAIN).mo; \ done mostlyclean: rm -rf *.mo test.po test_locale tmp.pot rm -f $(DOMAIN).pot.update $(DOMAIN).pot.update.tmp $(DOMAIN).pot.tmp clean: mostlyclean distclean: clean rm -f Makefile maintainer-clean: distclean test: $(IPA_TEST_I18N) --test-gettext validate-pot: $(IPA_TEST_I18N) --show-strings --validate-pot $(DOMAIN).pot validate-po: $(IPA_TEST_I18N) --show-strings --validate-po $(po_files) validate-src-strings: @rm -f tmp.pot @touch tmp.pot @$(MAKE) DOMAIN=tmp update-pot; \ status=$$?; \ rm tmp.pot; \ exit $$status debug: @echo Python potfiles: @echo PY_FILES = $(PY_FILES) @echo PY_EXPLICIT_FILES = $(PY_EXPLICIT_FILES) @echo C potfiles: @echo C_FILES = $(C_FILES) @echo H_FILES = $(H_FILES) freeipa-3.3.4/install/po/README0000664000175000017500000001521212202434255015446 0ustar mkosekmkosekQ: I've added a new source file, how do I make sure it's strings get translated? A: Edit Makefile.in and add the source file to the appropriate *_POTFILES list. Then run "make update-po". 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 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. Q: How do I just regenerate the pot template file without regenerating all the .po files? 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". This will generate a new .po file for each language which doesn't have one yet. Be sure to add the new .po file(s) to the source code repository. For certain languages, you may have to edit the Plurals line. See: 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 invalid Plurals line. Q: What files must be under source code control? A: The files Makefile.in, LINGUAS control the build, they must be in the SCM. The *.pot and *.po files are used by translators, they must be in SCM so the translator can checkout out a .po files, add the translations, and then check the .po file back in. Be careful, .po files may be automatically updated when the source files change (or the .pot changes, usually the .pot file changes only as a result of rescanning the source files). This mean a .po file might be automatically updated while a translator has the file out for editing, all the caveats about SCM merging apply. Q: Which are automatically generated and thus do not need to be in SCM? A: The *.mo files are automatically generated on demand from their corresponding .po file. Q: What role does the .pot file play? A: The .pot file is called a template file. It is generated by scanning all the source files (e.g. *.py *.c *.h) in the project using xgettext. xgettext locates every translatable string (e.g. strings marked with _()) and adds that string along with metadata about it's location to the .pot file. Thus the .pot file is a collection of every translatable string in the project. If you edit a source file and add a translatable string you will have to regenerate the .pot file in order to pick up the new string. Q: What is the relationship between a .po file and the .pot file? A: A .po file contains the translations for particular language. It derives from the .pot file. When the .pot file is updated with new strings to translate each .po will merge the new strings in. The .po file is where translators work providing translations for their language. Thus it's important the .po not be recreated from scratch and is kept in SCM, otherwise the translators work will be lost. Let's use an example for French, it's .po file will be fr.po. 1) Developer creates main.c with one translatable sting _("Begin"). 2) Produce the .pot file by running xgettext on main.c 3) .pot file contains one msgid, "Begin" 4) fr.po is created from the .pot file, it also contains one msgid, "Begin" 5) Translator edits fr.po and provide the French translation of "Begin". 6) Developer adds new translatable sting _("End") to main.c 7) Generate a new .pot file by running xgettext on main.c 8) .pot file contains two msgid's, "Begin", and "End" 9) fr.po is missing the new msgid in the .pot file, so the .pot is merged into fr.po by running msgmerge. This copies into fr.po the new "End" msgid but preserves the existing translations in fr.po (e.g. "Begin"). The fr.po will now have 2 msgid's one which is translated already (e.g. "Begin") and one that untranslated (e.g. "End"). 10) Sometime later the French translator comes back to see if he/she needs to add more translations to fr.po. They see there is a missing translation, they check fr.po out from SCM, add the missing translation, and then check fr.po back into SCM. This means at any given moment the set of .po files will have varying degrees of translation completeness. Because the .po files are merged when the source code files are updated existing translations are not lost. It also means a .po file which was fully translated may need new translations after a .pot update. It is permissible to have incomplete translations in a message catalog, at run time if a translation for a particular string is available in the message catalog the user will be presented with the string in their language. However if the string is not yet translated in the .po file then they just get the original string (typically in English). Q: What are .mo files? A: .mo files are the content of a .po file but in "machine" format for fast run time access (mo = Machine Object, po = Portable Object). .mo files are what gets installed along with the package. Think of a .po as a source file which is compiled into a object file for run time use. Q: Why don't we use gettexize and autopoint? A: Because the framework they produce is too limited. Specifically there is no way to pass the source language to xgettext when it scans a file. xgettext only knows how to automatically determine the language from the source files extension. However we have many files without extensions, thus we have to group all Python (et. al.) files together and run xgettext on every file *we* know to Python (because xgettext can't figure this out itself if there is no file extension). There is another added benefit of avoiding gettextize and autopoint, simplicity. Managing translations is complex and hard enough as it is, gettextize and autopoint adds another whole layer of complexity which just further obscures things. Q: Who created the awful mess and who do I ask when things don't work as I expect or I have further questions? A: John Dennis freeipa-3.3.4/install/share/0000775000175000017500000000000012271707664015266 5ustar mkosekmkosekfreeipa-3.3.4/install/share/kdc.conf.template0000664000175000017500000000072212202434255020474 0ustar mkosekmkosek[kdcdefaults] kdc_ports = 88 kdc_tcp_ports = 88 restrict_anonymous_to_tgt = true [realms] $REALM = { master_key_type = aes256-cts max_life = 7d max_renewable_life = 14d acl_file = /var/kerberos/krb5kdc/kadm5.acl dict_file = /usr/share/dict/words default_principal_flags = +preauth ; admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab pkinit_identity = FILE:/var/kerberos/krb5kdc/kdc.pem pkinit_anchors = FILE:/var/kerberos/krb5kdc/cacert.pem } freeipa-3.3.4/install/share/ds-nfiles.ldif0000664000175000017500000000025112202434255017773 0ustar mkosekmkosekdn: cn=config changetype: modify replace: nsslapd-maxdescriptors nsslapd-maxdescriptors: $NOFILES - replace: nsslapd-reservedescriptors nsslapd-reservedescriptors: 64 - freeipa-3.3.4/install/share/master-entry.ldif0000664000175000017500000000016212202434255020542 0ustar mkosekmkosekdn: cn=$FQDN,cn=masters,cn=ipa,cn=etc,$SUFFIX changetype: add objectclass: top objectclass: nsContainer cn: $FQDN freeipa-3.3.4/install/share/modrdn-krbprinc.ldif0000664000175000017500000000060412202434255021204 0ustar mkosekmkosek# add plugin configuration for ipauniqueid dn: cn=Kerberos Principal Name,cn=IPA MODRDN,cn=plugins,cn=config changetype: add objectclass: top objectclass: extensibleObject cn: Kerberos Principal Name ipaModRDNsourceAttr: uid ipaModRDNtargetAttr: krbPrincipalName ipaModRDNsuffix: @$REALM ipaModRDNfilter: (&(objectclass=posixaccount)(objectclass=krbPrincipalAux)) ipaModRDNscope: $SUFFIX freeipa-3.3.4/install/share/krbrealm.con.template0000664000175000017500000000006012202434255021357 0ustar mkosekmkosek.$REALM $REALM .$REALM. $REALM $REALM $REALM freeipa-3.3.4/install/share/entryusn.ldif0000664000175000017500000000047512202434255020006 0ustar mkosekmkosekdn: cn=config changetype: modify replace: nsslapd-entryusn-global nsslapd-entryusn-global: on dn: cn=config changetype: modify replace: nsslapd-entryusn-import-initval nsslapd-entryusn-import-initval: next dn: cn=USN,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginenabled nsslapd-pluginenabled: on freeipa-3.3.4/install/share/replica-automember.ldif0000664000175000017500000000056412202434255021673 0ustar mkosekmkosek# Configuration for Auto Membership Plugin for Replica # installation. This method should be revisted for # optimization due to a bug within 389 DS. # dsinstance.py should eventually insert this during common_setup. dn: cn=Auto Membership Plugin,cn=plugins,cn=config changetype: modify add: nsslapd-pluginConfigArea nsslapd-pluginConfigArea: cn=automember,cn=etc,$SUFFIX freeipa-3.3.4/install/share/certmap.conf.template0000664000175000017500000000750012271663206021375 0ustar mkosekmkosek# VERSION 2 - DO NOT REMOVE THIS LINE # # This file is managed by IPA and will be overwritten on upgrades. # BEGIN COPYRIGHT BLOCK # This Program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; version 2 of the License. # # This Program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this Program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301, USA # # In addition, as a special exception, Red Hat, Inc. gives You the additional # right to link the code of this Program with code not covered under the GNU # General Public License ("Non-GPL Code") and to distribute linked combinations # including the two, subject to the limitations in this paragraph. Non-GPL Code # permitted under this exception must only link to the code of this Program # through those well defined interfaces identified in the file named EXCEPTION # found in the source code files (the "Approved Interfaces"). The files of # Non-GPL Code may instantiate templates or use macros or inline functions from # the Approved Interfaces without causing the resulting work to be covered by # the GNU General Public License. Only Red Hat, Inc. may make changes or # additions to the list of Approved Interfaces. You must obey the GNU General # Public License in all respects for all of the Program code and other code used # in conjunction with the Program except the Non-GPL Code covered by this # exception. If you modify this file, you may extend this exception to your # version of the file, but you are not obligated to do so. If you do not wish to # provide this exception without modification, you must delete this exception # statement from your version and license this file solely under the GPL without # exception. # # # Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # END COPYRIGHT BLOCK # # # This file configures how a certificate is mapped to an LDAP entry. See the # documentation for more information on this file. # # The format of this file is as follows: # certmap # : [] # : [] # # Notes: # # 1. Mapping can be defined per issuer of a certificate. If mapping doesn't # exists for a particular 'issuerDN' then the server uses the default # mapping. # # 2. There must be an entry for =default and issuerDN "default". # This mapping is the default mapping. # # 3. '#' can be used to comment out a line. # # 4. DNComps & FilterComps are used to form the base DN and filter resp. for # performing an LDAP search while mapping the cert to a user entry. # # 5. DNComps can be one of the following: # commented out - take the user's DN from the cert as is # empty - search the entire LDAP tree (DN == suffix) # attr names - a comma separated list of attributes to form DN # # 6. FilterComps can be one of the following: # commented out - set the filter to "objectclass=*" # empty - set the filter to "objectclass=*" # attr names - a comma separated list of attributes to form the filter # certmap default default #default:DNComps #default:FilterComps e, uid #default:verifycert on #default:CmapLdapAttr certSubjectDN #default:library #default:InitFn default:DNComps default:FilterComps uid certmap ipaca CN=Certificate Authority,$SUBJECT_BASE ipaca:CmapLdapAttr seeAlso ipaca:verifycert on freeipa-3.3.4/install/share/default-aci.ldif0000664000175000017500000002046312271663206020302 0ustar mkosekmkosek# $SUFFIX (base entry) # FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authenticated users dn: $SUFFIX changetype: modify add: aci aci: (targetfilter = "(&(!(objectClass=ipaToken))(!(objectClass=ipatokenTOTP))(!(objectClass=ipatokenRadiusConfiguration)))")(target != "ldap:///idnsname=*,cn=dns,$SUFFIX")(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || userPKCS12 || ipaNTHash || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";) aci: (targetattr = "memberOf || memberHost || memberUser")(version 3.0; acl "No anonymous access to member information"; deny (read,search,compare) userdn != "ldap:///all";) aci: (targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || 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";) aci: (targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword")(version 3.0; acl "selfservice:Self can write own password"; allow (write) userdn="ldap:///self";) aci: (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";) aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "*")(target = "ldap:///cn=*,ou=SUDOers,$SUFFIX")(version 3.0; acl "No anonymous access to sudo"; deny (read,search,compare) userdn != "ldap:///all";) dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou")(version 3.0;acl "selfservice:User Self service";allow (write) userdn = "ldap:///self";) aci: (targetattr = "ipasshpubkey")(version 3.0;acl "selfservice:Users can manage their own SSH public keys";allow (write) userdn = "ldap:///self";) dn: cn=etc,$SUFFIX changetype: modify add: aci aci: (targetfilter = "(objectClass=ipaGuiConfig)")(targetattr != "aci")(version 3.0;acl "Admins can change GUI config"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) dn: cn=ipa,cn=etc,$SUFFIX changetype: modify add: aci aci: (targetfilter = "(|(objectClass=ipaConfigObject)(dnahostname=*))")(version 3.0;acl "Admins can change GUI config"; allow (delete) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) dn: cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) aci: (targetattr = "aci")(version 3.0;acl "Admins can manage delegations"; allow (write, delete) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) dn: cn=services,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr = "krbPrincipalKey || krbLastPwdChange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "Admins can manage service keytab";allow (write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) # Define which hosts can edit services # The managedby attribute stores the DN of hosts that are allowed to manage # a service. Use service-add-host to add hosts to a service. dn: cn=services,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr="userCertificate || krbPrincipalKey")(version 3.0; acl "Hosts can manage service Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";) # Allow hosts to update their own certificate in host/ # krbLastPwdChange lets a host unenroll itself dn: cn=computers,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr="usercertificate || krblastpwdchange || description || l || nshostlocation || nshardwareplatform || nsosversion")(version 3.0; acl "Hosts can modify their own certs and keytabs"; allow(write) userdn = "ldap:///self";) aci: (targetattr="ipasshpubkey")(version 3.0; acl "Hosts can modify their own SSH public keys"; allow(write) userdn = "ldap:///self";) # Define which hosts can edit other hosts # The managedby attribute stores the DN of hosts that are allowed to manage # another host. dn: cn=computers,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr="userCertificate || krbPrincipalKey")(version 3.0; acl "Hosts can manage other host Certificates and kerberos keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";) aci: (targetattr="ipasshpubkey")(version 3.0; acl "Hosts can manage other host SSH public keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";) dn: cn=computers,cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr = "krbPrincipalKey || krbLastPwdChange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "Admins can manage host keytab";allow (write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";) dn: cn=hbac,$SUFFIX changetype: modify add: aci aci: (targetattr = "*")(version 3.0; acl "No anonymous access to hbac"; deny (read,search,compare) userdn != "ldap:///all";) dn: cn=sudo,$SUFFIX changetype: modify add: aci aci: (targetattr = "*")(version 3.0; acl "No anonymous access to sudo"; deny (read,search,compare) userdn != "ldap:///all";) # This is used for the host/service one-time passwordn and keytab indirectors. # We can do a query on a DN to see if an attribute exists. dn: cn=accounts,$SUFFIX changetype: modify add: aci aci: (targetattr="userPassword || krbPrincipalKey")(version 3.0; acl "Search existence of password and kerberos keys"; allow(search) userdn = "ldap:///all";) # Let host add and update CA renewal certificates dn: cn=ipa,cn=etc,$SUFFIX changetype: modify add: aci aci: (target="ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(version 3.0; acl "Add CA Certificates for renewals"; allow(add) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";) dn: cn=ipa,cn=etc,$SUFFIX changetype: modify add: aci aci: (target="ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(targetattr="userCertificate")(version 3.0; acl "Modify CA Certificates for renewals"; allow(write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";) # Let users manage their own tokens dn: $SUFFIX changetype: modify add: aci aci: (targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";) aci: (targetfilter = "(objectClass=ipaToken)")(targetattrs = "ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";) aci: (targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPclockOffset || ipatokenTOTPtimeStep")(version 3.0; acl "Users can add TOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";) freeipa-3.3.4/install/share/uuid-ipauniqueid.ldif0000664000175000017500000000053612202434255021376 0ustar mkosekmkosek# add plugin configuration for ipauniqueid dn: cn=IPA Unique IDs,cn=IPA UUID,cn=plugins,cn=config changetype: add objectclass: top objectclass: extensibleObject cn: IPA Unique IDs ipaUuidAttr: ipaUniqueID ipaUuidMagicRegen: autogenerate ipaUuidFilter: (|(objectclass=ipaObject)(objectclass=ipaAssociation)) ipaUuidScope: $SUFFIX ipaUuidEnforce: TRUE freeipa-3.3.4/install/share/bind.named.conf.template0000664000175000017500000000227012271663206021740 0ustar mkosekmkosekoptions { // turns on IPv6 for port 53, IPv4 is on by default for all ifaces listen-on-v6 {any;}; // Put files that named is allowed to write in the data/ directory: directory "/var/named"; // the default dump-file "data/cache_dump.db"; statistics-file "data/named_stats.txt"; memstatistics-file "data/named_mem_stats.txt"; forward first; forwarders {$FORWARDERS}; // Any host is permitted to issue recursive queries allow-recursion { any; }; tkey-gssapi-keytab "/etc/named.keytab"; pid-file "/run/named/named.pid"; }; /* If you want to enable debugging, eg. using the 'rndc trace' command, * By default, SELinux policy does not allow named to modify the /var/named directory, * so put the default debug log file in data/ : */ logging { channel default_debug { file "data/named.run"; severity dynamic; print-time yes; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones"; dynamic-db "ipa" { library "ldap.so"; arg "uri ldapi://%2fvar%2frun%2fslapd-$SERVER_ID.socket"; arg "base cn=dns, $SUFFIX"; arg "fake_mname $FQDN."; arg "auth_method sasl"; arg "sasl_mech GSSAPI"; arg "sasl_user DNS/$FQDN"; arg "serial_autoincrement yes"; }; freeipa-3.3.4/install/share/encrypted_attribute.ldif0000664000175000017500000000034312202434255022171 0ustar mkosekmkosekdn: cn=$ENCRYPTED_ATTRIBUTE, cn=encrypted attributes, cn=userRoot, cn=ldbm database, cn=plugins, cn=config changetype: add objectClass: top objectClass: nsAttributeEncryption cn: $ENCRYPTED_ATTRIBUTE nsEncryptionAlgorithm: AES freeipa-3.3.4/install/share/preferences.html.template0000664000175000017500000000601712202434255022256 0ustar mkosekmkosek Automatically set browser preferences
freeipa-3.3.4/install/share/advise/0000775000175000017500000000000012271707664016541 5ustar mkosekmkosekfreeipa-3.3.4/install/share/advise/Makefile.am0000664000175000017500000000031012271663206020560 0ustar mkosekmkosekNULL = SUBDIRS = \ legacy \ $(NULL) appdir = $(IPA_DATA_DIR)/advise app_DATA = \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/share/advise/legacy/0000775000175000017500000000000012271707664020005 5ustar mkosekmkosekfreeipa-3.3.4/install/share/advise/legacy/pam_conf_sshd.template0000664000175000017500000000214612271663206024341 0ustar mkosekmkosek# PAM configuration for the "sshd" service # # auth auth sufficient pam_opie.so no_warn no_fake_prompts auth requisite pam_opieaccess.so no_warn allow_local #auth sufficient pam_krb5.so no_warn try_first_pass #auth sufficient pam_ssh.so no_warn try_first_pass auth sufficient /usr/local/lib/pam_ldap.so no_warn auth required pam_unix.so no_warn try_first_pass # account account required pam_nologin.so #account required pam_krb5.so account required /usr/local/lib/pam_ldap.so no_warn ignore_authinfo_unavail ignore_unknown_user account required pam_login_access.so account required pam_unix.so # session #session optional pam_ssh.so want_agent session required pam_permit.so # password #password sufficient pam_krb5.so no_warn try_first_pass password required pam_unix.so no_warn try_first_pass freeipa-3.3.4/install/share/advise/legacy/pam.conf.nss_pam_ldapd.template0000664000175000017500000000176512271663206026050 0ustar mkosekmkosekauth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth sufficient pam_ldap.so use_first_pass auth required pam_deny.so account required pam_unix.so broken_shadow account sufficient pam_localuser.so account sufficient pam_succeed_if.so uid < 500 quiet account [default=bad success=ok user_unknown=ignore] pam_ldap.so account required pam_permit.so password requisite pam_cracklib.so try_first_pass retry=3 type= password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok password sufficient pam_ldap.so use_authtok password required pam_deny.so session optional pam_keyinit.so revoke session required pam_limits.so session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid session required pam_unix.so session optional pam_ldap.so freeipa-3.3.4/install/share/advise/legacy/Makefile.am0000664000175000017500000000043012271663206022027 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/advise/legacy app_DATA = \ sssd.conf.template \ pam.conf.sssd.template \ pam.conf.nss_pam_ldapd.template \ pam_conf_sshd.template \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/share/advise/legacy/pam.conf.sssd.template0000664000175000017500000000176112271663206024214 0ustar mkosekmkosekauth required pam_env.so auth sufficient pam_unix.so nullok try_first_pass auth requisite pam_succeed_if.so uid >= 500 quiet auth sufficient pam_sss.so use_first_pass auth required pam_deny.so account required pam_unix.so broken_shadow account sufficient pam_localuser.so account sufficient pam_succeed_if.so uid < 500 quiet account [default=bad success=ok user_unknown=ignore] pam_sss.so account required pam_permit.so password requisite pam_cracklib.so try_first_pass retry=3 type= password sufficient pam_unix.so sha512 shadow nullok try_first_pass use_authtok password sufficient pam_sss.so use_authtok password required pam_deny.so session optional pam_keyinit.so revoke session required pam_limits.so session [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid session required pam_unix.so session optional pam_sss.so freeipa-3.3.4/install/share/advise/legacy/Makefile.in0000664000175000017500000003214112271707662022051 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = share/advise/legacy DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/advise/legacy app_DATA = \ sssd.conf.template \ pam.conf.sssd.template \ pam.conf.nss_pam_ldapd.template \ pam_conf_sshd.template \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/advise/legacy/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/advise/legacy/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/share/advise/legacy/sssd.conf.template0000664000175000017500000000041612271663206023434 0ustar mkosekmkosek[sssd] services = nss, pam config_file_version = 2 domains = default re_expression = (?P.+) [domain/default] cache_credentials = True id_provider = ldap auth_provider = ldap ldap_uri = $URI ldap_search_base = $BASE ldap_tls_cacert = /etc/openldap/cacerts/ipa.crt freeipa-3.3.4/install/share/advise/Makefile.in0000664000175000017500000004634412271707662020617 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = share/advise DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = SUBDIRS = \ legacy \ $(NULL) appdir = $(IPA_DATA_DIR)/advise app_DATA = \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/advise/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/advise/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-appDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-appDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/share/repoint-managed-entries.ldif0000664000175000017500000000034112202434255022630 0ustar mkosekmkosek# Repoint Managed Entries to the replicated cn=etc space dn: cn=Managed Entries,cn=plugins,cn=config changetype: modify add: nsslapd-pluginConfigArea nsslapd-pluginConfigArea: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX freeipa-3.3.4/install/share/anonymous-vlv.ldif0000664000175000017500000000040712202434255020747 0ustar mkosekmkosek# Needed to enable automount browsing on Solaris dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config changetype: modify add: aci aci: (targetattr !="aci")\ (version 3.0; acl "VLV Request Control"; allow (compare,read,search) \ userdn = "ldap:///anyone"; ) freeipa-3.3.4/install/share/Makefile.am0000664000175000017500000000313212271663206017312 0ustar mkosekmkosekNULL = SUBDIRS = \ advise \ $(NULL) appdir = $(IPA_DATA_DIR) app_DATA = \ 05rfc2247.ldif \ 60kerberos.ldif \ 60samba.ldif \ 60ipaconfig.ldif \ 60basev2.ldif \ 60basev3.ldif \ 60ipadns.ldif \ 61kerberos-ipav3.ldif \ 65ipasudo.ldif \ 70ipaotp.ldif \ anonymous-vlv.ldif \ bootstrap-template.ldif \ caJarSigningCert.cfg.template \ default-aci.ldif \ default-hbac.ldif \ default-smb-group.ldif \ delegation.ldif \ disable-betxn.ldif \ replica-acis.ldif \ ds-nfiles.ldif \ dns.ldif \ kerberos.ldif \ indices.ldif \ bind.named.conf.template \ bind.zone.db.template \ certmap.conf.template \ kdc.conf.template \ kdc_extensions.template \ kdc_req.conf.template \ krb5.conf.template \ krb5.ini.template \ krb.con.template \ krb.js.template \ krbrealm.con.template \ preferences.html.template \ smb.conf.template \ smb.conf.empty \ referint-conf.ldif \ dna.ldif \ master-entry.ldif \ memberof-task.ldif \ memberof-conf.ldif \ nis.uldif \ unique-attributes.ldif \ schema_compat.uldif \ ldapi.ldif \ wsgi.py \ repoint-managed-entries.ldif \ managed-entries.ldif \ user_private_groups.ldif \ host_nis_groups.ldif \ uuid-ipauniqueid.ldif \ modrdn-krbprinc.ldif \ entryusn.ldif \ root-autobind.ldif \ sudobind.ldif \ automember.ldif \ replica-automember.ldif \ replica-s4u2proxy.ldif \ copy-schema-to-ca.py \ upload-cacert.ldif \ sasl-mapping-fallback.ldif \ schema-update.ldif \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/share/kerberos.ldif0000664000175000017500000000271112271663206017734 0ustar mkosekmkosek#kerberos base object dn: cn=kerberos,$SUFFIX changetype: add objectClass: krbContainer objectClass: top cn: kerberos #Realm base object dn: cn=$REALM,cn=kerberos,$SUFFIX changetype: add cn: $REALM objectClass: top objectClass: krbrealmcontainer objectClass: krbticketpolicyaux krbSubTrees: $SUFFIX krbSearchScope: 2 krbSupportedEncSaltTypes: aes256-cts:normal krbSupportedEncSaltTypes: aes256-cts:special krbSupportedEncSaltTypes: aes128-cts:normal krbSupportedEncSaltTypes: aes128-cts:special krbSupportedEncSaltTypes: des3-hmac-sha1:normal krbSupportedEncSaltTypes: des3-hmac-sha1:special krbSupportedEncSaltTypes: arcfour-hmac:normal krbSupportedEncSaltTypes: arcfour-hmac:special krbSupportedEncSaltTypes: camellia128-cts-cmac:normal krbSupportedEncSaltTypes: camellia128-cts-cmac:special krbSupportedEncSaltTypes: camellia256-cts-cmac:normal krbSupportedEncSaltTypes: camellia256-cts-cmac:special krbMaxTicketLife: 86400 krbMaxRenewableAge: 604800 krbDefaultEncSaltTypes: aes256-cts:special krbDefaultEncSaltTypes: aes128-cts:special krbDefaultEncSaltTypes: des3-hmac-sha1:special krbDefaultEncSaltTypes: arcfour-hmac:special # Default password Policy dn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX changetype: add objectClass: top objectClass: nsContainer objectClass: krbPwdPolicy krbMinPwdLife: 3600 krbPwdMinDiffChars: 0 krbPwdMinLength: 8 krbPwdHistoryLength: 0 krbMaxPwdLife: 7776000 krbPwdMaxFailure: 6 krbPwdFailureCountInterval: 60 krbPwdLockoutDuration: 600 freeipa-3.3.4/install/share/05rfc2247.ldif0000664000175000017500000000670412271663206017364 0ustar mkosekmkosek# # BEGIN COPYRIGHT BLOCK # This Program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; version 2 of the License. # # This Program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this Program; if not, write to the Free Software Foundation, Inc., 51 Franklin # Street, Fifth Floor, Boston, MA 02110-1301, USA # # In addition, as a special exception, Red Hat, Inc. gives You the additional # right to link the code of this Program with code not covered under the GNU # General Public License ("Non-GPL Code") and to distribute linked combinations # including the two, subject to the limitations in this paragraph. Non-GPL Code # permitted under this exception must only link to the code of this Program # through those well defined interfaces identified in the file named EXCEPTION # found in the source code files (the "Approved Interfaces"). The files of # Non-GPL Code may instantiate templates or use macros or inline functions from # the Approved Interfaces without causing the resulting work to be covered by # the GNU General Public License. Only Red Hat, Inc. may make changes or # additions to the list of Approved Interfaces. You must obey the GNU General # Public License in all respects for all of the Program code and other code used # in conjunction with the Program except the Non-GPL Code covered by this # exception. If you modify this file, you may extend this exception to your # version of the file, but you are not obligated to do so. If you do not wish to # provide this exception without modification, you must delete this exception # statement from your version and license this file solely under the GPL without # exception. # # # Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. # Copyright (C) 2005 Red Hat, Inc. # All rights reserved. # END COPYRIGHT BLOCK # # # Schema from RFC 2247 and related pilot schema # "Using Domains in LDAP/X.500 Distinguished Names" # dn: cn=schema attributeTypes: ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domaincomponent' ) DESC 'Standard LDAP attribute type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2247' ) attributeTypes: ( 0.9.2342.19200300.100.1.38 NAME 'associatedName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' ) objectClasses: ( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST dc X-ORIGIN 'RFC 2247' ) objectClasses: ( 0.9.2342.19200300.100.4.13 NAME 'domain' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST dc MAY ( associatedName $ businessCategory $ description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ o $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ searchGuide $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ userPassword $ x121Address ) X-ORIGIN 'RFC 2247' ) objectClasses: ( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart' DESC 'Pilot objectclass' SUP domain MAY ( cn $ sn ) X-ORIGIN 'Internet directory pilot' ) freeipa-3.3.4/install/share/krb5.ini.template0000664000175000017500000000073212202434255020431 0ustar mkosekmkosek[libdefaults] default_realm = $REALM krb4_config = /usr/kerberos/lib/krb.conf krb4_realms = /usr/kerberos/lib/krb.realms dns_lookup_kdc = true [realms] $REALM = { admin_server = $FQDN kdc = $FQDN master_kdc = $FQDN default_domain = $REALM } [domain_realm] .$DOMAIN = $REALM $DOMAIN = $REALM [logging] # kdc = CONSOLE freeipa-3.3.4/install/share/copy-schema-to-ca.py0000775000175000017500000000463312271663206021053 0ustar mkosekmkosek#! /usr/bin/python """Copy the IPA schema to the CA directory server instance You need to run this script to prepare a 2.2 or 3.0 IPA master for installation of a 3.1 replica. Once a 3.1 replica is in the domain, every older CA master will emit schema replication errors until this script is run on it. """ import os import sys import pwd import shutil from ipapython import services, ipautil, dogtag from ipapython.ipa_log_manager import root_logger, standard_logging_setup from ipaserver.install.dsinstance import DS_USER, schema_dirname from ipaserver.install.cainstance import PKI_USER from ipalib import api SERVERID = "PKI-IPA" SCHEMA_FILENAMES = ( "60kerberos.ldif", "60samba.ldif", "60ipaconfig.ldif", "60basev2.ldif", "60basev3.ldif", "60ipadns.ldif", "61kerberos-ipav3.ldif", "65ipasudo.ldif", "70ipaotp.ldif", "05rfc2247.ldif", ) def add_ca_schema(): """Copy IPA schema files into the CA DS instance """ pki_pent = pwd.getpwnam(PKI_USER) ds_pent = pwd.getpwnam(DS_USER) for schema_fname in SCHEMA_FILENAMES: source_fname = os.path.join(ipautil.SHARE_DIR, schema_fname) target_fname = os.path.join(schema_dirname(SERVERID), schema_fname) if not os.path.exists(source_fname): root_logger.debug('File does not exist: %s', source_fname) continue if os.path.exists(target_fname): root_logger.info( 'Target exists, not overwriting: %s', target_fname) continue try: shutil.copyfile(source_fname, target_fname) except IOError, e: root_logger.warning('Could not install %s: %s', target_fname, e) else: root_logger.info('Installed %s', target_fname) os.chmod(target_fname, 0440) # read access for dirsrv user/group os.chown(target_fname, pki_pent.pw_uid, ds_pent.pw_gid) def restart_pki_ds(): """Restart the CA DS instance to pick up schema changes """ root_logger.info('Restarting CA DS') services.service('dirsrv').restart(SERVERID) def main(): if os.getegid() != 0: sys.exit("Must be root to run this script") standard_logging_setup(verbose=True) # In 3.0, restarting needs access to api.env (options, argv) = api.bootstrap_with_global_options(context='server') add_ca_schema() restart_pki_ds() root_logger.info('Schema updated successfully') main() freeipa-3.3.4/install/share/60basev2.ldif0000664000175000017500000002045412271663206017454 0ustar mkosekmkosek## IPA Base OID: 2.16.840.1.113730.3.8 ## ## Attributes: 2.16.840.1.113730.3.8.3 - V2 base attributres ## ObjectClasses: 2.16.840.1.113730.3.8.4 - V2 base objectclasses ## dn: cn=schema attributeTypes: (2.16.840.1.113730.3.8.3.1 NAME 'ipaUniqueID' DESC 'Unique identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch 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.2 NAME 'ipaClientVersion' DESC 'Text string describing client version of the IPA software installed' 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.3 NAME 'enrolledBy' DESC 'DN of administrator who performed manual enrollment of the host' SUP distinguishedName X-ORIGIN 'IPA v2' ) 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 $ userClass ) 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 $ 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' ) attributeTypes: (2.16.840.1.113730.3.8.3.5 NAME 'memberUser' DESC 'Reference to a principal that performs an action (usually user).' SUP distinguishedName X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.6 NAME 'userCategory' DESC 'Additional classification for users' 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.7 NAME 'memberHost' DESC 'Reference to a device where the operation takes place (usually host).' SUP distinguishedName X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.8 NAME 'hostCategory' DESC 'Additional classification for hosts' 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.19 NAME 'serviceCategory' DESC 'Additional classification for services' 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.20 NAME 'memberService' DESC 'Reference to the pam service of this operation.' SUP distinguishedName X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.25 NAME 'ipaPermissionType' DESC 'IPA permission flags' 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.9 NAME 'ipaEnabledFlag' DESC 'The flag to show if the association is active or should be ignored' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.6 NAME 'ipaAssociation' ABSTRACT MUST ( ipaUniqueID $ cn ) MAY ( memberUser $ userCategory $ memberHost $ hostCategory $ ipaEnabledFlag $ description ) X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.10 NAME 'sourceHost' DESC 'Link to a host or group of hosts' SUP memberHost SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.11 NAME 'externalHost' DESC 'Multivalue string attribute that allows storing host names.' 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.12 NAME 'sourceHostCategory' DESC 'Additional classification for hosts' 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.13 NAME 'accessRuleType' DESC 'The flag to represent if it is allow or deny rule.' 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.14 NAME 'accessTime' DESC 'Access time' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.7 NAME 'ipaHBACRule' SUP ipaAssociation STRUCTURAL MUST accessRuleType MAY ( sourceHost $ sourceHostCategory $ serviceCategory $ memberService $ externalHost $ accessTime ) X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.3.15 NAME 'nisDomainName' DESC 'NIS domain name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.8 NAME 'ipaNISNetgroup' DESC 'IPA version of NIS netgroup' SUP ipaAssociation STRUCTURAL MAY ( externalHost $ nisDomainName $ member $ memberOf ) X-ORIGIN 'IPA v2' ) attributeTypes: (1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'automount Map Name' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307bis' ) attributeTypes: (1.3.6.1.1.1.1.32 NAME 'automountKey' DESC 'Automount Key value' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307bis' ) attributeTypes: (1.3.6.1.1.1.1.33 NAME 'automountInformation' DESC 'Automount information' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307bis' ) objectClasses: (1.3.6.1.1.1.2.16 NAME 'automountMap' DESC 'Automount Map information' SUP top STRUCTURAL MUST automountMapName MAY description X-ORIGIN 'RFC 2307bis' ) objectClasses: (1.3.6.1.1.1.2.17 NAME 'automount' DESC 'Automount information' SUP top STRUCTURAL MUST ( automountKey $ automountInformation ) MAY description X-ORIGIN 'RFC 2307bis' ) attributeTypes: (2.16.840.1.113730.3.8.3.17 NAME 'hostCApolicy' DESC 'Policy on how to treat host requests for cert operations.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.9 NAME 'ipaCAaccess' STRUCTURAL MAY (member $ hostCApolicy) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.10 NAME 'ipaHBACService' STRUCTURAL MUST ( cn ) MAY ( description $ memberOf ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.4.11 NAME 'ipaHBACServiceGroup' DESC 'IPA HBAC service group object class' SUP groupOfNames STRUCTURAL X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/share/wsgi.py0000664000175000017500000000345112202434255016577 0ustar mkosekmkosek# Authors: # Rob Crittenden # Jason Gerard DeRose # John Dennis # # Copyright (C) 2010 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 . # """ WSGI appliction for IPA server. """ from ipalib import api from ipalib.config import Env from ipalib.constants import DEFAULT_CONFIG # Determine what debug level is configured. We can only do this # by reading in the configuration file(s). The server always reads # default.conf and will also read in `context'.conf. env = Env() env._bootstrap(context='server', log=None) env._finalize_core(**dict(DEFAULT_CONFIG)) # Initialize the API with the proper debug level api.bootstrap(context='server', debug=env.debug, log=None) try: api.finalize() except StandardError, e: api.log.error('Failed to start IPA: %s' % e) else: api.log.info('*** PROCESS START ***') # This is the WSGI callable: def application(environ, start_response): if not environ['wsgi.multithread']: return api.Backend.wsgi_dispatch(environ, start_response) else: api.log.error("IPA does not work with the threaded MPM, use the pre-fork MPM") freeipa-3.3.4/install/share/referint-conf.ldif0000664000175000017500000000143512202434255020655 0ustar mkosekmkosekdn: cn=referential integrity postoperation,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginenabled nsslapd-pluginenabled: on - add: nsslapd-pluginArg7 nsslapd-pluginArg7: manager - add: nsslapd-pluginArg8 nsslapd-pluginArg8: secretary - add: nsslapd-pluginArg9 nsslapd-pluginArg9: memberuser - add: nsslapd-pluginArg10 nsslapd-pluginArg10: memberhost - add: nsslapd-pluginArg11 nsslapd-pluginArg11: sourcehost - add: nsslapd-pluginArg12 nsslapd-pluginArg12: memberservice - add: nsslapd-pluginArg13 nsslapd-pluginArg13: managedby - add: nsslapd-pluginArg14 nsslapd-pluginArg14: memberallowcmd - add: nsslapd-pluginArg15 nsslapd-pluginArg15: memberdenycmd - add: nsslapd-pluginArg16 nsslapd-pluginArg16: ipasudorunas - add: nsslapd-pluginArg17 nsslapd-pluginArg17: ipasudorunasgroup freeipa-3.3.4/install/share/smb.conf.template0000664000175000017500000000146112271663206020523 0ustar mkosekmkosek[global] workgroup = $NETBIOS_NAME netbios name = $HOST_NETBIOS_NAME realm = $REALM kerberos method = dedicated keytab dedicated keytab file = FILE:/etc/samba/samba.keytab create krb5 conf = no security = user domain master = yes domain logons = yes log level = 1 max log size = 100000 log file = /var/log/samba/log.%m passdb backend = ipasam:ldapi://$LDAPI_SOCKET disable spoolss = yes ldapsam:trusted=yes ldap ssl = off ldap suffix = $SUFFIX ldap user suffix = cn=users,cn=accounts ldap group suffix = cn=groups,cn=accounts ldap machine suffix = cn=computers,cn=accounts rpc_server:epmapper = external rpc_server:lsarpc = external rpc_server:lsass = external rpc_server:lsasd = external rpc_server:samr = external rpc_server:netlogon = external rpc_server:tcpip = yes rpc_daemon:epmd = fork rpc_daemon:lsasd = fork freeipa-3.3.4/install/share/sudobind.ldif0000664000175000017500000000034412202434255017721 0ustar mkosekmkosek#SUDO bind user dn: uid=sudo,cn=sysaccounts,cn=etc,$SUFFIX changetype: add objectclass: account objectclass: simplesecurityobject uid: sudo userPassword: $RANDOM_PASSWORD passwordExpirationTime: 20380119031407Z nsIdleTimeout: 0 freeipa-3.3.4/install/share/kdc_req.conf.template0000664000175000017500000000042712202434255021345 0ustar mkosekmkosek[ req ] default_bits = 2048 distinguished_name = req_distinguished_name attributes = req_attributes prompt = no output_password = $PASSWORD [ req_distinguished_name ] $SUBJBASE $CERTNAME [ req_attributes ] challengePassword = A challenge password freeipa-3.3.4/install/share/delegation.ldif0000664000175000017500000007270412271663206020244 0ustar mkosekmkosek############################################ # Configure the DIT ############################################ dn: cn=roles,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: roles # Permissions-based Access Control dn: cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: pbac dn: cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: privileges dn: cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: permissions ############################################ # Add the default roles ############################################ dn: cn=helpdesk,cn=roles,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: helpdesk description: Helpdesk ############################################ # Add the default privileges ############################################ dn: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: User Administrators description: User Administrators dn: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Group Administrators description: Group Administrators dn: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Host Administrators description: Host Administrators dn: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Host Group Administrators description: Host Group Administrators dn: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Delegation Administrator description: Role administration dn: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Service Administrators description: Service Administrators dn: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Automount Administrators description: Automount Administrators dn: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Netgroups Administrators description: Netgroups Administrators dn: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Certificate Administrators description: Certificate Administrators dn: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Replication Administrators description: Replication Administrators member: cn=admins,cn=groups,cn=accounts,$SUFFIX dn: cn=Host Enrollment,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: Host Enrollment description: Host Enrollment ############################################ # Default permissions. ############################################ # User administration dn: cn=Add Users,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Users member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Change a user password member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add user to default group,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add user to default group member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Unlock user accounts,cn=permissions,cn=pbac,$SUFFIX changetype: add objectclass: top objectclass: groupofnames objectClass: ipapermission cn: Unlock user accounts member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=admins,cn=groups,cn=accounts,$SUFFIX dn: cn=Remove Users,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Users member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Users member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage User SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Manage User SSH Public Keys member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX # Group administration dn: cn=Add Groups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Groups member: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Groups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Groups member: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Groups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Groups member: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Group membership member: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX # Host administration dn: cn=Add Hosts,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Hosts member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Hosts,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Hosts member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Hosts,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Hosts member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage Host SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Manage Host SSH Public Keys member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX # Hostgroup administration dn: cn=Add Hostgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Hostgroups member: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Hostgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Hostgroups member: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Hostgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Hostgroups member: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Hostgroup membership,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Hostgroup membership member: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX # Service administration dn: cn=Add Services,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Services member: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Services,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Services member: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Services,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Services member: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX # Delegation administration dn: cn=Add Roles,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Roles member: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Roles,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Roles member: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Roles,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Roles member: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Role membership,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Role membership member: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify privilege membership,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify privilege membership member: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX # Automount administration dn: cn=Add Automount maps,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Automount maps member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Automount maps,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames 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 objectClass: groupofnames 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 objectClass: groupofnames objectClass: ipapermission cn: Remove Automount keys member: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX # Netgroup administration dn: cn=Add netgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add netgroups member: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove netgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove netgroups member: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify netgroups,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify netgroups member: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify netgroup membership,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify netgroup membership member: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX # Keytab access dn: cn=Manage host keytab,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Manage host keytab member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=Host Enrollment,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage service keytab,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Manage service keytab member: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=admins,cn=groups,cn=accounts,$SUFFIX # DNS administration # The permission and aci for this is in install/updates/dns.ldif dn: cn=Enroll a host,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Enroll a host member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=Host Enrollment,cn=privileges,cn=pbac,$SUFFIX # Replica administration dn: cn=Add Replication Agreements,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Add Replication Agreements ipapermissiontype: SYSTEM member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Replication Agreements,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify Replication Agreements ipapermissiontype: SYSTEM member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove Replication Agreements,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Remove Replication Agreements ipapermissiontype: SYSTEM member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify DNA Range,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Modify DNA Range ipapermissiontype: SYSTEM member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX ############################################ # Default permissions (ACIs) ############################################ # User administration dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Users";allow (add) groupdn = "ldap:///cn=Add Users,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetfilter = "(!(memberOf=cn=admins,cn=groups,cn=accounts,$SUFFIX))")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "krbLastAdminUnlock || krbLoginFailedCount")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Unlock user accounts";allow (write) groupdn = "ldap:///cn=Unlock user accounts,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "member")(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add user to default group";allow (write) groupdn = "ldap:///cn=Add user to default group,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Users";allow (delete) groupdn = "ldap:///cn=Remove Users,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Users";allow (write) groupdn = "ldap:///cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "ipasshpubkey")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage User SSH Public Keys";allow (write) groupdn = "ldap:///cn=Manage User SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX";) # Group administration dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Groups";allow (add) groupdn = "ldap:///cn=Add Groups,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetfilter = "(!(cn=admins))")(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Groups";allow (delete) groupdn = "ldap:///cn=Remove Groups,cn=permissions,cn=pbac,$SUFFIX";) # We need objectclass and gidnumber in modify so a non-posix group can be # promoted. We need mqpManagedBy and ipaUniqueId so a group can be detached. aci: (targetattr = "cn || description || gidnumber || objectclass || mepmanagedby || ipauniqueid")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Groups";allow (write) groupdn = "ldap:///cn=Modify Groups,cn=permissions,cn=pbac,$SUFFIX";) # Host administration dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Hosts";allow (add) groupdn = "ldap:///cn=Add Hosts,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Hosts";allow (delete) groupdn = "ldap:///cn=Remove Hosts,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "description || l || nshostlocation || nshardwareplatform || nsosversion")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Hosts";allow (write) groupdn = "ldap:///cn=Modify Hosts,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "ipasshpubkey")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage Host SSH Public Keys";allow (write) groupdn = "ldap:///cn=Manage Host SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX";) # Hostgroup administration dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Hostgroups";allow (add) groupdn = "ldap:///cn=Add Hostgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Hostgroups";allow (delete) groupdn = "ldap:///cn=Remove Hostgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0; acl "permission:Modify Hostgroups";allow (write) groupdn = "ldap:///cn=Modify Hostgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "member")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Hostgroup membership";allow (write) groupdn = "ldap:///cn=Modify Hostgroup membership,cn=permissions,cn=pbac,$SUFFIX";) # Service administration dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Services";allow (add) groupdn = "ldap:///cn=Add Services,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Services";allow (delete) groupdn = "ldap:///cn=Remove Services,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "usercertificate")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Services";allow (write) groupdn = "ldap:///cn=Modify Services,cn=permissions,cn=pbac,$SUFFIX";) # Delegation administration dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "*")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX")(version 3.0; acl "No anonymous access to roles"; deny (read,search,compare) userdn != "ldap:///all";) dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Roles";allow (add) groupdn = "ldap:///cn=Add Roles,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Roles";allow (delete) groupdn = "ldap:///cn=Remove Roles,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "cn || description")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX")(version 3.0; acl "permission:Modify Roles";allow (write) groupdn = "ldap:///cn=Modify Roles,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "member")(target = "ldap:///cn=*,cn=roles,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Role membership";allow (write) groupdn = "ldap:///cn=Modify Role membership,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "member")(target = "ldap:///cn=*,cn=permissions,cn=pbac,$SUFFIX")(version 3.0;acl "permission:Modify privilege membership";allow (write) groupdn = "ldap:///cn=Modify privilege membership,cn=permissions,cn=pbac,$SUFFIX";) # Automount administration dn: $SUFFIX 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: (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 dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Add netgroups";allow (add) groupdn = "ldap:///cn=Add netgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Remove netgroups";allow (delete) groupdn = "ldap:///cn=Remove netgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "description")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0; acl "permission:Modify netgroups";allow (write) groupdn = "ldap:///cn=Modify netgroups,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "memberhost || externalhost || memberuser || member")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Modify netgroup membership";allow (write) groupdn = "ldap:///cn=Modify netgroup membership,cn=permissions,cn=pbac,$SUFFIX";) # Host keytab admin dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage host keytab";allow (write) groupdn = "ldap:///cn=Manage host keytab,cn=permissions,cn=pbac,$SUFFIX";) # Service keytab admin dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage service keytab";allow (write) groupdn = "ldap:///cn=Manage service keytab,cn=permissions,cn=pbac,$SUFFIX";) # Add the ACI needed to do host enrollment. When this occurs we # set the krbPrincipalName, add krbPrincipalAux to objectClass and # set enrolledBy to whoever ran join. enrolledBy is specifically # not listed here, it is set by the plugin but we don't want an # admin overriding it using --setattr or ldapmodify. dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Enroll a host";allow (write) groupdn = "ldap:///cn=Enroll a host,cn=permissions,cn=pbac,$SUFFIX";) # Create virtual operations entry. This is used to control access to # operations that don't rely on LDAP directly. dn: cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: virtual operations # Retrieve Certificate virtual op dn: cn=retrieve certificate,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: retrieve certificate dn: cn=Retrieve Certificates from the CA,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Retrieve Certificates from the CA member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=retrieve certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Retrieve Certificates from the CA" ; allow (write) groupdn = "ldap:///cn=Retrieve Certificates from the CA,cn=permissions,cn=pbac,$SUFFIX";) # Request Certificate virtual op dn: cn=request certificate,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: request certificate dn: cn=Request Certificate,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Request Certificate member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Request Certificate" ; allow (write) groupdn = "ldap:///cn=Request Certificate,cn=permissions,cn=pbac,$SUFFIX";) # Request Certificate from different host virtual op dn: cn=request certificate different host,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: request certificate different host dn: cn=Request Certificates from a different host,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Request Certificates from a different host member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=request certificate different host,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Request Certificates from a different host" ; allow (write) groupdn = "ldap:///cn=Request Certificates from a different host,cn=permissions,cn=pbac,$SUFFIX";) # Certificate Status virtual op dn: cn=certificate status,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: certificate status dn: cn=Get Certificates status from the CA,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Get Certificates status from the CA member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate status,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Get Certificates status from the CA" ; allow (write) groupdn = "ldap:///cn=Get Certificates status from the CA,cn=permissions,cn=pbac,$SUFFIX";) # Revoke Certificate virtual op dn: cn=revoke certificate,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: revoke certificate dn: cn=Revoke Certificate,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Revoke Certificate member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=revoke certificate,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Revoke Certificate"; allow (write) groupdn = "ldap:///cn=Revoke Certificate,cn=permissions,cn=pbac,$SUFFIX";) # Certificate Remove Hold virtual op dn: cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: certificate remove hold dn: cn=Certificate Remove Hold,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Certificate Remove Hold member: cn=Certificate Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX changetype: modify add: aci aci: (targetattr = "objectclass")(target = "ldap:///cn=certificate remove hold,cn=virtual operations,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Certificate Remove Hold"; allow (write) groupdn = "ldap:///cn=Certificate Remove Hold,cn=permissions,cn=pbac,$SUFFIX";) freeipa-3.3.4/install/share/60samba.ldif0000664000175000017500000004133612270466515017362 0ustar mkosekmkosek## schema file for Fedora/RedHat Directory Server ## ## NOTE: this file can be copied as 60samba.ldif into your instance schema ## directory: ## cp samba-schema-FDS.ldif /etc/dirsrv/slapd-/schema/60schema.ldif ## ## Schema for storing Samba user accounts and group maps in LDAP ## OIDs are owned by the Samba Team ## ## Prerequisite schemas - uid (cosine.schema) ## - displayName (inetorgperson.schema) ## - gidNumber (nis.schema) ## ## 1.3.6.1.4.1.7165.2.1.x - attributeTypess ## 1.3.6.1.4.1.7165.2.2.x - objectClasseses ## ## Printer support ## 1.3.6.1.4.1.7165.2.3.1.x - attributeTypess ## 1.3.6.1.4.1.7165.2.3.2.x - objectClasseses ## ## Samba4 ## 1.3.6.1.4.1.7165.4.1.x - attributeTypess ## 1.3.6.1.4.1.7165.4.2.x - objectClasseses ## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls ## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations ## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track ## dn: cn=schema ## ####################################################################### ## Attributes used by Samba 3.0 schema ## ####################################################################### ## ## Password hashes## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE ) ## ## Account flags in string format ([UWDX ]) ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE ) ## ## Password timestamps & policies ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE ) ## ## string settings ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} ) ## ## SID, of any type ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) ## ## Primary group SID, compatible with ntSid ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) ## ## group mapping attributes ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) ## ## Store info on the domain ## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) ##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName' ## SUP name ) ## ##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList' ## DESC 'Privileges List' ## EQUALITY caseIgnoreIA5Match ## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} ) attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) # "min password length" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "password history" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "user must logon to change password" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "maximum password age" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "minimum password age" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "lockout duration" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "reset count minutes" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "bad lockout attempt" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "disconnect time" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # "refuse machine password change" attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' DESC 'Previous clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) # attributeTypes: ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) ## ####################################################################### ## objectClasses: used by Samba 3.0 schema ## ####################################################################### ## ## The X.500 data model (and therefore LDAPv3) says that each entry can ## only have one structural objectClasses. OpenLDAP 2.0 does not enforce ## this currently but will in v2.1 ## ## added new objectClasses: (and OID) for 3.0 to help us deal with backwards ## compatibility with 2.2 installations (e.g. ldapsam_compat) --jerry ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY DESC 'Samba 3.0 Auxilary SAM Account' MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours)) ## ## Group mapping info ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList )) ## ## Trust password for trust relationships (any kind) ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL DESC 'Samba Trust Password' MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet )) ## ## Whole-of-domain info ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange )) ## ## used for idmap_ldap module ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) ) objectClasses: ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY DESC 'Mapping from a SID to an ID' MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ) ) objectClasses: ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL DESC 'Structural Class for a SID' MUST ( sambaSID ) ) objectClasses: ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY DESC 'Samba Configuration Section' MAY ( description ) ) objectClasses: ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL DESC 'Samba Share Section' MUST ( sambaShareName ) MAY ( description ) ) objectClasses: ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL DESC 'Samba Configuration Option' MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ) ) ## retired during privilege rewrite ##objectClasses: ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY ## DESC 'Samba Privilege' ## MUST ( sambaSID ) ## MAY ( sambaPrivilegeList ) ) ## ## Trusted Domain Relationships ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL DESC 'Samba Trusted Domain Password' MUST ( sambaDomainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY ( sambaPreviousClearTextPassword ) ) ## ## used for IPA_ldapsam ## objectClasses: ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes) ) freeipa-3.3.4/install/share/smb.conf.empty0000664000175000017500000000001212202434255020027 0ustar mkosekmkosek[global] freeipa-3.3.4/install/share/host_nis_groups.ldif0000664000175000017500000000151412202434255021337 0ustar mkosekmkosekdn: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectclass: mepTemplateEntry cn: NGP HGP Template mepRDNAttr: cn mepStaticAttr: ipaUniqueId: autogenerate mepStaticAttr: objectclass: ipanisnetgroup mepStaticAttr: objectclass: ipaobject mepStaticAttr: nisDomainName: $DOMAIN mepMappedAttr: cn: $$cn mepMappedAttr: memberHost: $$dn mepMappedAttr: description: ipaNetgroup $$cn # Changes to this definition need to be reflected in # updates/20-host_nis_groups.update dn: cn=NGP Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectclass: extensibleObject cn: NGP Definition originScope: cn=hostgroups,cn=accounts,$SUFFIX originFilter: objectclass=ipahostgroup managedBase: cn=ng,cn=alt,$SUFFIX managedTemplate: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX freeipa-3.3.4/install/share/dna.ldif0000664000175000017500000000077012271663206016665 0ustar mkosekmkosek# add plugin configuration for user private groups dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config changetype: add objectclass: top objectclass: extensibleObject cn: Posix IDs dnaType: uidNumber dnaType: gidNumber dnaNextValue: eval($IDSTART) dnaMaxValue: eval($IDMAX) dnaMagicRegen: -1 dnaFilter: (|(objectClass=posixAccount)(objectClass=posixGroup)(objectClass=ipaIDobject)) dnaScope: $SUFFIX dnaThreshold: 500 dnaSharedCfgDN: cn=posix-ids,cn=dna,cn=ipa,cn=etc,$SUFFIX freeipa-3.3.4/install/share/schema_compat.uldif0000664000175000017500000001644012271663206021114 0ustar mkosekmkosek# # Enable the Schema Compatibility plugin provided by slapi-nis. # # http://slapi-nis.fedorahosted.org/ # dn: cn=Schema Compatibility, cn=plugins, cn=config default:objectclass: top default:objectclass: nsSlapdPlugin default:objectclass: extensibleObject default:cn: Schema Compatibility default:nsslapd-pluginpath: /usr/lib$LIBARCH/dirsrv/plugins/schemacompat-plugin.so default:nsslapd-plugininitfunc: schema_compat_plugin_init default:nsslapd-plugintype: object default:nsslapd-pluginenabled: on default:nsslapd-pluginid: schema-compat-plugin default:nsslapd-pluginversion: 0.8 default:nsslapd-pluginbetxn: on default:nsslapd-pluginvendor: redhat.com default:nsslapd-plugindescription: Schema Compatibility Plugin dn: cn=users, cn=Schema Compatibility, cn=plugins, cn=config default:objectClass: top default:objectClass: extensibleObject default:cn: users default:schema-compat-container-group: cn=compat, $SUFFIX default:schema-compat-container-rdn: cn=users default:schema-compat-search-base: cn=users, cn=accounts, $SUFFIX default:schema-compat-search-filter: objectclass=posixAccount default:schema-compat-entry-rdn: uid=%{uid} default:schema-compat-entry-attribute: objectclass=posixAccount default:schema-compat-entry-attribute: gecos=%{cn} default:schema-compat-entry-attribute: cn=%{cn} default:schema-compat-entry-attribute: uidNumber=%{uidNumber} default:schema-compat-entry-attribute: gidNumber=%{gidNumber} default:schema-compat-entry-attribute: loginShell=%{loginShell} default:schema-compat-entry-attribute: homeDirectory=%{homeDirectory} dn: cn=groups, cn=Schema Compatibility, cn=plugins, cn=config default:objectClass: top default:objectClass: extensibleObject default:cn: groups default:schema-compat-container-group: cn=compat, $SUFFIX default:schema-compat-container-rdn: cn=groups default:schema-compat-search-base: cn=groups, cn=accounts, $SUFFIX default:schema-compat-search-filter: objectclass=posixGroup default:schema-compat-entry-rdn: cn=%{cn} default:schema-compat-entry-attribute: objectclass=posixGroup default:schema-compat-entry-attribute: gidNumber=%{gidNumber} default:schema-compat-entry-attribute: memberUid=%{memberUid} default:schema-compat-entry-attribute: memberUid=%deref_r("member","uid") dn: cn=ng,cn=Schema Compatibility,cn=plugins,cn=config add:objectClass: top add:objectClass: extensibleObject add:cn: ng add:schema-compat-container-group: 'cn=compat, $SUFFIX' add:schema-compat-container-rdn: cn=ng add:schema-compat-check-access: yes add:schema-compat-search-base: 'cn=ng, cn=alt, $SUFFIX' add:schema-compat-search-filter: (objectclass=ipaNisNetgroup) add:schema-compat-entry-rdn: cn=%{cn} add:schema-compat-entry-attribute: objectclass=nisNetgroup add:schema-compat-entry-attribute: 'memberNisNetgroup=%deref_r("member","cn")' add:schema-compat-entry-attribute: 'nisNetgroupTriple=(%link("%ifeq(\"hostCategory\",\"all\",\"\",\"%collect(\\\"%{externalHost}\\\",\\\"%deref(\\\\\\\"memberHost\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberHost\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\")\")","-",",","%ifeq(\"userCategory\",\"all\",\"\",\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\")","-"),%{nisDomainName:-})' dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config add:objectClass: top add:objectClass: extensibleObject add:cn: sudoers add:schema-compat-container-group: 'ou=SUDOers, $SUFFIX' add:schema-compat-search-base: 'cn=sudorules, cn=sudo, $SUFFIX' add:schema-compat-search-filter: (&(objectclass=ipaSudoRule)(!(compatVisible=FALSE))(!(ipaEnabledFlag=FALSE))) add:schema-compat-entry-rdn: %ifeq("ipaEnabledFlag", "FALSE", "DISABLED", "cn=%{cn}") add:schema-compat-entry-attribute: objectclass=sudoRole add:schema-compat-entry-attribute: 'sudoUser=%ifeq("userCategory","all","ALL","%{externalUser}")' add:schema-compat-entry-attribute: 'sudoUser=%ifeq("userCategory","all","ALL","%deref_f(\"memberUser\",\"(objectclass=posixAccount)\",\"uid\")")' add:schema-compat-entry-attribute: 'sudoUser=%ifeq("userCategory","all","ALL","%deref_rf(\"memberUser\",\"(&(objectclass=ipaUserGroup)(!(objectclass=posixGroup)))\",\"member\",\"(|(objectclass=ipaUserGroup)(objectclass=posixAccount))\",\"uid\")")' add:schema-compat-entry-attribute: 'sudoUser=%ifeq("userCategory","all","ALL","%%%deref_f(\"memberUser\",\"(objectclass=posixGroup)\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoUser=%ifeq("userCategory","all","ALL","+%deref_f(\"memberUser\",\"(objectclass=ipaNisNetgroup)\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","%{externalHost}")' add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","%deref_f(\"memberHost\",\"(objectclass=ipaHost)\",\"fqdn\")")' add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","%deref_rf(\"memberHost\",\"(&(objectclass=ipaHostGroup)(!(objectclass=mepOriginEntry)))\",\"member\",\"(|(objectclass=ipaHostGroup)(objectclass=ipaHost))\",\"fqdn\")")' add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","+%deref_f(\"memberHost\",\"(&(objectclass=ipaHostGroup)(objectclass=mepOriginEntry))\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoHost=%ifeq("hostCategory","all","ALL","+%deref_f(\"memberHost\",\"(objectclass=ipaNisNetgroup)\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoCommand=%ifeq("cmdCategory","all","ALL","%deref(\"memberAllowCmd\",\"sudoCmd\")")' add:schema-compat-entry-attribute: 'sudoCommand=%ifeq("cmdCategory","all","ALL","%deref_r(\"memberAllowCmd\",\"member\",\"sudoCmd\")")' add:schema-compat-entry-attribute: 'sudoCommand=!%deref("memberDenyCmd","sudoCmd")' add:schema-compat-entry-attribute: 'sudoCommand=!%deref_r("memberDenyCmd","member","sudoCmd")' add:schema-compat-entry-attribute: 'sudoRunAsUser=%{ipaSudoRunAsExtUser}' add:schema-compat-entry-attribute: 'sudoRunAsUser=%deref("ipaSudoRunAs","uid")' add:schema-compat-entry-attribute: 'sudoRunAsUser=%ifeq("ipaSudoRunAsUserCategory","all","ALL","%%%deref_f(\"ipaSudoRunAs\",\"(objectclass=posixGroup)\",\"cn\")")' add:schema-compat-entry-attribute: 'sudoRunAsGroup=%{ipaSudoRunAsExtGroup}' add:schema-compat-entry-attribute: 'sudoRunAsGroup=%deref("ipaSudoRunAs","cn")' add:schema-compat-entry-attribute: 'sudoOption=%{ipaSudoOpt}' dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config default:objectClass: top default:objectClass: extensibleObject default:cn: computers default:schema-compat-container-group: cn=compat, $SUFFIX default:schema-compat-container-rdn: cn=computers default:schema-compat-search-base: cn=computers, cn=accounts, $SUFFIX default:schema-compat-search-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:schema-compat-entry-rdn: cn=%first("%{fqdn}") default:schema-compat-entry-attribute: objectclass=device default:schema-compat-entry-attribute: objectclass=ieee802Device default:schema-compat-entry-attribute: cn=%{fqdn} default:schema-compat-entry-attribute: macAddress=%{macAddress} # Enable anonymous VLV browsing for Solaris dn: oid=2.16.840.1.113730.3.4.9,cn=features,cn=config only:aci: '(targetattr !="aci")(version 3.0; acl "VLV Request Control"; allow (read, search, compare, proxy) userdn = "ldap:///anyone"; )' freeipa-3.3.4/install/share/managed-entries.ldif0000664000175000017500000000056012202434255021155 0ustar mkosekmkosekdn: cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: Managed Entries dn: cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: Templates dn: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: Definitions freeipa-3.3.4/install/share/fedora-ds.init.patch0000664000175000017500000000057212202434255021104 0ustar mkosekmkosek--- /etc/init.d/dirsrv.orig 2007-07-06 18:21:30.000000000 -0400 +++ /etc/init.d/dirsrv 2007-05-18 19:36:24.000000000 -0400 @@ -10,6 +10,9 @@ # datadir: /var/lib/dirsrv/slapd- # +# Get config. +[ -r /etc/sysconfig/dirsrv ] && . /etc/sysconfig/dirsrv + # Source function library. if [ -f /etc/rc.d/init.d/functions ] ; then . /etc/rc.d/init.d/functions freeipa-3.3.4/install/share/krb.js.template0000664000175000017500000000006512202434255020200 0ustar mkosekmkosekvar IPA_REALM = "$REALM"; var IPA_DOMAIN = "$DOMAIN";freeipa-3.3.4/install/share/key_escrow_schema.ldif0000664000175000017500000000356212202434255021611 0ustar mkosekmkosek# Key escrow schema. Currently unused # Main schema: attributeTypes: (2.16.840.1.113730.3.8.A.X NAME 'ipaVolumeEscrowPacket' DESC 'An encrypted packet containing a secret used for encrypting the volume' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE ) attributeTypes: (2.16.840.1.113730.3.8.A.X NAME 'ipaVolumeHost' DESC 'Link to the host that contains this volume' SUP memberHost SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) attributeTypes: (2.16.840.1.113730.3.8.A.X NAME 'ipaVolumeKeySecretType' DESC 'Type of the secret defined in this packet' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) attributeTypes: (2.16.840.1.113730.3.8.A.X NAME 'ipaVolumeInfo' DESC 'Information about a volume: NAME:VALUE' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) attributeTypes: (2.16.840.1.113730.3.8.A.X NAME 'ipaVolumeKeyObsoletionTimestamp' DESC 'Time when a key was marked as obsolete' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) objectClasses: (2.16.840.1.113730.3.8.O.Y NAME 'ipaVolumeKey' SUP top STRUCTURAL MUST ( ipaUniqueID $ ipaVolumeHost $ ipaVolumeEscrowPacket ) MAY ( ipaVolumeKeySecretType $ ipaVolumeInfo $ ipaVolumeKeyObsoletionTimestamp )) # Config schema: attributeTypes: ( 2.16.840.1.113730.3.8.3.50 NAME 'ipaObsoleteEscrowPacketLifetime' DESC 'Number of days before an obsolete escrow packet is deleted (if a newer packet for the same volume is available)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) attributeTypes: ( 2.16.840.1.113730.3.8.3.51 NAME 'ipaEscrowKeyCertificate' DESC 'Certificate for encrypting escrow packets' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE) attributeTypes: ( 2.16.840.1.113730.3.8.3.52 NAME 'ipaEscrowKey' DESC 'PKCS#12-formatted encrypted certificate and private key for encrypting escrow packets' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5) # Attributes removed from config object #$ ipaObsoleteEscrowPacketLifetime $ ipaEscrowKeyCertificate $ ipaEscrowKey freeipa-3.3.4/install/share/bind.zone.db.template0000664000175000017500000000117112271663206021266 0ustar mkosekmkosek$$ORIGIN $DOMAIN. $$TTL 86400 @ IN SOA $DOMAIN. $ZONEMGR. ( 01 ; serial 3H ; refresh 15M ; retry 1W ; expiry 1D ) ; minimum IN NS $HOST $HOST IN A $IP ; ; ldap servers _ldap._tcp IN SRV 0 100 389 $HOST ;kerberos realm _kerberos IN TXT $REALM ; kerberos servers _kerberos._tcp IN SRV 0 100 88 $HOST _kerberos._udp IN SRV 0 100 88 $HOST _kerberos-master._tcp IN SRV 0 100 88 $HOST _kerberos-master._udp IN SRV 0 100 88 $HOST _kpasswd._tcp IN SRV 0 100 464 $HOST _kpasswd._udp IN SRV 0 100 464 $HOST $OPTIONAL_NTP ; CNAME for IPA CA replicas (used for CRL, OCSP) $IPA_CA_RECORD freeipa-3.3.4/install/share/60ipadns.ldif0000664000175000017500000002370612271663206017553 0ustar mkosekmkosek## IPA Base OID: 2.16.840.1.113730.3.8 ## ## Attributes: 2.16.840.1.113730.3.8.5 - V2 DNS related attributres ## ObjectClasses: 2.16.840.1.113730.3.8.6 - V2 DNS related objectclasses ## dn: cn=schema attributeTypes: (1.3.6.1.4.1.2428.20.0.0 NAME 'dNSTTL' DESC 'An integer denoting time to live' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) attributeTypes: (1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass' DESC 'The class of a resource record' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord' DESC 'domain name pointer, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord' DESC 'host information, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord' DESC 'mailbox or mail list information, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord' DESC 'text string, RFC 1035' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord' DESC 'for AFS Data Base location, RFC 1183' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord' DESC 'Signature, RFC 2535' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord' DESC 'Key, RFC 2535' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord' DESC 'IPv6 address, RFC 1886' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord' DESC 'Location, RFC 1876' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord' DESC 'non-existant, RFC 2535' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord' DESC 'service location, RFC 2782' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord' DESC 'Naming Authority Pointer, RFC 2915' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord' DESC 'Key Exchange Delegation, RFC 2230' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord' DESC 'certificate, RFC 2538' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record' DESC 'A6 Record Type, RFC 2874' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord' DESC 'Non-Terminal DNS Name Redirection, RFC 2672' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributeTypes: (1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord' DESC 'Delegation Signer, RFC 3658' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord' DESC 'SSH Key Fingerprint, draft-ietf-secsh-dns-05.txt' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord' DESC 'RRSIG, RFC 3755' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord' DESC 'NSEC, RFC 3755' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (0.9.2342.19200300.100.1.26 NAME 'aRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (0.9.2342.19200300.100.1.29 NAME 'nSRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) attributeTypes: (0.9.2342.19200300.100.1.28 NAME 'mXRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (0.9.2342.19200300.100.1.27 NAME 'mDRecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) attributeTypes: (2.16.840.1.113730.3.8.5.0 NAME 'idnsName' DESC 'DNS FQDN' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.1 NAME 'idnsAllowDynUpdate' DESC 'permit dynamic updates on this zone' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.2 NAME 'idnsZoneActive' DESC 'define if the zone is considered in use' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.3 NAME 'idnsSOAmName' DESC 'SOA Name' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.4 NAME 'idnsSOArName' DESC 'SOA root Name' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.5 NAME 'idnsSOAserial' DESC 'SOA serial number' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.6 NAME 'idnsSOArefresh' DESC 'SOA refresh value' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.7 NAME 'idnsSOAretry' DESC 'SOA retry value' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.8 NAME 'idnsSOAexpire' DESC 'SOA expire value' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.9 NAME 'idnsSOAminimum' DESC 'SOA minimum value' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.5.10 NAME 'idnsUpdatePolicy' DESC 'DNS dynamic updates policy' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.11 NAME 'idnsAllowQuery' DESC 'BIND9 allow-query ACL element' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.12 NAME 'idnsAllowTransfer' DESC 'BIND9 allow-transfer ACL element' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.13 NAME 'idnsAllowSyncPTR' DESC 'permit synchronization of PTR records' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.14 NAME 'idnsForwardPolicy' DESC 'forward policy: only or first' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.15 NAME 'idnsForwarders' DESC 'list of forwarders' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.16 NAME 'idnsZoneRefresh' DESC 'zone refresh interval' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: ( 2.16.840.1.113730.3.8.5.17 NAME 'idnsPersistentSearch' DESC 'allow persistent searches' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) objectClasses: ( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( idnsAllowDynUpdate $ DNSTTL $ DNSClass $ ARecord $ AAAARecord $ A6Record $ NSRecord $ CNAMERecord $ PTRRecord $ SRVRecord $ TXTRecord $ MXRecord $ MDRecord $ HINFORecord $ MINFORecord $ AFSDBRecord $ SIGRecord $ KEYRecord $ LOCRecord $ NXTRecord $ NAPTRRecord $ KXRecord $ CERTRecord $ DNAMERecord $ DSRecord $ SSHFPRecord $ RRSIGRecord $ NSECRecord ) ) objectClasses: ( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsName $ idnsZoneActive $ idnsSOAmName $ idnsSOArName $ idnsSOAserial $ idnsSOArefresh $ idnsSOAretry $ idnsSOAexpire $ idnsSOAminimum ) MAY ( idnsUpdatePolicy $ idnsAllowQuery $ idnsAllowTransfer $ idnsAllowSyncPTR $ idnsForwardPolicy $ idnsForwarders ) ) objectClasses: ( 2.16.840.1.113730.3.8.6.2 NAME 'idnsConfigObject' DESC 'DNS global config options' STRUCTURAL MAY ( idnsForwardPolicy $ idnsForwarders $ idnsAllowSyncPTR $ idnsZoneRefresh $ idnsPersistentSearch ) ) objectClasses: ( 2.16.840.1.113730.3.8.12.18 NAME 'ipaDNSZone' SUP top AUXILIARY MUST idnsName MAY managedBy X-ORIGIN 'IPA v3' ) freeipa-3.3.4/install/share/replica-s4u2proxy.ldif0000664000175000017500000000106012202434255021422 0ustar mkosekmkosekdn: cn=ipa-http-delegation,cn=s4u2proxy,cn=etc,$SUFFIX changetype: modify add: memberPrincipal memberPrincipal: HTTP/$FQDN@$REALM # ipa-cifs-delegation-targets needs to be an ipaAllowedTarget for HTTP # delegation but we don't add it here as an LDIF because this entry may # already exist from another replica, or previous install. If it is missing # then it will be caught by the update file 61-trusts-s4u2proxy.update dn: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX changetype: modify add: memberPrincipal memberPrincipal: ldap/$FQDN@$REALM freeipa-3.3.4/install/share/user_private_groups.ldif0000664000175000017500000000152212202434255022220 0ustar mkosekmkosekdn: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectclass: mepTemplateEntry cn: UPG Template mepRDNAttr: cn mepStaticAttr: objectclass: posixgroup mepStaticAttr: objectclass: ipaobject mepStaticAttr: ipaUniqueId: autogenerate mepMappedAttr: cn: $$uid mepMappedAttr: gidNumber: $$uidNumber mepMappedAttr: description: User private group for $$uid # Changes to this definition need to be reflected in # updates/20-user_private_groups.update dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX changetype: add objectclass: extensibleObject cn: UPG Definition originScope: cn=users,cn=accounts,$SUFFIX originFilter: (&(objectclass=posixAccount)(!(description=__no_upg__))) managedBase: cn=groups,cn=accounts,$SUFFIX managedTemplate: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX freeipa-3.3.4/install/share/upload-cacert.ldif0000664000175000017500000000026112271663206020641 0ustar mkosekmkosek# add CA certificate to LDAP server dn: cn=CAcert,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: pkiCA cn: CAcert cACertificate;binary:: $CADERCERT freeipa-3.3.4/install/share/automember.ldif0000664000175000017500000000201712202434255020251 0ustar mkosekmkosek# Configuration for Auto Membership Plugin for Master # installation. This method should be revisted for # optimization due to a bug within 389 DS which prevents # the definition files from being added seperatly after # the insertion of cn=Auto Membership Plugin,cn=plugins,cn=config # and subsequent 389 DS restart. dn: cn=Auto Membership Plugin,cn=plugins,cn=config changetype: modify add: nsslapd-pluginConfigArea nsslapd-pluginConfigArea: cn=automember,cn=etc,$SUFFIX dn: cn=automember,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: automember dn: cn=Hostgroup,cn=automember,cn=etc,$SUFFIX changetype: add objectclass: autoMemberDefinition cn: Hostgroup autoMemberScope: cn=computers,cn=accounts,$SUFFIX autoMemberFilter: objectclass=ipaHost autoMemberGroupingAttr: member:dn dn: cn=Group,cn=automember,cn=etc,$SUFFIX changetype: add objectclass: autoMemberDefinition cn: Group autoMemberScope: cn=users,cn=accounts,$SUFFIX autoMemberFilter: objectclass=posixAccount autoMemberGroupingAttr: member:dn freeipa-3.3.4/install/share/60kerberos.ldif0000664000175000017500000004677512202434255020116 0ustar mkosekmkosekdn: cn=schema # Novell Kerberos Schema Definitions # Novell Inc. # 1800 South Novell Place # Provo, UT 84606 # # VeRsIoN=1.0 # CoPyRiGhT=(c) Copyright 2006, Novell, Inc. All rights reserved # # OIDs: # joint-iso-ccitt(2) # country(16) # us(840) # organization(1) # Novell(113719) # applications(1) # kerberos(301) # Kerberos Attribute Type(4) attr# version# # specific attribute definitions # Kerberos Attribute Syntax(5) # specific syntax definitions # Kerberos Object Class(6) class# version# # specific class definitions # # iso(1) # member-body(2) # United States(840) # mit (113554) # infosys(1) # ldap(4) # attributeTypes(1) # Kerberos(6) ######################################################################## ######################################################################## # Attribute Type Definitions # ######################################################################## ##### This is the principal name in the RFC 1964 specified format attributetypes: ( 2.16.840.1.113719.1.301.4.1.1 NAME 'krbPrincipalName' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) ##### If there are multiple krbPrincipalName values for an entry, this ##### is the canonical principal name in the RFC 1964 specified ##### format. (If this attribute does not exist, then all ##### krbPrincipalName values are treated as canonical.) attributetypes: ( 1.2.840.113554.1.4.1.6.1 NAME 'krbCanonicalName' EQUALITY caseExactIA5Match SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE) ##### This specifies the type of the principal, the types could be any of ##### the types mentioned in section 6.2 of RFC 4120 attributetypes: ( 2.16.840.1.113719.1.301.4.3.1 NAME 'krbPrincipalType' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### This flag is used to find whether directory User Password has to be used ##### as kerberos password. ##### TRUE, if User Password is to be used as the kerberos password. ##### FALSE, if User Password and the kerberos password are different. attributetypes: ( 2.16.840.1.113719.1.301.4.5.1 NAME 'krbUPEnabled' DESC 'Boolean' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE) ##### The time at which the principal expires attributetypes: ( 2.16.840.1.113719.1.301.4.6.1 NAME 'krbPrincipalExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### The krbTicketFlags attribute holds information about the kerberos flags for a principal ##### The values (0x00000001 - 0x00800000) are reserved for standards and ##### values (0x01000000 - 0x80000000) can be used for proprietary extensions. ##### The flags and values as per RFC 4120 and MIT implementation are, ##### DISALLOW_POSTDATED 0x00000001 ##### DISALLOW_FORWARDABLE 0x00000002 ##### DISALLOW_TGT_BASED 0x00000004 ##### DISALLOW_RENEWABLE 0x00000008 ##### DISALLOW_PROXIABLE 0x00000010 ##### DISALLOW_DUP_SKEY 0x00000020 ##### DISALLOW_ALL_TIX 0x00000040 ##### REQUIRES_PRE_AUTH 0x00000080 ##### REQUIRES_HW_AUTH 0x00000100 ##### REQUIRES_PWCHANGE 0x00000200 ##### DISALLOW_SVR 0x00001000 ##### PWCHANGE_SERVICE 0x00002000 attributetypes: ( 2.16.840.1.113719.1.301.4.8.1 NAME 'krbTicketFlags' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### The maximum ticket lifetime for a principal in seconds attributetypes: ( 2.16.840.1.113719.1.301.4.9.1 NAME 'krbMaxTicketLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Maximum renewable lifetime for a principal's ticket in seconds attributetypes: ( 2.16.840.1.113719.1.301.4.10.1 NAME 'krbMaxRenewableAge' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Forward reference to the Realm object. ##### (FDN of the krbRealmContainer object). ##### Example: cn=ACME.COM, cn=Kerberos, cn=Security attributetypes: ( 2.16.840.1.113719.1.301.4.14.1 NAME 'krbRealmReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### List of LDAP servers that kerberos servers can contact. ##### The attribute holds data in the ldap uri format, ##### Example: ldaps://acme.com:636 ##### ##### The values of this attribute need to be updated, when ##### the LDAP servers listed here are renamed, moved or deleted. attributetypes: ( 2.16.840.1.113719.1.301.4.15.1 NAME 'krbLdapServers' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ##### A set of forward references to the KDC Service objects. ##### (FDNs of the krbKdcService objects). ##### Example: cn=kdc - server 1, ou=uvw, o=xyz attributetypes: ( 2.16.840.1.113719.1.301.4.17.1 NAME 'krbKdcServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### A set of forward references to the Password Service objects. ##### (FDNs of the krbPwdService objects). ##### Example: cn=kpasswdd - server 1, ou=uvw, o=xyz attributetypes: ( 2.16.840.1.113719.1.301.4.18.1 NAME 'krbPwdServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### This attribute holds the Host Name or the ip address, ##### transport protocol and ports of the kerberos service host ##### The format is host_name-or-ip_address#protocol#port ##### Protocol can be 0 or 1. 0 is for UDP. 1 is for TCP. attributetypes: ( 2.16.840.1.113719.1.301.4.24.1 NAME 'krbHostServer' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) ##### This attribute holds the scope for searching the principals ##### under krbSubTree attribute of krbRealmContainer ##### The value can either be 1 (ONE) or 2 (SUB_TREE). attributetypes: ( 2.16.840.1.113719.1.301.4.25.1 NAME 'krbSearchScope' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### FDNs pointing to Kerberos principals attributetypes: ( 2.16.840.1.113719.1.301.4.26.1 NAME 'krbPrincipalReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### This attribute specifies which attribute of the user objects ##### be used as the principal name component for Kerberos. ##### The allowed values are cn, sn, uid, givenname, fullname. attributetypes: ( 2.16.840.1.113719.1.301.4.28.1 NAME 'krbPrincNamingAttr' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) ##### A set of forward references to the Administration Service objects. ##### (FDNs of the krbAdmService objects). ##### Example: cn=kadmindd - server 1, ou=uvw, o=xyz attributetypes: ( 2.16.840.1.113719.1.301.4.29.1 NAME 'krbAdmServers' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### Maximum lifetime of a principal's password attributetypes: ( 2.16.840.1.113719.1.301.4.30.1 NAME 'krbMaxPwdLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Minimum lifetime of a principal's password attributetypes: ( 2.16.840.1.113719.1.301.4.31.1 NAME 'krbMinPwdLife' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Minimum number of character clases allowed in a password attributetypes: ( 2.16.840.1.113719.1.301.4.32.1 NAME 'krbPwdMinDiffChars' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Minimum length of the password attributetypes: ( 2.16.840.1.113719.1.301.4.33.1 NAME 'krbPwdMinLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Number of previous versions of passwords that are stored attributetypes: ( 2.16.840.1.113719.1.301.4.34.1 NAME 'krbPwdHistoryLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Number of consecutive pre-authentication failures before lockout attributetypes: ( 1.3.6.1.4.1.5322.21.2.1 NAME 'krbPwdMaxFailure' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Period after which bad preauthentication count will be reset attributetypes: ( 1.3.6.1.4.1.5322.21.2.2 NAME 'krbPwdFailureCountInterval' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### Period in which lockout is enforced attributetypes: ( 1.3.6.1.4.1.5322.21.2.3 NAME 'krbPwdLockoutDuration' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### FDN pointing to a Kerberos Password Policy object attributetypes: ( 2.16.840.1.113719.1.301.4.36.1 NAME 'krbPwdPolicyReference' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE) ##### The time at which the principal's password expires attributetypes: ( 2.16.840.1.113719.1.301.4.37.1 NAME 'krbPasswordExpiration' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### This attribute holds the principal's key (krbPrincipalKey) that is encrypted with ##### the master key (krbMKey). ##### The attribute is ASN.1 encoded. ##### ##### The format of the value for this attribute is explained below, ##### KrbKeySet ::= SEQUENCE { ##### attribute-major-vno [0] UInt16, ##### attribute-minor-vno [1] UInt16, ##### kvno [2] UInt32, ##### mkvno [3] UInt32 OPTIONAL, ##### keys [4] SEQUENCE OF KrbKey, ##### ... ##### } ##### ##### KrbKey ::= SEQUENCE { ##### salt [0] KrbSalt OPTIONAL, ##### key [1] EncryptionKey, ##### s2kparams [2] OCTET STRING OPTIONAL, ##### ... ##### } ##### ##### KrbSalt ::= SEQUENCE { ##### type [0] Int32, ##### salt [1] OCTET STRING OPTIONAL ##### } ##### ##### EncryptionKey ::= SEQUENCE { ##### keytype [0] Int32, ##### keyvalue [1] OCTET STRING ##### } attributetypes: ( 2.16.840.1.113719.1.301.4.39.1 NAME 'krbPrincipalKey' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) ##### FDN pointing to a Kerberos Ticket Policy object. attributetypes: ( 2.16.840.1.113719.1.301.4.40.1 NAME 'krbTicketPolicyReference' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE) ##### Forward reference to an entry that starts sub-trees ##### where principals and other kerberos objects in the realm are configured. ##### Example: ou=acme, ou=pq, o=xyz attributetypes: ( 2.16.840.1.113719.1.301.4.41.1 NAME 'krbSubTrees' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### Holds the default encryption/salt type combinations of principals for ##### the Realm. Stores in the form of key:salt strings. ##### Example: des-cbc-crc:normal attributetypes: ( 2.16.840.1.113719.1.301.4.42.1 NAME 'krbDefaultEncSaltTypes' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ##### Holds the Supported encryption/salt type combinations of principals for ##### the Realm. Stores in the form of key:salt strings. ##### The supported encryption types are mentioned in RFC 3961 ##### The supported salt types are, ##### NORMAL ##### V4 ##### NOREALM ##### ONLYREALM ##### SPECIAL ##### AFS3 ##### Example: des-cbc-crc:normal ##### ##### This attribute obsoletes the krbSupportedEncTypes and krbSupportedSaltTypes ##### attributes. attributetypes: ( 2.16.840.1.113719.1.301.4.43.1 NAME 'krbSupportedEncSaltTypes' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ##### This attribute holds the principal's old keys (krbPwdHistory) that is encrypted with ##### the kadmin/history key. ##### The attribute is ASN.1 encoded. ##### ##### The format of the value for this attribute is explained below, ##### KrbKeySet ::= SEQUENCE { ##### attribute-major-vno [0] UInt16, ##### attribute-minor-vno [1] UInt16, ##### kvno [2] UInt32, ##### mkvno [3] UInt32 OPTIONAL -- actually kadmin/history key, ##### keys [4] SEQUENCE OF KrbKey, ##### ... ##### } ##### ##### KrbKey ::= SEQUENCE { ##### salt [0] KrbSalt OPTIONAL, ##### key [1] EncryptionKey, ##### s2kparams [2] OCTET STRING OPTIONAL, ##### ... ##### } ##### ##### KrbSalt ::= SEQUENCE { ##### type [0] Int32, ##### salt [1] OCTET STRING OPTIONAL ##### } ##### ##### EncryptionKey ::= SEQUENCE { ##### keytype [0] Int32, ##### keyvalue [1] OCTET STRING ##### } attributetypes: ( 2.16.840.1.113719.1.301.4.44.1 NAME 'krbPwdHistory' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) ##### The time at which the principal's password last password change happened. attributetypes: ( 2.16.840.1.113719.1.301.4.45.1 NAME 'krbLastPwdChange' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### This attribute holds the kerberos master key. ##### This can be used to encrypt principal keys. ##### This attribute has to be secured in directory. ##### ##### This attribute is ASN.1 encoded. ##### The format of the value for this attribute is explained below, ##### KrbMKey ::= SEQUENCE { ##### kvno [0] UInt32, ##### key [1] MasterKey ##### } ##### ##### MasterKey ::= SEQUENCE { ##### keytype [0] Int32, ##### keyvalue [1] OCTET STRING ##### } attributetypes: ( 2.16.840.1.113719.1.301.4.46.1 NAME 'krbMKey' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) ##### This stores the alternate principal names for the principal in the RFC 1961 specified format attributetypes: ( 2.16.840.1.113719.1.301.4.47.1 NAME 'krbPrincipalAliases' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) ##### The time at which the principal's last successful authentication happened. attributetypes: ( 2.16.840.1.113719.1.301.4.48.1 NAME 'krbLastSuccessfulAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### The time at which the principal's last failed authentication happened. attributetypes: ( 2.16.840.1.113719.1.301.4.49.1 NAME 'krbLastFailedAuth' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ##### This attribute stores the number of failed authentication attempts ##### happened for the principal since the last successful authentication. attributetypes: ( 2.16.840.1.113719.1.301.4.50.1 NAME 'krbLoginFailedCount' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ##### This attribute holds the application specific data. attributetypes: ( 2.16.840.1.113719.1.301.4.51.1 NAME 'krbExtraData' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40) ##### This attributes holds references to the set of directory objects. ##### This stores the DNs of the directory objects to which the ##### principal object belongs to. attributetypes: ( 2.16.840.1.113719.1.301.4.52.1 NAME 'krbObjectReferences' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### This attribute holds references to a Container object where ##### the additional principal objects and stand alone principal ##### objects (krbPrincipal) can be created. attributetypes: ( 2.16.840.1.113719.1.301.4.53.1 NAME 'krbPrincContainerRef' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12) ##### The time at which administrator unlocked the account attributetypes: ( 1.3.6.1.4.1.5322.21.2.5 NAME 'krbLastAdminUnlock' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE) ######################################################################## ######################################################################## # Object Class Definitions # ######################################################################## #### This is a kerberos container for all the realms in a tree. objectClasses: ( 2.16.840.1.113719.1.301.6.1.1 NAME 'krbContainer' SUP top MUST ( cn ) ) ##### The krbRealmContainer is created per realm and holds realm specific data. objectClasses: ( 2.16.840.1.113719.1.301.6.2.1 NAME 'krbRealmContainer' SUP top MUST ( cn ) MAY ( krbMKey $ krbUPEnabled $ krbSubTrees $ krbSearchScope $ krbLdapServers $ krbSupportedEncSaltTypes $ krbDefaultEncSaltTypes $ krbTicketPolicyReference $ krbKdcServers $ krbPwdServers $ krbAdmServers $ krbPrincNamingAttr $krbPwdPolicyReference $ krbPrincContainerRef ) ) ##### An instance of a class derived from krbService is created per ##### kerberos authentication or administration server in an realm and holds ##### references to the realm objects. These references is used to further read ##### realm specific data to service AS/TGS requests. Additionally this object ##### contains some server specific data like pathnames and ports that the ##### server uses. This is the identity the kerberos server logs in with. A key ##### pair for the same is created and the kerberos server logs in with the same. ##### ##### krbKdcService, krbAdmService and krbPwdService derive from this class. objectClasses: ( 2.16.840.1.113719.1.301.6.3.1 NAME 'krbService' ABSTRACT SUP ( top ) MUST ( cn ) MAY ( krbHostServer $ krbRealmReferences ) ) ##### Representative object for the KDC server to bind into a LDAP directory ##### and have a connection to access Kerberos data with the required ##### access rights. objectClasses: ( 2.16.840.1.113719.1.301.6.4.1 NAME 'krbKdcService' SUP ( krbService ) ) ##### Representative object for the Kerberos Password server to bind into a LDAP directory ##### and have a connection to access Kerberos data with the required ##### access rights. objectClasses: ( 2.16.840.1.113719.1.301.6.5.1 NAME 'krbPwdService' SUP ( krbService ) ) ###### The principal data auxiliary class. Holds principal information ###### and is used to store principal information for Person, Service objects. objectClasses: ( 2.16.840.1.113719.1.301.6.8.1 NAME 'krbPrincipalAux' AUXILIARY MAY ( krbPrincipalName $ krbCanonicalName $ krbUPEnabled $ krbPrincipalKey $ krbTicketPolicyReference $ krbPrincipalExpiration $ krbPasswordExpiration $ krbPwdPolicyReference $ krbPrincipalType $ krbPwdHistory $ krbLastPwdChange $ krbPrincipalAliases $ krbLastSuccessfulAuth $ krbLastFailedAuth $ krbLoginFailedCount $ krbExtraData $ krbLastAdminUnlock ) ) ###### This class is used to create additional principals and stand alone principals. objectClasses: ( 2.16.840.1.113719.1.301.6.9.1 NAME 'krbPrincipal' SUP ( top ) MUST ( krbPrincipalName ) MAY ( krbObjectReferences ) ) ###### The principal references auxiliary class. Holds all principals referred ###### from a service objectClasses: ( 2.16.840.1.113719.1.301.6.11.1 NAME 'krbPrincRefAux' SUP top AUXILIARY MAY krbPrincipalReferences ) ##### Representative object for the Kerberos Administration server to bind into a LDAP directory ##### and have a connection Id to access Kerberos data with the required access rights. objectClasses: ( 2.16.840.1.113719.1.301.6.13.1 NAME 'krbAdmService' SUP ( krbService ) ) ##### The krbPwdPolicy object is a template password policy that ##### can be applied to principals when they are created. ##### These policy attributes will be in effect, when the Kerberos ##### passwords are different from users' passwords (UP). objectClasses: ( 2.16.840.1.113719.1.301.6.14.1 NAME 'krbPwdPolicy' SUP top MUST ( cn ) MAY ( krbMaxPwdLife $ krbMinPwdLife $ krbPwdMinDiffChars $ krbPwdMinLength $ krbPwdHistoryLength $ krbPwdMaxFailure $ krbPwdFailureCountInterval $ krbPwdLockoutDuration ) ) ##### The krbTicketPolicyAux holds Kerberos ticket policy attributes. ##### This class can be attached to a principal object or realm object. objectClasses: ( 2.16.840.1.113719.1.301.6.16.1 NAME 'krbTicketPolicyAux' AUXILIARY MAY ( krbTicketFlags $ krbMaxTicketLife $ krbMaxRenewableAge ) ) ##### The krbTicketPolicy object is an effective ticket policy that is associated with a realm or a principal objectClasses: ( 2.16.840.1.113719.1.301.6.17.1 NAME 'krbTicketPolicy' SUP top MUST ( cn ) ) freeipa-3.3.4/install/share/dns.ldif0000664000175000017500000001161712202434255016703 0ustar mkosekmkosekdn: cn=dns,$SUFFIX changetype: add objectClass: idnsConfigObject objectClass: nsContainer objectClass: top cn: dns aci: (targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";) aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";) aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";) aci: (targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";) dn: $SUFFIX changetype: modify add: aci aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:add dns entries";allow (add) groupdn = "ldap:///cn=add dns entries,cn=permissions,cn=pbac,$SUFFIX";) aci: (target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:remove dns entries";allow (delete) groupdn = "ldap:///cn=remove dns entries,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";) aci: (targetattr = "idnsforwardpolicy || idnsforwarders || idnsallowsyncptr || idnszonerefresh || idnspersistentsearch")(target = "ldap:///cn=dns,$SUFFIX")(version 3.0;acl "permission:Write DNS Configuration";allow (write) groupdn = "ldap:///cn=Write DNS Configuration,cn=permissions,cn=pbac,$SUFFIX";) dn: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: DNS Administrators description: DNS Administrators dn: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup cn: DNS Servers description: DNS Servers dn: cn=add dns entries,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: groupofnames objectClass: top objectClass: ipapermission cn: add dns entries description: Add DNS entries member: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX dn: cn=remove dns entries,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: groupofnames objectClass: top objectClass: ipapermission cn: remove dns entries description: Remove DNS entries member: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX dn: cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: groupofnames objectClass: top objectClass: ipapermission cn: update dns entries description: Update DNS entries member: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX dn: cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: ipapermission cn: Read DNS Entries description: Read DNS entries ipapermissiontype: SYSTEM member: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX dn: cn=Write DNS Configuration,cn=permissions,cn=pbac,$SUFFIX changetype: add objectClass: groupofnames objectClass: top objectClass: ipapermission cn: Write DNS Configuration description: Write DNS Configuration member: cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX member: cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX freeipa-3.3.4/install/share/default-smb-group.ldif0000664000175000017500000000037512271663206021461 0ustar mkosekmkosekdn: cn=Default SMB Group,cn=groups,cn=accounts,$SUFFIX changetype: add cn: Default SMB Group description: Fallback group for primary group RID, do not add users to this group gidnumber: -1 objectclass: top objectclass: ipaobject objectclass: posixgroup freeipa-3.3.4/install/share/unique-attributes.ldif0000664000175000017500000000656712202434255021621 0ustar mkosekmkosekdn: cn=krbPrincipalName uniqueness,cn=plugins,cn=config changetype: add objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: krbPrincipalName uniqueness nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: krbPrincipalName nsslapd-pluginarg1: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 nsslapd-pluginVendor: Fedora Project nsslapd-pluginDescription: Enforce unique attribute values dn: cn=krbCanonicalName uniqueness,cn=plugins,cn=config changetype: add objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: krbCanonicalName uniqueness nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: krbCanonicalName nsslapd-pluginarg1: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 nsslapd-pluginVendor: Fedora Project nsslapd-pluginDescription: Enforce unique attribute values dn: cn=netgroup uniqueness,cn=plugins,cn=config changetype: add objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: netgroup uniqueness nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: cn nsslapd-pluginarg1: cn=ng,cn=alt,$SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 nsslapd-pluginVendor: Fedora Project nsslapd-pluginDescription: Enforce unique attribute values dn: cn=ipaUniqueID uniqueness,cn=plugins,cn=config changetype: add objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: ipaUniqueID uniqueness nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: ipaUniqueID nsslapd-pluginarg1: $SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 nsslapd-pluginVendor: Fedora Project nsslapd-pluginDescription: Enforce unique attribute values dn: cn=sudorule name uniqueness,cn=plugins,cn=config changetype: add objectClass: top objectClass: nsSlapdPlugin objectClass: extensibleObject cn: sudorule name uniqueness nsslapd-pluginDescription: Enforce unique attribute values nsslapd-pluginPath: libattr-unique-plugin nsslapd-pluginInitfunc: NSUniqueAttr_Init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on nsslapd-pluginarg0: cn nsslapd-pluginarg1: cn=sudorules,cn=sudo,$SUFFIX nsslapd-plugin-depends-on-type: database nsslapd-pluginId: NSUniqueAttr nsslapd-pluginVersion: 1.1.0 nsslapd-pluginVendor: Fedora Project #dn: cn=uid uniqueness,cn=plugins,cn=config #objectClass: top #objectClass: nsSlapdPlugin #objectClass: extensibleObject #cn: uid uniqueness #nsslapd-pluginPath: libattr-unique-plugin #nsslapd-pluginInitfunc: NSUniqueAttr_Init #nsslapd-pluginType: preoperation #nsslapd-pluginEnabled: on #nsslapd-pluginarg0: uid #nsslapd-pluginarg1: cn=accounts,$SUFFIX #nsslapd-plugin-depends-on-type: database #nsslapd-pluginId: NSUniqueAttr #nsslapd-pluginVersion: 1.1.0 #nsslapd-pluginVendor: Fedora Project #nsslapd-pluginDescription: Enforce unique attribute values # freeipa-3.3.4/install/share/bootstrap-template.ldif0000664000175000017500000002246212271663206021753 0ustar mkosekmkosekdn: cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: accounts dn: cn=users,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: users dn: cn=groups,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: groups dn: cn=services,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: services dn: cn=computers,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: computers dn: cn=hostgroups,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: hostgroups dn: cn=alt,$SUFFIX changetype: add objectClass: nsContainer cn: alt dn: cn=ng,cn=alt,$SUFFIX changetype: add objectClass: nsContainer cn: ng dn: cn=automount,$SUFFIX changetype: add objectClass: nsContainer cn: automount dn: cn=default,cn=automount,$SUFFIX changetype: add objectClass: nsContainer cn: default dn: automountmapname=auto.master,cn=default,cn=automount,$SUFFIX changetype: add objectClass: automountMap automountMapName: auto.master dn: automountmapname=auto.direct,cn=default,cn=automount,$SUFFIX changetype: add objectClass: automountMap automountMapName: auto.direct dn: description=/- auto.direct,automountmapname=auto.master,cn=default,cn=automount,$SUFFIX changetype: add objectClass: automount automountKey: /- automountInformation: auto.direct description: /- auto.direct dn: cn=hbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: hbac dn: cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: hbacservices dn: cn=hbacservicegroups,cn=hbac,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: hbacservicegroups dn: cn=sudo,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: sudo dn: cn=sudocmds,cn=sudo,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: sudocmds dn: cn=sudocmdgroups,cn=sudo,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: sudocmdgroups dn: cn=sudorules,cn=sudo,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: sudorules dn: cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: etc dn: cn=sysaccounts,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: sysaccounts dn: cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: ipa dn: cn=masters,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: masters dn: cn=replicas,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: replicas dn: cn=dna,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: dna dn: cn=posix-ids,cn=dna,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: posix-ids dn: cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: ca_renewal dn: cn=s4u2proxy,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top cn: s4u2proxy dn: cn=ipa-http-delegation,cn=s4u2proxy,cn=etc,$SUFFIX changetype: add objectClass: ipaKrb5DelegationACL objectClass: groupOfPrincipals objectClass: top cn: ipa-http-delegation memberPrincipal: HTTP/$HOST@$REALM ipaAllowedTarget: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX ipaAllowedTarget: cn=ipa-cifs-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX dn: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX changetype: add objectClass: groupOfPrincipals objectClass: top cn: ipa-ldap-delegation-targets memberPrincipal: ldap/$HOST@$REALM dn: cn=ipa-cifs-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX changetype: add objectClass: groupOfPrincipals objectClass: top cn: ipa-cifs-delegation-targets dn: uid=admin,cn=users,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: person objectClass: posixaccount objectClass: krbprincipalaux objectClass: krbticketpolicyaux objectClass: inetuser objectClass: ipaobject objectClass: ipasshuser uid: admin krbPrincipalName: admin@$REALM cn: Administrator sn: Administrator uidNumber: $IDSTART gidNumber: $IDSTART homeDirectory: /home/admin loginShell: /bin/bash gecos: Administrator nsAccountLock: FALSE ipaUniqueID: autogenerate dn: cn=admins,cn=groups,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: posixgroup objectClass: ipausergroup objectClass: ipaobject cn: admins description: Account administrators group gidNumber: $IDSTART member: uid=admin,cn=users,cn=accounts,$SUFFIX nsAccountLock: FALSE ipaUniqueID: autogenerate dn: cn=ipausers,cn=groups,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: nestedgroup objectClass: ipausergroup objectClass: ipaobject description: Default group for all users cn: ipausers ipaUniqueID: autogenerate dn: cn=editors,cn=groups,cn=accounts,$SUFFIX changetype: add objectClass: top objectClass: groupofnames objectClass: posixgroup objectClass: ipausergroup objectClass: ipaobject gidNumber: eval($IDSTART+2) description: Limited admins who can edit other users cn: editors ipaUniqueID: autogenerate dn: cn=sshd,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: sshd description: sshd ipauniqueid:autogenerate dn: cn=ftp,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: ftp description: ftp ipauniqueid:autogenerate dn: cn=su,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: su description: su ipauniqueid:autogenerate dn: cn=login,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: login description: login ipauniqueid:autogenerate dn: cn=su-l,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: su-l description: su with login shell ipauniqueid:autogenerate dn: cn=sudo,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: sudo description: sudo ipauniqueid:autogenerate dn: cn=sudo-i,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: sudo-i description: sudo-i ipauniqueid:autogenerate dn: cn=gdm,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: gdm description: gdm ipauniqueid:autogenerate dn: cn=gdm-password,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: gdm-password description: gdm-password ipauniqueid:autogenerate dn: cn=kdm,cn=hbacservices,cn=hbac,$SUFFIX changetype: add objectclass: ipahbacservice objectclass: ipaobject cn: kdm description: kdm ipauniqueid:autogenerate dn: cn=Sudo,cn=hbacservicegroups,cn=hbac,$SUFFIX changetype: add objectClass: ipaobject objectClass: ipahbacservicegroup objectClass: nestedGroup objectClass: groupOfNames objectClass: top cn: Sudo ipauniqueid:autogenerate description: Default group of Sudo related services member: cn=sudo,cn=hbacservices,cn=hbac,$SUFFIX member: cn=sudo-i,cn=hbacservices,cn=hbac,$SUFFIX dn: cn=ipaConfig,cn=etc,$SUFFIX changetype: add objectClass: nsContainer objectClass: top objectClass: ipaGuiConfig objectClass: ipaConfigObject ipaUserSearchFields: uid,givenname,sn,telephonenumber,ou,title ipaGroupSearchFields: cn,description ipaSearchTimeLimit: 2 ipaSearchRecordsLimit: 100 ipaHomesRootDir: /home ipaDefaultLoginShell: /bin/sh ipaDefaultPrimaryGroup: ipausers ipaMaxUsernameLength: 32 ipaPwdExpAdvNotify: 4 ipaGroupObjectClasses: top ipaGroupObjectClasses: groupofnames ipaGroupObjectClasses: nestedgroup ipaGroupObjectClasses: ipausergroup ipaGroupObjectClasses: ipaobject ipaUserObjectClasses: top ipaUserObjectClasses: person ipaUserObjectClasses: organizationalperson ipaUserObjectClasses: inetorgperson ipaUserObjectClasses: inetuser ipaUserObjectClasses: posixaccount ipaUserObjectClasses: krbprincipalaux ipaUserObjectClasses: krbticketpolicyaux ipaUserObjectClasses: ipaobject ipaUserObjectClasses: ipasshuser ipaDefaultEmailDomain: $DOMAIN ipaMigrationEnabled: FALSE ipaConfigString: AllowNThash ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 dn: cn=cosTemplates,cn=accounts,$SUFFIX changetype: add objectclass: top objectclass: nsContainer cn: cosTemplates # templates for this cos definition are managed by the pwpolicy plugin dn: cn=Password Policy,cn=accounts,$SUFFIX changetype: add description: Password Policy based on group membership objectClass: top objectClass: ldapsubentry objectClass: cosSuperDefinition objectClass: cosClassicDefinition cosTemplateDn: cn=cosTemplates,cn=accounts,$SUFFIX cosAttribute: krbPwdPolicyReference override cosSpecifier: memberOf dn: cn=selinux,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: selinux dn: cn=usermap,cn=selinux,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: usermap dn: cn=ranges,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: nsContainer cn: ranges dn: cn=${REALM}_id_range,cn=ranges,cn=etc,$SUFFIX changetype: add objectClass: top objectClass: ipaIDrange objectClass: ipaDomainIDRange cn: ${REALM}_id_range ipaBaseID: $IDSTART ipaIDRangeSize: $IDRANGE_SIZE ipaRangeType: ipa-local freeipa-3.3.4/install/share/sasl-mapping-fallback.ldif0000664000175000017500000000015212271663206022245 0ustar mkosekmkosekdn: cn=config changetype: modify replace: nsslapd-sasl-mapping-fallback nsslapd-sasl-mapping-fallback: on freeipa-3.3.4/install/share/65ipasudo.ldif0000664000175000017500000001142012271663206017734 0ustar mkosekmkosekdn: cn=schema ## ## IPA SUDO schema (added in IPA v2) ## ## Attributes: 2.16.840.1.113730.3.8.7.x ## ObjectClasses: 2.16.840.1.113730.3.8.8.x ## ## Attribute to store DN of an allowed SUDO command or a group of SUDO commands attributetypes: (2.16.840.1.113730.3.8.7.1 NAME 'memberAllowCmd' DESC 'Reference to a command or group of commands that are allowed by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) ## Attribute to store DN of a prohibited SUDO command or a group of SUDO commands attributetypes: (2.16.840.1.113730.3.8.7.2 NAME 'memberDenyCmd' DESC 'Reference to a command or group of commands that are denied by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) ## Attribute to store command category attributeTypes: (2.16.840.1.113730.3.8.7.3 NAME 'cmdCategory' DESC 'Additional classification for commands' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to store user not managed by the central server attributetypes: (2.16.840.1.113730.3.8.7.4 NAME 'externalUser' DESC 'Multivalue string attribute that allows storing user names.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to store sudo options attributetypes: (2.16.840.1.113730.3.8.7.5 NAME 'ipaSudoOpt' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v2' ) ## Attribute to store the reference identity under which the command should be run attributeTypes: (2.16.840.1.113730.3.8.7.6 NAME 'ipaSudoRunAs' DESC 'Reference to a user or group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) ## Attribute to store a name of the user not managed by IPA. Command witll be executed under his identity. attributeTypes: (2.16.840.1.113730.3.8.7.7 NAME 'ipaSudoRunAsExtUser' DESC 'Multivalue string attribute that allows storing user name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to express category of identities that the command can be run under attributeTypes: (2.16.840.1.113730.3.8.7.8 NAME 'ipaSudoRunAsUserCategory' DESC 'Additional classification for users' SUP userCategory X-ORIGIN 'IPA v2' ) ## Attribute to store a reference to the "run as group" identitity attributeTypes: (2.16.840.1.113730.3.8.7.9 NAME 'ipaSudoRunAsGroup' DESC 'Reference to group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) ## Attribute to store a name of the "run as group" identitity if this group is not directly managed by IPA attributeTypes: (2.16.840.1.113730.3.8.7.10 NAME 'ipaSudoRunAsExtGroup' DESC 'Multivalue string attribute that allows storing group name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to express category of group identities that the command can be run under attributeTypes: (2.16.840.1.113730.3.8.7.11 NAME 'ipaSudoRunAsGroupCategory' DESC 'Additional classification for groups' SUP userCategory X-ORIGIN 'IPA v2' ) ## Attribute to store host mask attributeTypes: (2.16.840.1.113730.3.8.7.12 NAME 'hostMask' DESC 'IP mask to identify a subnet.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Attribute to store sudo command attributeTypes: (2.16.840.1.113730.3.8.7.13 NAME 'sudoCmd' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactMatch ORDERING caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) ## Object class for SUDO rules objectClasses: (2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $ externalHost $ hostMask $ memberAllowCmd $ memberDenyCmd $ cmdCategory $ ipaSudoOpt $ ipaSudoRunAs $ ipaSudoRunAsExtUser $ ipaSudoRunAsUserCategory $ ipaSudoRunAsGroup $ ipaSudoRunAsExtGroup $ ipaSudoRunAsGroupCategory $ sudoNotBefore $ sudoNotAfter $ sudoOrder ) X-ORIGIN 'IPA v2' ) ## Object class for SUDO commands objectClasses: (2.16.840.1.113730.3.8.8.2 NAME 'ipaSudoCmd' DESC 'IPA object class for SUDO command' STRUCTURAL MUST ( ipaUniqueID $ sudoCmd ) MAY ( memberOf $ description ) X-ORIGIN 'IPA v2' ) ## Object class for groups of the SUDO commands objectClasses: (2.16.840.1.113730.3.8.8.3 NAME 'ipaSudoCmdGrp' DESC 'IPA object class to store groups of SUDO commands' SUP groupOfNames MUST ( ipaUniqueID ) STRUCTURAL X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/share/root-autobind.ldif0000664000175000017500000000054112202434255020677 0ustar mkosekmkosek# root-autobind, config dn: cn=root-autobind,cn=config changetype: add objectClass: extensibleObject objectClass: top cn: root-autobind uidNumber: 0 gidNumber: 0 dn: cn=config changetype: modify replace: nsslapd-ldapiautobind nsslapd-ldapiautobind: on dn: cn=config changetype: modify replace: nsslapd-ldapimaptoentries nsslapd-ldapimaptoentries: on freeipa-3.3.4/install/share/krb5.conf.template0000664000175000017500000000116312271663206020604 0ustar mkosekmkosekincludedir /var/lib/sss/pubconf/krb5.include.d/ [logging] default = FILE:/var/log/krb5libs.log kdc = FILE:/var/log/krb5kdc.log admin_server = FILE:/var/log/kadmind.log [libdefaults] default_realm = $REALM dns_lookup_realm = false dns_lookup_kdc = true rdns = false ticket_lifetime = 24h forwardable = yes $OTHER_LIBDEFAULTS [realms] $REALM = { kdc = $FQDN:88 master_kdc = $FQDN:88 admin_server = $FQDN:749 default_domain = $DOMAIN pkinit_anchors = FILE:/etc/ipa/ca.crt } [domain_realm] .$DOMAIN = $REALM $DOMAIN = $REALM $OTHER_DOMAIN_REALM_MAPS [dbmodules] $REALM = { db_library = ipadb.so } freeipa-3.3.4/install/share/60ipaconfig.ldif0000664000175000017500000001203112270466515020224 0ustar mkosekmkosek## schema file for ipa configuration ## ## IPA Base OID: 2.16.840.1.113730.3.8 ## ## Attributes: 2.16.840.1.113730.3.8.1 - V1 ## ObjectClasses: 2.16.840.1.113730.3.8.2 - V1 ## Attributes: 2.16.840.1.113730.3.8.3 - V2 ## ObjectClasses: 2.16.840.1.113730.3.8.4 - V2 dn: cn=schema ############################################### ## ## Attributes ## ## ipaUserSearchFields - attribute names to search against when looking for users attributetypes: ( 2.16.840.1.113730.3.8.1.1 NAME 'ipaUserSearchFields' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) ## ipaGroupSearchFields - attribute names to search against when looking for groups attributetypes: ( 2.16.840.1.113730.3.8.1.2 NAME 'ipaGroupSearchFields' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) ## ipaSearchTimeLimit - search time limit in seconds attributetypes: ( 2.16.840.1.113730.3.8.1.3 NAME 'ipaSearchTimeLimit' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ## ipaSearchRecordsLimit - maximum number of records to return attributetypes: ( 2.16.840.1.113730.3.8.1.4 NAME 'ipaSearchRecordsLimit' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ## ipaCustomFields - custom fields to show in the UI in addition to pre-defined ones attributetypes: ( 2.16.840.1.113730.3.8.1.5 NAME 'ipaCustomFields' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ## ipaHomesRootDir - default posix home directory root dir to use when creating new accounts attributetypes: ( 2.16.840.1.113730.3.8.1.6 NAME 'ipaHomesRootDir' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE) ## ipaDefaultLoginShell - default posix login shell to use when creating new accounts attributetypes: ( 2.16.840.1.113730.3.8.1.7 NAME 'ipaDefaultLoginShell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE) ## ipaDefaultPrimaryGroup - default posix primary group to assign when creating new accounts attributetypes: ( 2.16.840.1.113730.3.8.1.8 NAME 'ipaDefaultPrimaryGroup' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE) ## ipaMaxUsernameLength - maximum username length to allow in the UI attributetypes: ( 2.16.840.1.113730.3.8.1.9 NAME 'ipaMaxUsernameLength' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) ## ipaPwdExpAdvNotify - time in days to send out paswword expiration notification before passwpord actually expires attributetypes: ( 2.16.840.1.113730.3.8.1.10 NAME 'ipaPwdExpAdvNotify' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE) # ipaUserObjectClasses - required objectclasses for users attributetypes: ( 2.16.840.1.113730.3.8.1.11 NAME 'ipaUserObjectClasses' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) # ipaGroupObjectClasses - required objectclasses for groups attributetypes: ( 2.16.840.1.113730.3.8.1.12 NAME 'ipaGroupObjectClasses' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) attributetypes: ( 2.16.840.1.113730.3.8.1.13 NAME 'ipaDefaultEmailDomain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) # ipaMigrationEnabled - if TRUE allow adding user entries with pre-hashed passwords attributeTypes: ( 2.16.840.1.113730.3.8.3.22 NAME 'ipaMigrationEnabled' DESC 'Enable adding user entries with pre-hashed passwords.' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE ) attributetypes: ( 2.16.840.1.113730.3.8.3.23 NAME 'ipaCertificateSubjectBase' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15) ## ipaConfigString - can hold any string to be used as configuration for something (it is multivalued) attributeTypes: (2.16.840.1.113730.3.8.3.16 NAME 'ipaConfigString' DESC 'Generic configuration stirng' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.26 NAME 'ipaSELinuxUserMapDefault' DESC 'Default SELinux user' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') attributeTypes: ( 2.16.840.1.113730.3.8.3.27 NAME 'ipaSELinuxUserMapOrder' DESC 'Available SELinux user context ordering' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') ############################################### ## ## ObjectClasses ## ## ipaGuiConfig - GUI config parameters objectclass 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) ) ## ipaConfigObject - Generic config strings object holder objectClasses: (2.16.840.1.113730.3.8.4.13 NAME 'ipaConfigObject' DESC 'generic config object for IPA' AUXILIARY MAY ( ipaConfigString ) X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/share/krb.con.template0000664000175000017500000000005512202434255020342 0ustar mkosekmkosek$REALM $DOMAIN $REALM $DOMAIN admin server freeipa-3.3.4/install/share/70ipaotp.ldif0000664000175000017500000001206012271663206017561 0ustar mkosekmkosek# IPA OTP schema # BaseOID: 2.16.840.1.113730.3.8.16 # See RFC 4517 for Syntax OID definitions dn: cn=schema attributeTypes: (2.16.840.1.113730.3.8.16.1.1 NAME 'ipatokenUniqueID' DESC 'Token Unique Identifier' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.2 NAME 'ipatokenDisabled' DESC 'Optionally marks token as Disabled' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.3 NAME 'ipatokenNotBefore' DESC 'Token validity date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.4 NAME 'ipatokenNotAfter' DESC 'Token expiration date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.5 NAME 'ipatokenVendor' DESC 'Optional Vendor identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.6 NAME 'ipatokenModel' DESC 'Optional Model identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.7 NAME 'ipatokenSerial' DESC 'OTP Token Serial number' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.8 NAME 'ipatokenOTPkey' DESC 'OTP Token Key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.9 NAME 'ipatokenOTPalgorithm' DESC 'OTP Token Algorithm' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.10 NAME 'ipatokenOTPdigits' DESC 'OTP Token Number of digits' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.11 NAME 'ipatokenTOTPclockOffset' DESC 'TOTP clock offset' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.12 NAME 'ipatokenTOTPtimeStep' DESC 'TOTP time-step' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.13 NAME 'ipatokenOwner' DESC 'User entry that owns this token' SUP distinguishedName SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.14 NAME 'ipatokenRadiusUserName' DESC 'Corresponding Radius username' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.15 NAME 'ipatokenRadiusConfigLink' DESC 'Corresponding Radius Configuration link' SUP distinguishedName SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.16 NAME 'ipatokenRadiusServer' DESC 'Server String Configuration' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.17 NAME 'ipatokenRadiusSecret' DESC 'Server Secret' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.18 NAME 'ipatokenRadiusTimeout' DESC 'Server Timeout' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.19 NAME 'ipatokenRadiusRetries' DESC 'Number of allowed Retries' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') attributeTypes: (2.16.840.1.113730.3.8.16.1.20 NAME 'ipatokenUserMapAttribute' DESC 'Attribute to map from the user entry for RADIUS server authentication' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') objectClasses: (2.16.840.1.113730.3.8.16.2.1 NAME 'ipaToken' SUP top ABSTRACT DESC 'Abstract token class for tokens' MUST (ipatokenUniqueID) MAY (description $ ipatokenOwner $ ipatokenDisabled $ ipatokenNotBefore $ ipatokenNotAfter $ ipatokenVendor $ ipatokenModel $ ipatokenSerial) X-ORIGIN 'IPA OTP') objectClasses: (2.16.840.1.113730.3.8.16.2.2 NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MAY (ipatokenOTPkey $ ipatokenOTPalgorithm $ ipatokenOTPdigits $ ipatokenTOTPclockOffset $ ipatokenTOTPtimeStep) X-ORIGIN 'IPA OTP') objectClasses: (2.16.840.1.113730.3.8.16.2.3 NAME 'ipatokenRadiusProxyUser' SUP top AUXILIARY DESC 'Radius Proxy User' MUST (ipatokenRadiusConfigLink) MAY (ipatokenRadiusUserName) X-ORIGIN 'IPA OTP') objectClasses: (2.16.840.1.113730.3.8.16.2.4 NAME 'ipatokenRadiusConfiguration' SUP top STRUCTURAL DESC 'Proxy Radius Configuration' MUST (cn $ ipatokenRadiusServer $ ipatokenRadiusSecret) MAY (description $ ipatokenRadiusTimeout $ ipatokenRadiusRetries $ ipatokenUserMapAttribute) X-ORIGIN 'IPA OTP') freeipa-3.3.4/install/share/60policyv2.ldif0000664000175000017500000001266112202434255020034 0ustar mkosekmkosek# Policy related schema. # This file should not be loaded. # Remove this comment and assign right OIDs when time comes to do something # about this functionality. dn: cn=schema attributeTypes: (2.16.840.1.113730.3.8.L.1 NAME 'ipaPolicyType' DESC 'Type of the policy' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.2 NAME 'ipaSchemaFile' DESC 'Name of the file with schema definition' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.3 NAME 'ipaTrasformFile' DESC 'Name of the policy transformation file' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.4 NAME 'ipaOrderedUUIDList' DESC 'Defines order of the entities within some sort of ordered group' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.5 NAME 'ipaLastChangeBy' DESC 'DN of the user who caused the configuration change' SUP owner EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.6 NAME 'ipaLastChanged' DESC 'Last time there was some change to the data' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.7 NAME 'ipaAllowedTemplateRef' DESC 'DN of the allowed policy template' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.8 NAME 'ipaTemplateRef' DESC 'DN of the allowed policy template' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.9 NAME 'ipaPolicyBlob' DESC 'Compressed XML policy data in binary format' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.10 NAME 'ipaPolicyState' DESC 'State of the policy data' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.11 NAME 'ipaPolicyGroupRef' DESC 'DN of the member policy group reference' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.12 NAME 'ipaRoleType' DESC 'Type of the role' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.13 NAME 'ipaRoleOrder' DESC 'List of possible roles in priority order' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.L.14 NAME 'ipaRoleRef' DESC 'DN of the role definition policy' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) attributeTypes: (2.16.840.1.113730.3.8.L.15 NAME 'ipaRoleName' DESC 'Name of the role' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.1 NAME 'ipaContainer' SUP nsContainer STRUCTURAL MAY description X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.2 NAME 'ipaPolicyTemplate' SUP top STRUCTURAL MUST ( cn $ ipaUniqueID $ ipaPolicyType $ ipaSchemaFile ) MAY ( ipaTrasformFile $ description ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.3 NAME 'ipaOrderedContainer' SUP ipaContainer STRUCTURAL MAY ( ipaOrderedUUIDList $ ipaLastChangeBy $ ipaLastChanged ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.4 NAME 'ipaPolicyGroup' SUP ipaOrderedContainer STRUCTURAL MUST ( ipaUniqueID $ ipaEnabledFlag ) MAY ipaAllowedTemplateRef X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.5 NAME 'ipaPolicy' SUP ipaContainer STRUCTURAL MUST ( ipaUniqueID $ ipaEnabledFlag $ ipaTemplateRef ) MAY ( ipaLastChangeBy $ ipaLastChanged ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.6 NAME 'ipaPolicyData' SUP top STRUCTURAL MUST ( ipaUniqueID $ cn $ ipaPolicyState $ ipaLastChangeBy $ ipaLastChanged ) MAY ( ipaPolicyBlob $ description ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.7 NAME 'ipaPolicyLink' SUP ipaAssociation STRUCTURAL MAY ( ipaPolicyGroupRef $ owner ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.8 NAME 'ipaRelationsContainer' SUP ipaContainer STRUCTURAL MUST ( ipaRoleType $ ipaRoleOrder ) X-ORIGIN 'IPA v2' ) objectClasses: (2.16.840.1.113730.3.8.M.9 NAME 'ipaRelation' SUP ipaAssociation STRUCTURAL MUST ( ipaRoleRef $ ipaRoleName ) X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/share/disable-betxn.ldif0000664000175000017500000000303012202434255020626 0ustar mkosekmkosek# Disable transactions in 389-ds-base dn: cn=7-bit check,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=attribute uniqueness,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=Auto Membership Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=Linked Attributes,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=Managed Entries,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=MemberOf Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: postoperation dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginbetxn nsslapd-pluginbetxn: off dn: cn=PAM Pass Through Auth,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: preoperation dn: cn=referential integrity postoperation,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: postoperation dn: cn=Roles Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginbetxn nsslapd-pluginbetxn: off dn: cn=State Change Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginType nsslapd-pluginType: postoperation dn: cn=USN,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginbetxn nsslapd-pluginbetxn: off freeipa-3.3.4/install/share/61kerberos-ipav3.ldif0000664000175000017500000000066712202434255021125 0ustar mkosekmkosekdn: cn=schema 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') objectClasses: (2.16.840.1.113730.3.8.12.8 NAME 'ipaKrbPrincipal' SUP krbPrincipalAux AUXILIARY MUST ( krbPrincipalName $ ipaKrbPrincipalAlias ) X-ORIGIN 'IPA v3' ) freeipa-3.3.4/install/share/memberof-conf.ldif0000664000175000017500000000034712202434255020634 0ustar mkosekmkosekdn: cn=MemberOf Plugin,cn=plugins,cn=config changetype: modify replace: nsslapd-pluginenabled nsslapd-pluginenabled: on - add: memberofgroupattr memberofgroupattr: memberUser - add: memberofgroupattr memberofgroupattr: memberHost freeipa-3.3.4/install/share/ldapi.ldif0000664000175000017500000000016312202434255017202 0ustar mkosekmkosek# Enable the ldapi listener dn: cn=config changetype: modify replace: nsslapd-ldapilisten nsslapd-ldapilisten: on freeipa-3.3.4/install/share/Makefile.in0000664000175000017500000005114112271707662017333 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = share DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = SUBDIRS = \ advise \ $(NULL) appdir = $(IPA_DATA_DIR) app_DATA = \ 05rfc2247.ldif \ 60kerberos.ldif \ 60samba.ldif \ 60ipaconfig.ldif \ 60basev2.ldif \ 60basev3.ldif \ 60ipadns.ldif \ 61kerberos-ipav3.ldif \ 65ipasudo.ldif \ 70ipaotp.ldif \ anonymous-vlv.ldif \ bootstrap-template.ldif \ caJarSigningCert.cfg.template \ default-aci.ldif \ default-hbac.ldif \ default-smb-group.ldif \ delegation.ldif \ disable-betxn.ldif \ replica-acis.ldif \ ds-nfiles.ldif \ dns.ldif \ kerberos.ldif \ indices.ldif \ bind.named.conf.template \ bind.zone.db.template \ certmap.conf.template \ kdc.conf.template \ kdc_extensions.template \ kdc_req.conf.template \ krb5.conf.template \ krb5.ini.template \ krb.con.template \ krb.js.template \ krbrealm.con.template \ preferences.html.template \ smb.conf.template \ smb.conf.empty \ referint-conf.ldif \ dna.ldif \ master-entry.ldif \ memberof-task.ldif \ memberof-conf.ldif \ nis.uldif \ unique-attributes.ldif \ schema_compat.uldif \ ldapi.ldif \ wsgi.py \ repoint-managed-entries.ldif \ managed-entries.ldif \ user_private_groups.ldif \ host_nis_groups.ldif \ uuid-ipauniqueid.ldif \ modrdn-krbprinc.ldif \ entryusn.ldif \ root-autobind.ldif \ sudobind.ldif \ automember.ldif \ replica-automember.ldif \ replica-s4u2proxy.ldif \ copy-schema-to-ca.py \ upload-cacert.ldif \ sasl-mapping-fallback.ldif \ schema-update.ldif \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign share/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign share/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-appDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-appDATA .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/share/kdc_extensions.template0000664000175000017500000000146512202434255022034 0ustar mkosekmkosek[ kdc_cert ] basicConstraints=CA:FALSE # Here are some examples of the usage of nsCertType. If it is omitted keyUsage = nonRepudiation, digitalSignature, keyEncipherment, keyAgreement #Pkinit EKU extendedKeyUsage = 1.3.6.1.5.2.3.5 subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer # Copy subject details issuerAltName=issuer:copy # Add id-pkinit-san (pkinit subjectAlternativeName) # Also add the KDC fqdn, for good measure. subjectAltName=otherName:1.3.6.1.5.2.2;SEQUENCE:kdc_princ_name,DNS:${ENV::HOST_FQDN} [kdc_princ_name] realm = EXP:0, GeneralString:${ENV::REALM} principal_name = EXP:1, SEQUENCE:kdc_principal_seq [kdc_principal_seq] name_type = EXP:0, INTEGER:1 name_string = EXP:1, SEQUENCE:kdc_principals [kdc_principals] princ1 = GeneralString:krbtgt princ2 = GeneralString:${ENV::REALM} freeipa-3.3.4/install/share/memberof-task.ldif0000664000175000017500000000042512202434255020646 0ustar mkosekmkosek# Note, if you change this dn also update the dn in # ipaserver/install/dsinstance.py dn: cn=IPA install $TIME, cn=memberof task, cn=tasks, cn=config changetype: add objectClass: top objectClass: extensibleObject cn: IPA install basedn: $SUFFIX filter: (objectclass=*) ttl: 10 freeipa-3.3.4/install/share/default-hbac.ldif0000664000175000017500000000062212202434255020430 0ustar mkosekmkosek# default HBAC policy that grants permission to all services dn: ipauniqueid=autogenerate,cn=hbac,$SUFFIX changetype: add objectclass: ipaassociation objectclass: ipahbacrule cn: allow_all accessruletype: allow usercategory: all hostcategory: all sourcehostcategory: all servicecategory: all ipaenabledflag: TRUE description: Allow all users to access any host from any host ipauniqueid: autogenerate freeipa-3.3.4/install/share/replica-acis.ldif0000664000175000017500000000405012271663206020452 0ustar mkosekmkosek# Replica administration dn: cn=config changetype: modify add: aci aci: (targetattr != aci)(version 3.0; aci "replica admins read access"; allow (read, search, compare) groupdn = "ldap:///cn=Modify Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) dn: cn="$SUFFIX",cn=mapping tree,cn=config changetype: modify add: aci aci: (targetattr=*)(version 3.0;acl "permission:Add Replication Agreements";allow (add) groupdn = "ldap:///cn=Add Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) dn: cn="$SUFFIX",cn=mapping tree,cn=config changetype: modify add: aci aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5Replica)(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement)(objectClass=nsMappingTree))")(version 3.0; acl "permission:Modify Replication Agreements"; allow (read, write, search) groupdn = "ldap:///cn=Modify Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) dn: cn="$SUFFIX",cn=mapping tree,cn=config changetype: modify add: aci aci: (targetattr=*)(targetfilter="(|(objectclass=nsds5replicationagreement)(objectclass=nsDSWindowsReplicationAgreement))")(version 3.0;acl "permission:Remove Replication Agreements";allow (delete) groupdn = "ldap:///cn=Remove Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config changetype: modify add: aci aci: (targetattr=dnaNextRange || dnaNextValue || dnaMaxValue)(version 3.0;acl "permission:Modify DNA Range";allow (write) groupdn = "ldap:///cn=Modify DNA Range,cn=permissions,cn=pbac,$SUFFIX";) dn: cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: modify add: aci aci: (targetattr=nsslapd-readonly)(version 3.0; acl "Allow marking the database readonly"; allow (write) groupdn = "ldap:///cn=Remove Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) dn: cn=tasks,cn=config changetype: modify add: aci aci: (targetattr=*)(version 3.0; acl "Run tasks after replica re-initialization"; allow (add) groupdn = "ldap:///cn=Modify Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";) freeipa-3.3.4/install/share/indices.ldif0000664000175000017500000001210412271663206017533 0ustar mkosekmkosekdn: cn=krbPrincipalName,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:krbPrincipalName nsSystemIndex:false nsIndexType:eq nsIndexType:sub dn: cn=ou,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:ou nsSystemIndex:false nsIndexType:eq nsIndexType:sub dn: cn=carLicense,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:carLicense nsSystemIndex:false nsIndexType:eq nsIndexType:sub dn: cn=title,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:title nsSystemIndex:false nsIndexType:eq nsIndexType:sub dn: cn=manager,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:manager nsSystemIndex:false nsIndexType:eq nsIndexType:pres nsIndexType:sub dn: cn=secretary,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:secretary nsSystemIndex:false nsIndexType:eq nsIndexType:pres nsIndexType:sub dn: cn=displayname,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:displayname nsSystemIndex:false nsIndexType:eq nsIndexType:sub dn: cn=uid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: modify add: nsIndexType nsIndexType:sub dn: cn=uidnumber,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:uidnumber nsSystemIndex:false nsIndexType:eq nsMatchingRule: integerOrderingMatch dn: cn=gidnumber,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add objectClass:top objectClass:nsIndex cn:gidnumber nsSystemIndex:false nsIndexType:eq nsMatchingRule: integerOrderingMatch dn: cn=ntUniqueId,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: modify replace: nsIndexType nsIndexType: eq,pres dn: cn=ntUserDomainId,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: modify replace: nsIndexType nsIndexType: eq,pres dn: cn=fqdn,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add ObjectClass: top ObjectClass: nsIndex cn: fqdn nsSystemIndex: false nsIndexType: eq nsIndexType: pres dn: cn=macAddress,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add ObjectClass: top ObjectClass: nsIndex cn: macAddress nsSystemIndex: false nsIndexType: eq nsIndexType: pres dn: cn=memberHost,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: memberHost ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=memberUser,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: memberUser ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=sourcehost,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: sourcehost ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=memberservice,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: memberservice ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=managedby,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: managedby ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=memberallowcmd,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: memberallowcmd ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=memberdenycmd,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: memberdenycmd ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=ipasudorunas,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: ipasudorunas ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=ipasudorunasgroup,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: ipasudorunasgroup ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq nsIndexType: pres nsIndexType: sub dn: cn=automountkey,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: automountkey ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq dn: cn=ipakrbprincipalalias,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: ipakrbprincipalalias ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq dn: cn=ipauniqueid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config changetype: add cn: ipauniqueid ObjectClass: top ObjectClass: nsIndex nsSystemIndex: false nsIndexType: eq freeipa-3.3.4/install/share/60basev3.ldif0000664000175000017500000002371412271663206017457 0ustar mkosekmkosek## IPA Base OID: 2.16.840.1.113730.3.8 ## ## Attributes: 2.16.840.1.113730.3.8.11 - V3 base attributres ## ObjectClasses: 2.16.840.1.113730.3.8.12 - V3 base objectclasses ## dn: cn=schema attributeTypes: (2.16.840.1.113730.3.8.11.1 NAME 'ipaExternalMember' DESC 'External Group Member Identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.2 NAME 'ipaNTSecurityIdentifier' DESC 'NT Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.23 NAME 'ipaNTTrustedDomainSID' DESC 'NT Trusted Domain Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.3 NAME 'ipaNTFlatName' DESC 'Flat/Netbios Name' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.4 NAME 'ipaNTFallbackPrimaryGroup' DESC 'Fallback Group to set the Primary group Security Identifier for users with UPGs' SUP distinguishedName X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.5 NAME 'ipaNTHash' DESC 'NT Hash of user password' EQUALITY octetStringMatch ORDERING octetStringOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.6 NAME 'ipaNTLogonScript' DESC 'User Logon Script Name' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.7 NAME 'ipaNTProfilePath' DESC 'User Profile Path' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.8 NAME 'ipaNTHomeDirectory' DESC 'User Home Directory Path' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.9 NAME 'ipaNTHomeDirectoryDrive' DESC 'User Home Drive Letter' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.10 NAME 'ipaNTDomainGUID' DESC 'NT Domain GUID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) attributeTypes: ( 2.16.840.1.113730.3.8.11.11 NAME 'ipaNTTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 2.16.840.1.113730.3.8.11.12 NAME 'ipaNTTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 2.16.840.1.113730.3.8.11.13 NAME 'ipaNTTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 2.16.840.1.113730.3.8.11.14 NAME 'ipaNTTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) attributeTypes: ( 2.16.840.1.113730.3.8.11.15 NAME 'ipaNTTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) attributeTypes: ( 2.16.840.1.113730.3.8.11.16 NAME 'ipaNTTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) attributeTypes: ( 2.16.840.1.113730.3.8.11.17 NAME 'ipaNTTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) attributeTypes: ( 2.16.840.1.113730.3.8.11.18 NAME 'ipaNTTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 2.16.840.1.113730.3.8.11.19 NAME 'ipaNTSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) attributeTypes: ( 2.16.840.1.113730.3.8.11.20 NAME 'memberPrincipal' DESC 'Principal names member of a groupOfPrincipals group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA-v3') attributeTypes: ( 2.16.840.1.113730.3.8.11.21 NAME 'ipaAllowToImpersonate' DESC 'Principals that can be impersonated' SUP distinguishedName X-ORIGIN 'IPA-v3') attributeTypes: ( 2.16.840.1.113730.3.8.11.22 NAME 'ipaAllowedTarget' DESC 'Target principals alowed to get a ticket for' SUP distinguishedName X-ORIGIN 'IPA-v3') attributeTypes: (2.16.840.1.113730.3.8.11.30 NAME 'ipaSELinuxUser' DESC 'An SELinux user' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3') attributeTypes: (2.16.840.1.113730.3.8.11.31 NAME 'ipaSshPubKey' DESC 'SSH public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v3' ) attributeTypes: (2.16.840.1.113730.3.8.11.33 NAME 'ipaBaseID' DESC 'First value 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.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 attributeTypes: (2.16.840.1.113730.3.8.11.38 NAME 'ipaNTSIDBlacklistIncoming' DESC 'Extra SIDs filtered out from incoming MS-PAC' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3') attributeTypes: (2.16.840.1.113730.3.8.11.39 NAME 'ipaNTSIDBlacklistOutgoing' DESC 'Extra SIDs filtered out from outgoing MS-PAC' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3') attributeTypes: (2.16.840.1.113730.3.8.11.40 NAME 'ipaUserAuthType' DESC 'Allowed authentication methods' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v3') attributeTypes: (2.16.840.1.113730.3.8.11.41 NAME 'ipaRangeType' DESC 'Range type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3' ) 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' ) objectClasses: (2.16.840.1.113730.3.8.12.4 NAME 'ipaNTDomainAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier $ ipaNTFlatName $ ipaNTDomainGUID ) MAY ( ipaNTFallbackPrimaryGroup ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $ ipaNTTrustAttributes $ ipaNTTrustDirection $ ipaNTTrustPartner $ ipaNTFlatName $ ipaNTTrustAuthOutgoing $ ipaNTTrustAuthIncoming $ ipaNTTrustedDomainSID $ ipaNTTrustForestTrustInfo $ ipaNTTrustPosixOffset $ ipaNTSupportedEncryptionTypes $ ipaNTSIDBlacklistIncoming $ ipaNTSIDBlacklistOutgoing) ) objectClasses: (2.16.840.1.113730.3.8.12.6 NAME 'groupOfPrincipals' SUP top AUXILIARY MUST ( cn ) MAY ( memberPrincipal ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.7 NAME 'ipaKrb5DelegationACL' SUP groupOfPrincipals STRUCTURAL MAY ( ipaAllowToImpersonate $ ipaAllowedTarget ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.10 NAME 'ipaSELinuxUserMap' SUP ipaAssociation STRUCTURAL MUST ipaSELinuxUser MAY ( accessTime $ seeAlso ) X-ORIGIN 'IPA v3') objectClasses: (2.16.840.1.113730.3.8.12.11 NAME 'ipaSshGroupOfPubKeys' ABSTRACT MAY ipaSshPubKey X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.12 NAME 'ipaSshUser' SUP ipaSshGroupOfPubKeys AUXILIARY X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.13 NAME 'ipaSshHost' SUP ipaSshGroupOfPubKeys AUXILIARY X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.14 NAME 'ipaIDobject' SUP top AUXILIARY MAY ( uidNumber $ gidNumber $ ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.15 NAME 'ipaIDrange' ABSTRACT MUST ( cn $ ipaBaseID $ ipaIDRangeSize $ ipaRangeType ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.16 NAME 'ipaDomainIDRange' SUP ipaIDrange STRUCTURAL MAY ( ipaBaseRID $ ipaSecondaryBaseRID ) X-ORIGIN 'IPA v3' ) objectClasses: (2.16.840.1.113730.3.8.12.17 NAME 'ipaTrustedADDomainRange' SUP ipaIDrange STRUCTURAL MUST ( ipaBaseRID $ ipaNTTrustedDomainSID ) X-ORIGIN 'IPA v3' ) objectclasses: (2.16.840.1.113730.3.8.12.19 NAME 'ipaUserAuthTypeClass' SUP top AUXILIARY DESC 'Class for authentication methods definition' MAY ipaUserAuthType X-ORIGIN 'IPA v3') freeipa-3.3.4/install/share/caJarSigningCert.cfg.template0000664000175000017500000001232112202434255022720 0ustar mkosekmkosekdesc=Jar Signing certificate to auto-configure Firefox enable=true enableBy=admin lastModified=1239836280692 name=Manual Jar Signing Certificate Enrollment visible=true auth.class_id= auth.instance_id=raCertAuth input.list=i1,i2 input.i1.class_id=certReqInputImpl input.i2.class_id=submitterInfoInputImpl output.list=o1 output.o1.class_id=certOutputImpl policyset.list=caJarSigningSet policyset.caJarSigningSet.list=1,2,3,6,7,9 policyset.caJarSigningSet.1.constraint.class_id=subjectNameConstraintImpl policyset.caJarSigningSet.1.constraint.name=Subject Name Constraint policyset.caJarSigningSet.1.constraint.params.accept=true policyset.caJarSigningSet.1.constraint.params.pattern=.* policyset.caJarSigningSet.1.default.class_id=userSubjectNameDefaultImpl policyset.caJarSigningSet.1.default.name=Subject Name Default policyset.caJarSigningSet.1.default.params.name= policyset.caJarSigningSet.2.constraint.class_id=validityConstraintImpl policyset.caJarSigningSet.2.constraint.name=Validity Constraint policyset.caJarSigningSet.2.constraint.params.notAfterCheck=false policyset.caJarSigningSet.2.constraint.params.notBeforeCheck=false policyset.caJarSigningSet.2.constraint.params.range=2922 policyset.caJarSigningSet.2.default.class_id=validityDefaultImpl policyset.caJarSigningSet.2.default.name=Validity Default policyset.caJarSigningSet.2.default.params.range=1461 policyset.caJarSigningSet.2.default.params.startTime=60 policyset.caJarSigningSet.3.constraint.class_id=keyConstraintImpl policyset.caJarSigningSet.3.constraint.name=Key Constraint policyset.caJarSigningSet.3.constraint.params.keyMaxLength=4096 policyset.caJarSigningSet.3.constraint.params.keyMinLength=1024 policyset.caJarSigningSet.3.constraint.params.keyType=- policyset.caJarSigningSet.3.default.class_id=userKeyDefaultImpl policyset.caJarSigningSet.3.default.name=Key Default policyset.caJarSigningSet.6.constraint.class_id=keyUsageExtConstraintImpl policyset.caJarSigningSet.6.constraint.name=Key Usage Extension Constraint policyset.caJarSigningSet.6.constraint.params.keyUsageCritical=- policyset.caJarSigningSet.6.constraint.params.keyUsageCrlSign=- policyset.caJarSigningSet.6.constraint.params.keyUsageDataEncipherment=- policyset.caJarSigningSet.6.constraint.params.keyUsageDecipherOnly=- policyset.caJarSigningSet.6.constraint.params.keyUsageDigitalSignature=- policyset.caJarSigningSet.6.constraint.params.keyUsageEncipherOnly=- policyset.caJarSigningSet.6.constraint.params.keyUsageKeyAgreement=- policyset.caJarSigningSet.6.constraint.params.keyUsageKeyCertSign=- policyset.caJarSigningSet.6.constraint.params.keyUsageKeyEncipherment=- policyset.caJarSigningSet.6.constraint.params.keyUsageNonRepudiation=- policyset.caJarSigningSet.6.default.class_id=keyUsageExtDefaultImpl policyset.caJarSigningSet.6.default.name=Key Usage Default policyset.caJarSigningSet.6.default.params.keyUsageCritical=true policyset.caJarSigningSet.6.default.params.keyUsageCrlSign=false policyset.caJarSigningSet.6.default.params.keyUsageDataEncipherment=false policyset.caJarSigningSet.6.default.params.keyUsageDecipherOnly=false policyset.caJarSigningSet.6.default.params.keyUsageDigitalSignature=true policyset.caJarSigningSet.6.default.params.keyUsageEncipherOnly=false policyset.caJarSigningSet.6.default.params.keyUsageKeyAgreement=false policyset.caJarSigningSet.6.default.params.keyUsageKeyCertSign=true policyset.caJarSigningSet.6.default.params.keyUsageKeyEncipherment=false policyset.caJarSigningSet.6.default.params.keyUsageNonRepudiation=false policyset.caJarSigningSet.7.constraint.class_id=nsCertTypeExtConstraintImpl policyset.caJarSigningSet.7.constraint.name=Netscape Certificate Type Extension Constraint policyset.caJarSigningSet.7.constraint.params.nsCertCritical=- policyset.caJarSigningSet.7.constraint.params.nsCertEmail=- policyset.caJarSigningSet.7.constraint.params.nsCertEmailCA=- policyset.caJarSigningSet.7.constraint.params.nsCertObjectSigning=- policyset.caJarSigningSet.7.constraint.params.nsCertObjectSigningCA=- policyset.caJarSigningSet.7.constraint.params.nsCertSSLCA=- policyset.caJarSigningSet.7.constraint.params.nsCertSSLClient=- policyset.caJarSigningSet.7.constraint.params.nsCertSSLServer=- policyset.caJarSigningSet.7.default.class_id=nsCertTypeExtDefaultImpl policyset.caJarSigningSet.7.default.name=Netscape Certificate Type Extension Default policyset.caJarSigningSet.7.default.params.nsCertCritical=false policyset.caJarSigningSet.7.default.params.nsCertEmail=false policyset.caJarSigningSet.7.default.params.nsCertEmailCA=false policyset.caJarSigningSet.7.default.params.nsCertObjectSigning=true policyset.caJarSigningSet.7.default.params.nsCertObjectSigningCA=false policyset.caJarSigningSet.7.default.params.nsCertSSLCA=false policyset.caJarSigningSet.7.default.params.nsCertSSLClient=false policyset.caJarSigningSet.7.default.params.nsCertSSLServer=false policyset.caJarSigningSet.9.constraint.class_id=signingAlgConstraintImpl policyset.caJarSigningSet.9.constraint.name=No Constraint policyset.caJarSigningSet.9.constraint.params.signingAlgsAllowed=MD5withRSA,MD2withRSA,SHA1withRSA,SHA256withRSA,SHA512withRSA,SHA1withDSA,SHA1withEC policyset.caJarSigningSet.9.default.class_id=signingAlgDefaultImpl policyset.caJarSigningSet.9.default.name=Signing Alg policyset.caJarSigningSet.9.default.params.signingAlg=- freeipa-3.3.4/install/share/schema-update.ldif0000664000175000017500000000140512271663206020637 0ustar mkosekmkosek# FIXME: https://fedorahosted.org/389/ticket/47490 dn: cn=schema changetype: modify add: objectClasses objectClasses: ( 2.16.840.1.113730.3.2.41 NAME 'nsslapdPlugin' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsslapd-pluginPath $ nsslapd-pluginInitFunc $ nsslapd-pluginType $ nsslapd-pluginId $ nsslapd-pluginVersion $ nsslapd-pluginVendor $ nsslapd-pluginDescription $ nsslapd-pluginEnabled ) MAY ( nsslapd-pluginConfigArea $ nsslapd-plugin-depends-on-type ) X-ORIGIN 'Netscape Directory Server' ) objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) MAY ( nsSaslMapPriority ) X-ORIGIN 'Netscape Directory Server' ) freeipa-3.3.4/install/share/nis.uldif0000664000175000017500000001175612271663206017107 0ustar mkosekmkosekdn: cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: nsSlapdPlugin default:objectclass: extensibleObject default:cn: NIS Server default:nsslapd-pluginpath: /usr/lib$LIBARCH/dirsrv/plugins/nisserver-plugin.so default:nsslapd-plugininitfunc: nis_plugin_init default:nsslapd-plugintype: object default:nsslapd-pluginbetxn: on default:nsslapd-pluginenabled: on default:nsslapd-pluginid: nis-server default:nsslapd-pluginversion: 0.10 default:nsslapd-pluginvendor: redhat.com default:nsslapd-plugindescription: NIS Server Plugin default:nis-tcp-wrappers-name: nis-server dn: nis-domain=$DOMAIN+nis-map=passwd.byname, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: passwd.byname default:nis-base: cn=users, cn=accounts, $SUFFIX default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=passwd.byuid, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: passwd.byuid default:nis-base: cn=users, cn=accounts, $SUFFIX default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=group.byname, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: group.byname default:nis-base: cn=groups, cn=accounts, $SUFFIX default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=group.bygid, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: group.bygid default:nis-base: cn=groups, cn=accounts, $SUFFIX default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=netid.byname, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: netid.byname default:nis-base: cn=users, cn=accounts, $SUFFIX default:nis-secure: no # Note that the escapes in this entry can be quite confusing. The trick # is that each level of nesting requires (2^n) - 1 escapes. So the # first level is \", the second is \\\", the third is \\\\\\\", etc. # (1, 3, 7, 15, more than that and you'll go insane) # Note that this configuration mirrors the Schema Compat configuration for # triples. dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: netgroup default:nis-base: cn=ng, cn=alt, $SUFFIX default:nis-filter: (objectClass=ipanisNetgroup) default:nis-key-format: %{cn} default:nis-value-format:%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\"),%{nisDomainName:-})") default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=ethers.byaddr, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: ethers.byaddr default:nis-base: cn=computers, cn=accounts, $SUFFIX default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6") default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7") default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=ethers.byname, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: ethers.byname default:nis-base: cn=computers, cn=accounts, $SUFFIX default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%7") default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7") default:nis-secure: no freeipa-3.3.4/install/tools/0000775000175000017500000000000012271707664015324 5ustar mkosekmkosekfreeipa-3.3.4/install/tools/ipa-restore0000775000175000017500000000154012271663206017475 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Rob Crittenden # # Copyright (C) 2013 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 . # from ipaserver.install.ipa_restore import Restore Restore.run_cli() freeipa-3.3.4/install/tools/ipa-managed-entries0000775000175000017500000001667112271663206021070 0ustar mkosekmkosek#!/usr/bin/python # Authors: Jr Aquino # # Copyright (C) 2011 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 . # import re import sys from optparse import OptionParser from ipapython import ipautil, config, ipaldap from ipaserver.install import installutils from ipalib import api, errors from ipapython.ipa_log_manager import * from ipapython.dn import DN CACERT = "/etc/ipa/ca.crt" def parse_options(): usage = "%prog [options] \n" usage += "%prog [options]\n" parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Display debugging information about the update(s)") parser.add_option("-e", "--entry", dest="managed_entry", default=None, type="string", help="DN for the Managed Entry Definition") parser.add_option("-l", "--list", dest="list_managed_entries", action="store_true", help="DN for the Managed Entry Definition") parser.add_option("-p", "--password", dest="dirman_password", help="Directory Manager password") options, args = parser.parse_args() return 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=True) return password def main(): retval = 0 def_dn = None options, args = parse_options() if options.list_managed_entries: pass elif len(args) != 1: sys.exit("You must specify an action, either status, enable or disable") elif args[0] != "enable" and args[0] != "disable" and args[0] != "status": sys.exit("Unrecognized action [" + args[0] + "]") standard_logging_setup(None, debug=options.debug) host = installutils.get_fqdn() api.bootstrap(context='cli', debug=options.debug) api.finalize() managed_entry_definitions_dn = DN( ('cn', 'Definitions'), ('cn', 'Managed Entries'), ('cn', 'etc'), api.env.basedn ) conn = None try: filter = '(objectClass=extensibleObject)' conn = ipaldap.IPAdmin(host, 636, cacert=CACERT) if options.dirman_password: conn.do_simple_bind(bindpw=options.dirman_password) else: conn.do_sasl_gssapi_bind() except errors.ACIError: dirman_password = get_dirman_password() if dirman_password is None: sys.exit("Directory Manager password required") try: conn.do_simple_bind(bindpw=dirman_password) except errors.ACIError: sys.exit("Invalid credentials") except errors.ExecutionError, lde: sys.exit("An error occurred while connecting to the server.\n%s\n" % str(lde)) if options.list_managed_entries: # List available Managed Entry Plugins managed_entries = None try: entries = conn.get_entries( managed_entry_definitions_dn, conn.SCOPE_SUBTREE, filter) except Exception, e: root_logger.debug("Search for managed entries failed: %s" % str(e)) sys.exit("Unable to find managed entries at %s" % managed_entry_definitions_dn) managed_entries = [entry.single_value('cn') for entry in entries] if managed_entries: print "Available Managed Entry Definitions:" for managed_entry in managed_entries: print managed_entry retval = 0 sys.exit() if not options.managed_entry: sys.exit("\nYou must specify a managed entry definition") else: def_dn = DN(('cn', options.managed_entry), managed_entry_definitions_dn) disabled = True try: [entry] = conn.get_entries(def_dn, conn.SCOPE_BASE, filter, ['originfilter']) disable_attr = '(objectclass=disable)' try: org_filter = entry.single_value('originfilter', None) disabled = re.search(r'%s' % disable_attr, org_filter) except KeyError: sys.exit("%s is not a valid Managed Entry" % def_dn) except errors.NotFound: sys.exit("%s is not a valid Managed Entry" % def_dn) except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde if args[0] == "status": if not disabled: print "Plugin Enabled" else: print "Plugin Disabled" return 0 if args[0] == "enable": try: if not disabled: print "Plugin already Enabled" retval = 2 else: # Remove disable_attr from filter enable_attr = org_filter.replace(disable_attr, '') #enable_attr = {'originfilter': enable_attr} entry['originfilter'] = [enable_attr] conn.update_entry(entry) print "Enabling Plugin" retval = 0 except errors.NotFound: print "Enabling Plugin" except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 elif args[0] == "disable": # Set originFilter to objectclass=disabled # In future we should we should dedicate an attribute for enabling/ # disabling. try: if disabled: print "Plugin already disabled" retval = 2 else: if org_filter[:2] == '(&' and org_filter[-1] == ')': disable_attr = org_filter[:2] + disable_attr + org_filter[2:] else: disable_attr = '(&%s(%s))' % (disable_attr, org_filter) entry['originfilter'] = [disable_attr] conn.update_entry(entry) print "Disabling Plugin" except errors.NotFound: print "Plugin is already disabled" retval = 2 except errors.DatabaseError, dbe: print "An error occurred while talking to the server." print dbe retval = 1 except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 else: retval = 1 return retval if __name__ == '__main__': installutils.run_script(main, operation_name='ipa-managed-entries') freeipa-3.3.4/install/tools/ipa-adtrust-install0000775000175000017500000004474012271663206021155 0ustar mkosekmkosek#! /usr/bin/python # # Authors: Sumit Bose # Based on ipa-server-install by Karl MacMillan # and ipa-dns-install by Martin Nagy # # Copyright (C) 2011 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 . # from ipaserver.install import adtrustinstance from ipaserver.install.installutils import * from ipaserver.install import service from ipapython import version from ipapython import ipautil, sysrestore from ipalib import api, errors, util from ipapython.config import IPAOptionParser import krbV from ipapython.ipa_log_manager import * from ipapython.dn import DN log_file_name = "/var/log/ipaserver-install.log" def parse_options(): parser = IPAOptionParser(version=version.VERSION) parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="print debugging information") parser.add_option("--ip-address", dest="ip_address", type="ip", ip_local=True, help="Master Server IP Address") parser.add_option("--netbios-name", dest="netbios_name", help="NetBIOS name of the IPA domain") parser.add_option("--no-msdcs", dest="no_msdcs", action="store_true", default=False, help="Do not create DNS service records " \ "for Windows in managed DNS server") parser.add_option("--rid-base", dest="rid_base", type=int, default=1000, help="Start value for mapping UIDs and GIDs to RIDs") parser.add_option("--secondary-rid-base", dest="secondary_rid_base", type=int, default=100000000, help="Start value of the secondary range for mapping " \ "UIDs and GIDs to RIDs") parser.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") parser.add_option("-a", "--admin-password", sensitive=True, dest="admin_password", help="admin user kerberos password") parser.add_option("-A", "--admin-name", sensitive=True, dest="admin_name", default='admin', help="admin user principal") parser.add_option("--add-sids", dest="add_sids", action="store_true", default=False, help="Add SIDs for existing users and" \ " groups as the final step") parser.add_option("--enable-compat", dest="enable_compat", default=False, action="store_true", help="Enable support for trusted domains for old clients") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) return safe_options, options def netbios_name_error(name): print "\nIllegal NetBIOS name [%s].\n" % name print "Up to 15 characters and only uppercase ASCII letter and digits are allowed." def read_netbios_name(netbios_default): netbios_name = "" print "Enter the NetBIOS name for the IPA domain." print "Only up to 15 uppercase ASCII letters and digits are allowed." print "Example: EXAMPLE." print "" print "" if not netbios_default: netbios_default = "EXAMPLE" while True: netbios_name = ipautil.user_input("NetBIOS domain name", netbios_default, allow_empty = False) print "" if adtrustinstance.check_netbios_name(netbios_name): break netbios_name_error(netbios_name) return netbios_name def read_admin_password(admin_name): print "Configuring cross-realm trusts for IPA server requires password for user '%s'." % (admin_name) print "This user is a regular system account used for IPA server administration." print "" admin_password = read_password(admin_name, confirm=False, validate=None) return admin_password def set_and_check_netbios_name(netbios_name, unattended): """ Depending if trust in already configured or not a given NetBIOS domain name must be handled differently. If trust is not configured the given NetBIOS is used or the NetBIOS is generated if none was given on the command line. If trust is already configured the given NetBIOS name is used to reset the stored NetBIOS name it it differs from the current one. """ flat_name_attr = 'ipantflatname' cur_netbios_name = None gen_netbios_name = None reset_netbios_name = False dom_dn = None try: (dom_dn, entry) = api.Backend.ldap2.get_entry(DN(('cn', api.env.domain), api.env.container_cifsdomains, ipautil.realm_to_suffix(api.env.realm)), [flat_name_attr]) except errors.NotFound: # trust not configured pass else: cur_netbios_name = entry.get(flat_name_attr)[0] if cur_netbios_name and not netbios_name: # keep the current NetBIOS name netbios_name = cur_netbios_name reset_netbios_name = False elif cur_netbios_name and cur_netbios_name != netbios_name: # change the NetBIOS name print "Current NetBIOS domain name is %s, new name is %s.\n" % \ (cur_netbios_name, netbios_name) print "Please note that changing the NetBIOS name might " \ "break existing trust relationships." if unattended: reset_netbios_name = True print "NetBIOS domain name will be changed to %s.\n" % \ netbios_name else: print "Say 'yes' if the NetBIOS shall be changed and " \ "'no' if the old one shall be kept." reset_netbios_name = ipautil.user_input( 'Do you want to reset the NetBIOS domain name?', default = False, allow_empty = False) if not reset_netbios_name: netbios_name = cur_netbios_name elif cur_netbios_name and cur_netbios_name == netbios_name: # keep the current NetBIOS name reset_netbios_name = False elif not cur_netbios_name: if not netbios_name: gen_netbios_name = adtrustinstance.make_netbios_name(api.env.domain) if dom_dn: # Fix existing trust configuration print "Trust is configured but no NetBIOS domain name found, " \ "setting it now." reset_netbios_name = True else: # initial trust configuration reset_netbios_name = False else: # all possible cases should be covered above raise Exception('Unexpected state while checking NetBIOS domain name') if not adtrustinstance.check_netbios_name(netbios_name): if unattended and not gen_netbios_name: netbios_name_error(netbios_name) sys.exit("Aborting installation.") else: if netbios_name: netbios_name_error(netbios_name) netbios_name = None if not unattended and not netbios_name: netbios_name = read_netbios_name(gen_netbios_name) if unattended and not netbios_name and gen_netbios_name: netbios_name = gen_netbios_name return (netbios_name, reset_netbios_name) def ensure_admin_kinit(admin_name, admin_password): try: ipautil.run(['kinit', admin_name], stdin=admin_password+'\n') except ipautil.CalledProcessError, e: print "There was error to automatically re-kinit your admin user ticket." return False return True def enable_compat_tree(): print "Do you want to enable support for trusted domains in Schema Compatibility plugin?" print "This will allow clients older than SSSD 1.9 and non-Linux clients to work with trusted users." print "" enable_compat = ipautil.user_input("Enable trusted domains support in slapi-nis?", default = False, allow_empty = False) print "" return enable_compat def main(): safe_options, options = parse_options() if os.getegid() != 0: sys.exit("Must be root to setup AD trusts on server") standard_logging_setup(log_file_name, debug=options.debug, filemode='a') print "\nThe log file for this installation can be found in %s" % log_file_name 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") check_server_configuration() global fstore fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') print "==============================================================================" print "This program will setup components needed to establish trust to AD domains for" print "the FreeIPA Server." print "" print "This includes:" print " * Configure Samba" print " * Add trust related objects to FreeIPA LDAP server" #TODO: #print " * Add a SID to all users and Posix groups" print "" print "To accept the default shown in brackets, press the Enter key." print "" # Check if samba packages are installed if not adtrustinstance.check_inst(): sys.exit("Aborting installation.") # Initialize the ipalib api cfg = dict( in_server=True, debug=options.debug, ) api.bootstrap(**cfg) api.finalize() # If domain name and realm does not match, IPA server will not be able # to estabilish trust with Active Directory. Print big fat warning. realm_not_matching_domain = (api.env.domain.upper() != api.env.realm) if realm_not_matching_domain: print("WARNING: Realm name does not match the domain name.\n" "You will not be able to estabilish trusts with Active " "Directory unless\nthe realm name of the IPA server matches its " "domain name.\n\n") if not options.unattended: if not ipautil.user_input("Do you wish to continue?", default = False, allow_empty = False): sys.exit("Aborting installation.") # Check if /etc/samba/smb.conf already exists. In case it was not generated # by IPA, print a warning that we will break existing configuration. if adtrustinstance.ipa_smb_conf_exists(): if not options.unattended: print "IPA generated smb.conf detected." if not ipautil.user_input("Overwrite smb.conf?", default = False, allow_empty = False): sys.exit("Aborting installation.") elif os.path.exists('/etc/samba/smb.conf'): print("WARNING: The smb.conf already exists. Running " "ipa-adtrust-install will break your existing samba " "configuration.\n\n") if not options.unattended: if not ipautil.user_input("Do you wish to continue?", default = False, allow_empty = False): sys.exit("Aborting installation.") if not options.unattended and not options.enable_compat: options.enable_compat = enable_compat_tree() # Check we have a public IP that is associated with the hostname ip = None try: hostaddr = resolve_host(api.env.host) if len(hostaddr) > 1: print >> sys.stderr, "The server hostname resolves to more than one address:" for addr in hostaddr: print >> sys.stderr, " %s" % addr if options.ip_address: if str(options.ip_address) not in hostaddr: print >> sys.stderr, "Address passed in --ip-address did not match any resolved" print >> sys.stderr, "address!" sys.exit(1) print "Selected IP address:", str(options.ip_address) ip = options.ip_address else: if options.unattended: print >> sys.stderr, "Please use --ip-address option to specify the address" sys.exit(1) else: ip = read_ip_address(api.env.host, fstore) else: ip = hostaddr and ipautil.CheckedIPAddress(hostaddr[0], match_local=True) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) print "Aborting installation" sys.exit(1) ip_address = str(ip) root_logger.debug("will use ip_address: %s\n", ip_address) admin_password = options.admin_password if not (options.unattended or admin_password): admin_password = read_admin_password(options.admin_name) admin_kinited = None if admin_password: admin_kinited = ensure_admin_kinit(options.admin_name, admin_password) if not admin_kinited: print "Proceeding with credentials that existed before" 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: api.Backend.ldap2.connect(ccache) 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") 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))) (netbios_name, reset_netbios_name) = \ set_and_check_netbios_name(options.netbios_name, options.unattended) if not options.add_sids: # The filter corresponds to ipa_sidgen_task.c LDAP search filter filter = '(&(objectclass=ipaobject)(!(objectclass=mepmanagedentry))' \ '(|(objectclass=posixaccount)(objectclass=posixgroup)' \ '(objectclass=ipaidobject))(!(ipantsecurityidentifier=*)))' base_dn = api.env.basedn try: root_logger.debug("Searching for objects with missing SID with " "filter=%s, base_dn=%s", filter, base_dn) (entries, truncated) = api.Backend.ldap2.find_entries(filter=filter, base_dn=base_dn, attrs_list=['']) except errors.NotFound: # All objects have SIDs assigned pass except (errors.DatabaseError, errors.NetworkError), e: print "Could not retrieve a list of objects that need a SID identifier assigned:" print unicode(e) else: object_count = len(entries) if object_count > 0: print "" print "WARNING: %d existing users or groups do not have a SID identifier assigned." \ % len(entries) print "Installer can run a task to have ipa-sidgen Directory Server plugin generate" print "the SID identifier for all these users. Please note, the in case of a high" print "number of users and groups, the operation might lead to high replication" print "traffic and performance degradation. Refer to ipa-adtrust-install(1) man page" print "for details." print "" if options.unattended: print "Unattended mode was selected, installer will NOT run ipa-sidgen task!" else: if ipautil.user_input("Do you want to run the ipa-sidgen task?", default=False, allow_empty=False): options.add_sids = True if not options.unattended: print "" print "The following operations may take some minutes to complete." print "Please wait until the prompt is returned." print "" 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, reset_netbios_name, options.rid_base, options.secondary_rid_base, options.no_msdcs, options.add_sids, enable_compat = options.enable_compat) smb.find_local_id_range() smb.create_instance() print """ ============================================================================= Setup complete You must make sure these network ports are open: \tTCP Ports: \t * 138: netbios-dgm \t * 139: netbios-ssn \t * 445: microsoft-ds \tUDP Ports: \t * 138: netbios-dgm \t * 139: netbios-ssn \t * 389: (C)LDAP \t * 445: microsoft-ds Additionally you have to make sure the FreeIPA LDAP server is not reachable by any domain controller in the Active Directory domain by closing down the following ports for these servers: \tTCP Ports: \t * 389, 636: LDAP/LDAPS You may want to choose to REJECT the network packets instead of DROPing them to avoid timeouts on the AD domain controllers. ============================================================================= """ if admin_password: admin_kinited = ensure_admin_kinit(options.admin_name, admin_password) if not admin_kinited: print """ WARNING: you MUST re-kinit admin user before using 'ipa trust-*' commands family in order to re-generate Kerberos tickets to include AD-specific information""" return 0 if __name__ == '__main__': run_script(main, log_file_name=log_file_name, operation_name='ipa-adtrust-install') freeipa-3.3.4/install/tools/ipa-compat-manage0000775000175000017500000001612012271663206020523 0ustar mkosekmkosek#!/usr/bin/python # Authors: Rob Crittenden # Authors: Simo Sorce # # 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 . # import sys try: from optparse import OptionParser from ipapython import ipautil, config from ipaserver.install import installutils from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax from ipaserver.plugins.ldap2 import ldap2 from ipalib import api, errors from ipapython.ipa_log_manager import * from ipapython.dn import DN 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) compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config')) nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config')) def parse_options(): usage = "%prog [options] \n" usage += "%prog [options]\n" parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Display debugging information about the update(s)") parser.add_option("-y", dest="password", help="File containing the Directory Manager password") config.add_standard_options(parser) options, args = parser.parse_args() config.init_config(options) return 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 get_entry(dn, conn): """ Return the entry for the given DN. If the entry is not found return None. """ entry = None try: (dn, entry) = conn.get_entry(dn) except errors.NotFound: pass return entry def main(): retval = 0 files = ['/usr/share/ipa/schema_compat.uldif'] options, args = parse_options() if len(args) != 1: sys.exit("You must specify one action, either enable or disable") elif args[0] != "enable" and args[0] != "disable" and args[0] != "status": sys.exit("Unrecognized action [" + args[0] + "]") standard_logging_setup(None, debug=options.debug) dirman_password = "" if options.password: pw = ipautil.template_file(options.password, []) dirman_password = pw.strip() else: dirman_password = get_dirman_password() if dirman_password is None: sys.exit("Directory Manager password required") api.bootstrap(context='cli', debug=options.debug) api.finalize() conn = None try: try: conn = ldap2(shared_instance=False, base_dn='') conn.connect( bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password ) except errors.ExecutionError, lde: sys.exit("An error occurred while connecting to the server.\n%s\n" % str(lde)) except errors.ACIError, e: sys.exit("Authentication failed: %s" % e.info) if args[0] == "status": entry = None try: entry = get_entry(compat_dn, conn) if entry is not None and entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'on': print "Plugin Enabled" else: print "Plugin Disabled" except errors.LDAPError, lde: print "An error occurred while talking to the server." print lde if args[0] == "enable": entry = None try: entry = get_entry(compat_dn, conn) if entry is not None and entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'on': print "Plugin already Enabled" retval = 2 else: print "Enabling plugin" if entry is None: ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}) if not ld.update(files): print "Updating Directory Server failed." retval = 1 else: mod = {'nsslapd-pluginenabled': 'on'} conn.update_entry(compat_dn, mod) except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 elif args[0] == "disable": entry = None try: entry = get_entry(nis_config_dn, conn) # We can't disable schema compat if the NIS plugin is enabled if entry is not None and entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'on': print >>sys.stderr, "The NIS plugin is configured, cannot disable compatibility." print >>sys.stderr, "Run 'ipa-nis-manage disable' first." retval = 2 except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 if retval == 0: entry = None try: entry = get_entry(compat_dn, conn) if entry is None or entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off': print "Plugin is already disabled" retval = 2 else: print "Disabling plugin" mod = {'nsslapd-pluginenabled': 'off'} conn.update_entry(compat_dn, mod) except errors.DatabaseError, dbe: print "An error occurred while talking to the server." print dbe retval = 1 except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 else: retval = 1 if retval == 0: print "This setting will not take effect until you restart Directory Server." finally: if conn and conn.isconnected(): conn.disconnect() return retval if __name__ == '__main__': installutils.run_script(main, operation_name='ipa-compat-manage') freeipa-3.3.4/install/tools/ipa-ldap-updater0000775000175000017500000000165512270466515020406 0ustar mkosekmkosek#!/usr/bin/python # Authors: Rob Crittenden # # 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 . # # Documentation can be found at http://freeipa.org/page/LdapUpdate from ipaserver.install.ipa_ldap_updater import LDAPUpdater LDAPUpdater.run_cli() freeipa-3.3.4/install/tools/ipa-dns-install0000775000175000017500000002256612271663206020255 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Martin Nagy # Based on ipa-server-install by Karl MacMillan # # Copyright (C) 2007 - 2009 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 . # from optparse import OptionGroup, SUPPRESS_HELP import krbV from ipaserver.install import service, bindinstance, ntpinstance, httpinstance from ipaserver.install.installutils import * from ipaserver.install import installutils from ipapython import version from ipapython import ipautil, sysrestore from ipalib import api, errors, util from ipapython.config import IPAOptionParser from ipapython.ipa_log_manager import standard_logging_setup, root_logger 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="admin 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", type="ip", ip_local=True, help="Master Server IP Address") parser.add_option("--forwarder", dest="forwarders", action="append", type="ip", help="Add a DNS forwarder") parser.add_option("--no-forwarders", dest="no_forwarders", action="store_true", default=False, help="Do not add any DNS forwarders, use root servers instead") parser.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use") parser.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="Do not create new reverse DNS zone") parser.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback, type="string", help="DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN") parser.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) if options.forwarders and options.no_forwarders: parser.error("You cannot specify a --forwarder option together with --no-forwarders") elif options.reverse_zone and options.no_reverse: parser.error("You cannot specify a --reverse-zone option together with --no-reverse") if options.unattended: if not options.forwarders and not options.no_forwarders: parser.error("You must specify at least one --forwarder option or --no-forwarders option") return safe_options, options def main(): safe_options, options = parse_options() if os.getegid() != 0: sys.exit("Must be root to setup server") standard_logging_setup(log_file_name, debug=options.debug, filemode='a') print "\nThe log file for this installation can be found in %s" % log_file_name 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() global fstore fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') print "==============================================================================" print "This program will setup DNS for the FreeIPA Server." print "" print "This includes:" print " * Configure DNS (bind)" print "" print "To accept the default shown in brackets, press the Enter key." print "" # Check bind packages are installed if not bindinstance.check_inst(options.unattended): sys.exit("Aborting installation.") # Initialize the ipalib api cfg = dict( in_server=True, debug=options.debug, ) api.bootstrap(**cfg) api.finalize() if bindinstance.named_conf_exists(): sys.exit("\nDNS is already configured in this IPA server.") # Create a BIND instance if options.unattended and not options.dm_password: sys.exit("\nIn unattended mode you need to provide at least the -p option") dm_password = options.dm_password or read_password("Directory Manager", confirm=False, validate=False) if dm_password is None: sys.exit("Directory Manager password required") bind = bindinstance.BindInstance(fstore, dm_password) # try the connection try: bind.ldap_connect() bind.ldap_disconnect() except errors.ACIError: sys.exit("Password is not valid!") # Check we have a public IP that is associated with the hostname if options.ip_address: ip = options.ip_address else: hostaddr = resolve_host(api.env.host) try: if len(hostaddr) > 1: print >> sys.stderr, "The server hostname resolves to more than one address:" for addr in hostaddr: print >> sys.stderr, " %s" % addr if options.ip_address: if str(options.ip_address) not in hostaddr: print >> sys.stderr, "Address passed in --ip-address did not match any resolved" print >> sys.stderr, "address!" sys.exit(1) print "Selected IP address:", str(options.ip_address) ip = options.ip_address else: if options.unattended: print >> sys.stderr, "Please use --ip-address option to specify the address" sys.exit(1) else: ip = read_ip_address(api.env.host, fstore) else: ip = hostaddr and ipautil.CheckedIPAddress(hostaddr[0], match_local=True) except Exception, e: print "Error: Invalid IP Address %s: %s" % (ip, e) ip = None if not ip: if options.unattended: sys.exit("Unable to resolve IP address for host name") else: ip = read_ip_address(api.env.host, fstore) ip_address = str(ip) root_logger.debug("will use ip_address: %s\n", ip_address) if options.reverse_zone and not bindinstance.verify_reverse_zone(options.reverse_zone, ip): sys.exit(1) if options.no_forwarders: dns_forwarders = () elif options.forwarders: dns_forwarders = options.forwarders else: dns_forwarders = read_dns_forwarders() root_logger.debug("will use dns_forwarders: %s\n", str(dns_forwarders)) if bind.dm_password: api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=bind.dm_password) else: # See if our LDAP server is up and we can talk to it over GSSAPI ccache = krbV.default_context().default_ccache() api.Backend.ldap2.connect(ccache) if options.reverse_zone: reverse_zone = bindinstance.normalize_zone(options.reverse_zone) else: reverse_zone = bindinstance.find_reverse_zone(ip) if reverse_zone is None and not options.no_reverse: if options.unattended: reverse_zone = util.get_reverse_zone_default(ip) elif bindinstance.create_reverse(): reverse_zone = util.get_reverse_zone_default(ip) reverse_zone = bindinstance.read_reverse_zone(reverse_zone, ip) if reverse_zone is not None: print "Using reverse zone %s" % reverse_zone conf_ntp = ntpinstance.NTPInstance(fstore).is_enabled() if not options.unattended: print "" print "The following operations may take some minutes to complete." print "Please wait until the prompt is returned." print "" bind.setup(api.env.host, ip_address, api.env.realm, api.env.domain, dns_forwarders, conf_ntp, reverse_zone, zonemgr=options.zonemgr) bind.create_instance() # Restart http instance to make sure that python-dns has the right resolver # https://bugzilla.redhat.com/show_bug.cgi?id=800368 http = httpinstance.HTTPInstance(fstore) service.print_msg("Restarting the web server") http.restart() print "==============================================================================" print "Setup complete" print "" bind.check_global_configuration() print "" print "" print "\tYou must make sure these network ports are open:" print "\t\tTCP Ports:" print "\t\t * 53: bind" print "\t\tUDP Ports:" print "\t\t * 53: bind" return 0 if __name__ == '__main__': with private_ccache(): installutils.run_script(main, log_file_name=log_file_name, operation_name='ipa-dns-install') freeipa-3.3.4/install/tools/ipa-server-install0000775000175000017500000015204312271663206020771 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Karl MacMillan # Simo Sorce # Rob Crittenden # # Copyright (C) 2007-2010 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 . # # requires the following packages: # fedora-ds-base # openldap-clients # nss-tools import sys import os import grp import signal import shutil import pickle import random import tempfile import nss.error import base64 import pwd import textwrap from optparse import OptionGroup, OptionValueError try: from ipaserver.install import adtrustinstance _server_trust_ad_installed = True except ImportError: _server_trust_ad_installed = False from ipaserver.install import dsinstance from ipaserver.install import krbinstance from ipaserver.install import bindinstance from ipaserver.install import httpinstance from ipaserver.install import ntpinstance from ipaserver.install import certs from ipaserver.install import cainstance from ipaserver.install import memcacheinstance from ipaserver.install import otpdinstance from ipaserver.install import sysupgrade from ipaserver.install import replication from ipaserver.install import service, installutils from ipapython import version from ipapython import certmonger from ipapython import ipaldap from ipaserver.install.installutils import * from ipaserver.plugins.ldap2 import ldap2 from ipapython import sysrestore from ipapython.ipautil import * from ipapython import ipautil from ipapython import dogtag from ipalib import api, errors, util, x509 from ipapython.config import IPAOptionParser from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file from ipalib.util import validate_domain_name from ipapython import services as ipaservices from ipapython.ipa_log_manager import * from ipapython.dn import DN import ipaclient.ntpconf uninstalling = False installation_cleanup = True VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c', 'serialnumber', 'l', 'title', 'sn', 'givenname', 'initials', 'generationqualifier', 'dc', 'mail', 'uid', 'postaladdress', 'postalcode', 'postofficebox', 'houseidentifier', 'e', 'street', 'pseudonym', 'incorporationlocality', 'incorporationstate', 'incorporationcountry', 'businesscategory'] def subject_callback(option, opt_str, value, parser): """ Make sure the certificate subject base is a valid DN """ v = unicode(value, 'utf-8') if any(ord(c) < 0x20 for c in v): raise OptionValueError("Subject base must not contain control characters") if '&' in v: raise OptionValueError("Subject base must not contain an ampersand (\"&\")") try: dn = DN(v) for rdn in dn: if rdn.attr.lower() not in VALID_SUBJECT_ATTRS: raise OptionValueError('%s=%s has invalid attribute: "%s"' % (opt_str, value, rdn.attr)) except ValueError, e: raise OptionValueError('%s=%s has invalid subject base format: %s' % (opt_str, value, e)) parser.values.subject = dn def validate_dm_password(password): if len(password) < 8: raise ValueError("Password must be at least 8 characters long") if any(ord(c) < 0x20 for c in password): raise ValueError("Password must not contain control characters") if any(ord(c) >= 0x7F for c in password): raise ValueError("Password must only contain ASCII characters") # Disallow characters that pkisilent doesn't process properly: bad_characters = ' &\\<%' if any(c in bad_characters for c in password): raise ValueError('Password must not contain these characters: %s' % ', '.join('"%s"' % c for c in bad_characters)) def parse_options(): # Guaranteed to give a random 200k range below the 2G mark (uint32_t limit) namespace = random.randint(1, 10000) * 200000 parser = IPAOptionParser(version=version.VERSION) basic_group = OptionGroup(parser, "basic options") basic_group.add_option("-r", "--realm", dest="realm_name", help="realm name") basic_group.add_option("-n", "--domain", dest="domain_name", help="domain name") basic_group.add_option("-p", "--ds-password", dest="dm_password", sensitive=True, help="admin password") basic_group.add_option("-P", "--master-password", dest="master_password", sensitive=True, help="kerberos master password (normally autogenerated)") basic_group.add_option("-a", "--admin-password", sensitive=True, dest="admin_password", help="admin user kerberos password") basic_group.add_option("--mkhomedir", dest="mkhomedir", action="store_true", default=False, help="create home directories for users " "on their first login") basic_group.add_option("--hostname", dest="host_name", help="fully qualified name of server") basic_group.add_option("--ip-address", dest="ip_address", type="ip", ip_local=True, help="Master Server IP Address") basic_group.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false", help="do not configure ntp", default=True) basic_group.add_option("--idstart", dest="idstart", default=namespace, type=int, help="The starting value for the IDs range (default random)") basic_group.add_option("--idmax", dest="idmax", default=0, type=int, help="The max value value for the IDs range (default: idstart+199999)") basic_group.add_option("--no_hbac_allow", dest="hbac_allow", default=False, action="store_true", help="Don't install allow_all HBAC rule") basic_group.add_option("--no-ui-redirect", dest="ui_redirect", action="store_false", default=True, help="Do not automatically redirect to the Web UI") basic_group.add_option("--ssh-trust-dns", dest="trust_sshfp", default=False, action="store_true", help="configure OpenSSH client to trust DNS SSHFP records") basic_group.add_option("--no-ssh", dest="conf_ssh", default=True, action="store_false", help="do not configure OpenSSH client") basic_group.add_option("--no-sshd", dest="conf_sshd", default=True, action="store_false", help="do not configure OpenSSH server") basic_group.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="print debugging information") basic_group.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended (un)installation never prompts the user") parser.add_option_group(basic_group) cert_group = OptionGroup(parser, "certificate system options") cert_group.add_option("", "--external-ca", dest="external_ca", action="store_true", default=False, help="Generate a CSR to be signed by an external CA") cert_group.add_option("", "--external_cert_file", dest="external_cert_file", help="PEM file containing a certificate signed by the external CA") cert_group.add_option("", "--external_ca_file", dest="external_ca_file", help="PEM file containing the external CA chain") cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", default=True, help="disables pkinit setup steps") cert_group.add_option("--dirsrv_pkcs12", dest="dirsrv_pkcs12", help="PKCS#12 file containing the Directory Server SSL certificate") cert_group.add_option("--http_pkcs12", dest="http_pkcs12", help="PKCS#12 file containing the Apache Server SSL certificate") cert_group.add_option("--pkinit_pkcs12", dest="pkinit_pkcs12", help="PKCS#12 file containing the Kerberos KDC SSL certificate") cert_group.add_option("--dirsrv_pin", dest="dirsrv_pin", sensitive=True, help="The password of the Directory Server PKCS#12 file") cert_group.add_option("--http_pin", dest="http_pin", sensitive=True, help="The password of the Apache Server PKCS#12 file") cert_group.add_option("--pkinit_pin", dest="pkinit_pin", help="The password of the Kerberos KDC PKCS#12 file") cert_group.add_option("--root-ca-file", dest="root_ca_file", help="PEM file with root CA certificate(s) to trust") cert_group.add_option("--subject", action="callback", callback=subject_callback, type="string", help="The certificate subject base (default O=)") parser.add_option_group(cert_group) dns_group = OptionGroup(parser, "DNS options") dns_group.add_option("--setup-dns", dest="setup_dns", action="store_true", default=False, help="configure bind with our zone") dns_group.add_option("--forwarder", dest="forwarders", action="append", type="ip", help="Add a DNS forwarder") dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true", default=False, help="Do not add any DNS forwarders, use root servers instead") dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use") dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="Do not create reverse DNS zone") dns_group.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback, type="string", help="DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN") dns_group.add_option("--no-host-dns", dest="no_host_dns", action="store_true", 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") parser.add_option_group(dns_group) uninstall_group = OptionGroup(parser, "uninstall options") uninstall_group.add_option("", "--uninstall", dest="uninstall", action="store_true", default=False, help="uninstall an existing installation. The uninstall can " \ "be run with --unattended option") parser.add_option_group(uninstall_group) options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) if options.dm_password is not None: try: validate_dm_password(options.dm_password) except ValueError, e: parser.error("DS admin password: " + str(e)) if options.admin_password is not None and len(options.admin_password) < 8: parser.error("Admin user password must be at least 8 characters long") if options.domain_name is not None: try: validate_domain_name(options.domain_name) except ValueError, e: parser.error("invalid domain: " + unicode(e)) if not options.setup_dns: if options.forwarders: parser.error("You cannot specify a --forwarder option without the --setup-dns option") if options.no_forwarders: parser.error("You cannot specify a --no-forwarders option without the --setup-dns option") if options.reverse_zone: parser.error("You cannot specify a --reverse-zone option without the --setup-dns option") if options.no_reverse: parser.error("You cannot specify a --no-reverse option without the --setup-dns option") elif options.forwarders and options.no_forwarders: parser.error("You cannot specify a --forwarder option together with --no-forwarders") elif options.reverse_zone and options.no_reverse: parser.error("You cannot specify a --reverse-zone option together with --no-reverse") if options.uninstall: if (options.realm_name or options.admin_password or options.master_password): parser.error("In uninstall mode, -a, -r and -P options are not allowed") elif options.unattended: if (not options.realm_name or not options.dm_password or not options.admin_password): parser.error("In unattended mode you need to provide at least -r, -p and -a options") if options.setup_dns: if not options.forwarders and not options.no_forwarders: parser.error("You must specify at least one --forwarder option or --no-forwarders option") # If any of the PKCS#12 options are selected, all are required. pkcs12_req = (options.dirsrv_pkcs12, options.http_pkcs12) pkcs12_opt = (options.pkinit_pkcs12,) if any(pkcs12_req + pkcs12_opt) and not all(pkcs12_req): parser.error("--dirsrv_pkcs12 and --http_pkcs12 are required if any " "PKCS#12 options are used.") if options.unattended: if options.dirsrv_pkcs12 and options.dirsrv_pin is None: parser.error("You must specify --dirsrv_pin with --dirsrv_pkcs12") if options.http_pkcs12 and options.http_pin is None: parser.error("You must specify --http_pin with --http_pkcs12") if options.pkinit_pkcs12 and options.pkinit_pin is None: parser.error("You must specify --pkinit_pin with --pkinit_pkcs12") if options.dirsrv_pkcs12 and not options.root_ca_file: parser.error( "--root-ca-file must be given with the PKCS#12 options.") if (options.external_cert_file or options.external_ca_file) and options.dirsrv_pkcs12: parser.error( "PKCS#12 options cannot be used with the external CA options.") if options.external_ca: if options.external_cert_file: parser.error("You cannot specify --external_cert_file together with --external-ca") if options.external_ca_file: parser.error("You cannot specify --external_ca_file together with --external-ca") if options.dirsrv_pkcs12: parser.error("You cannot specify PKCS#12 options together with --external-ca") if ((options.external_cert_file and not options.external_ca_file) or (not options.external_cert_file and options.external_ca_file)): parser.error("if either external CA option is used, both are required.") if (options.external_ca_file and not os.path.isabs(options.external_ca_file)): parser.error("--external-ca-file must use an absolute path") if (options.external_cert_file and not os.path.isabs(options.external_cert_file)): parser.error("--external-cert-file must use an absolute path") if options.idmax == 0: options.idmax = int(options.idstart) + 200000 - 1 if options.idmax < options.idstart: parser.error("idmax (%u) cannot be smaller than idstart (%u)" % (options.idmax, options.idstart)) #Automatically disable pkinit w/ dogtag until that is supported options.setup_pkinit = False return safe_options, options def signal_handler(signum, frame): global ds print "\nCleaning up..." if ds: print "Removing configuration for %s instance" % ds.serverid ds.stop() if ds.serverid: dsinstance.erase_ds_instance_data (ds.serverid) sys.exit(1) ANSWER_CACHE = "/root/.ipa_cache" def read_cache(dm_password): """ Returns a dict of cached answers or empty dict if no cache file exists. """ if not ipautil.file_exists(ANSWER_CACHE): return {} top_dir = tempfile.mkdtemp("ipa") fname = "%s/cache" % top_dir try: decrypt_file(ANSWER_CACHE, fname, dm_password, top_dir) except Exception, e: shutil.rmtree(top_dir) raise Exception("Decryption of answer cache in %s failed, please check your password." % ANSWER_CACHE) try: with open(fname, 'rb') as f: try: optdict = pickle.load(f) except Exception, e: raise Exception("Parse error in %s: %s" % (ANSWER_CACHE, str(e))) except IOError, e: raise Exception("Read error in %s: %s" % (ANSWER_CACHE, str(e))) finally: shutil.rmtree(top_dir) # These are the only ones that may be overridden for opt in ('external_ca_file', 'external_cert_file'): try: del optdict[opt] except KeyError: pass return optdict def write_cache(options): """ Takes a dict as input and writes a cached file of answers """ top_dir = tempfile.mkdtemp("ipa") fname = "%s/cache" % top_dir try: with open(fname, 'wb') as f: pickle.dump(options, f) ipautil.encrypt_file(fname, ANSWER_CACHE, options['dm_password'], top_dir) except IOError, e: raise Exception("Unable to cache command-line options %s" % str(e)) finally: shutil.rmtree(top_dir) def read_host_name(host_default,no_host_dns=False): host_name = "" print "Enter the fully qualified domain name of the computer" print "on which you're setting up server software. Using the form" print "." print "Example: master.example.com." print "" print "" if host_default == "": host_default = "master.example.com" host_name = user_input("Server host name", host_default, allow_empty = False) print "" verify_fqdn(host_name,no_host_dns) return host_name def read_domain_name(domain_name, unattended): print "The domain name has been determined based on the host name." print "" if not unattended: domain_name = user_input("Please confirm the domain name", domain_name) print "" return domain_name def read_realm_name(domain_name, unattended): print "The kerberos protocol requires a Realm name to be defined." print "This is typically the domain name converted to uppercase." print "" if unattended: return domain_name.upper() realm_name = user_input("Please provide a realm name", domain_name.upper()) upper_dom = realm_name.upper() #pylint: disable=E1103 if upper_dom != realm_name: print "An upper-case realm name is required." if not user_input("Do you want to use " + upper_dom + " as realm name?", True): print "" print "An upper-case realm name is required. Unable to continue." sys.exit(1) else: realm_name = upper_dom print "" return realm_name def read_dm_password(): print "Certain directory server operations require an administrative user." print "This user is referred to as the Directory Manager and has full access" print "to the Directory for system management tasks and will be added to the" print "instance of directory server created for IPA." print "The password must be at least 8 characters long." print "" #TODO: provide the option of generating a random password dm_password = read_password("Directory Manager", validator=validate_dm_password) return dm_password def read_admin_password(): print "The IPA server requires an administrative user, named 'admin'." print "This user is a regular system account used for IPA server administration." print "" #TODO: provide the option of generating a random password admin_password = read_password("IPA admin") return admin_password def check_dirsrv(unattended): (ds_unsecure, ds_secure) = dsinstance.check_ports() if not ds_unsecure or not ds_secure: print "IPA requires ports 389 and 636 for the Directory Server." print "These are currently in use:" if not ds_unsecure: print "\t389" if not ds_secure: print "\t636" sys.exit(1) def uninstall(): rv = 0 print "Shutting down all IPA services" try: (stdout, stderr, rc) = run(["/usr/sbin/ipactl", "stop"], raiseonerr=False) except Exception, e: pass # Need to get dogtag info before /etc/ipa/default.conf is removed dogtag_constants = dogtag.configured_constants() print "Removing IPA client configuration" try: (stdout, stderr, rc) = run(["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--uninstall"], raiseonerr=False) if rc not in [0,2]: root_logger.debug("ipa-client-install returned %d" % rc) raise RuntimeError(stdout) except Exception, e: rv = 1 print "Uninstall of client side components failed!" print "ipa-client-install returned: " + str(e) ntpinstance.NTPInstance(fstore).uninstall() if not dogtag_constants.SHARED_DB: cads_instance = cainstance.CADSInstance( dogtag_constants=dogtag_constants) if cads_instance.is_configured(): cads_instance.uninstall() cainstance.stop_tracking_certificates(dogtag_constants) ca_instance = cainstance.CAInstance( api.env.realm, certs.NSS_DIR, dogtag_constants=dogtag_constants) if ca_instance.is_configured(): ca_instance.uninstall() bindinstance.BindInstance(fstore).uninstall() httpinstance.HTTPInstance(fstore).uninstall() krbinstance.KrbInstance(fstore).uninstall() dsinstance.DsInstance(fstore=fstore).uninstall() if _server_trust_ad_installed: adtrustinstance.ADTRUSTInstance(fstore).uninstall() memcacheinstance.MemcacheInstance().uninstall() otpdinstance.OtpdInstance().uninstall() ipaservices.restore_network_configuration(fstore, sstore) fstore.restore_all_files() try: os.remove(ANSWER_CACHE) except Exception: pass # ipa-client-install removes /etc/ipa/default.conf sstore._load() ipaclient.ntpconf.restore_forced_ntpd(sstore) group_exists = sstore.restore_state("install", "group_exists") ipaservices.knownservices.ipa.disable() ipautil.restore_hostname(sstore) # remove upgrade state file sysupgrade.remove_upgrade_file() if fstore.has_files(): root_logger.error('Some files have not been restored, see /var/lib/ipa/sysrestore/sysrestore.index') has_state = False for module in IPA_MODULES: # from installutils if sstore.has_state(module): root_logger.error('Some installation state for %s has not been restored, see /var/lib/ipa/sysrestore/sysrestore.state' % module) has_state = True rv = 1 if has_state: root_logger.error('Some installation state has not been restored.\nThis may cause re-installation to fail.\nIt should be safe to remove /var/lib/ipa/sysrestore.state but it may\nmean your system hasn\'t be restored to its pre-installation state.') # Note that this name will be wrong after the first uninstall. dirname = dsinstance.config_dirname(dsinstance.realm_to_serverid(api.env.realm)) dirs = [dirname, dogtag_constants.ALIAS_DIR, certs.NSS_DIR] ids = certmonger.check_state(dirs) if ids: root_logger.error('Some certificates may still be tracked by certmonger.\nThis will cause re-installation to fail.\nStart the certmonger service and list the certificates being tracked\n # getcert list\nThese may be untracked by executing\n # getcert stop-tracking -i \nfor each id in: %s' % ', '.join(ids)) return rv def set_subject_in_config(realm_name, dm_password, suffix, subject_base): ldapuri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % ( dsinstance.realm_to_serverid(realm_name) ) try: conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn=suffix) conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password) except errors.ExecutionError, e: root_logger.critical("Could not connect to the Directory Server on %s" % realm_name) raise e (dn, entry_attrs) = conn.get_ipa_config() if 'ipacertificatesubjectbase' not in entry_attrs: mod = {'ipacertificatesubjectbase': str(subject_base)} conn.update_entry(dn, mod) conn.disconnect() def main(): global ds global uninstalling global installation_cleanup ds = None safe_options, options = parse_options() if os.getegid() != 0: sys.exit("Must be root to set up server") ipaservices.check_selinux_status() signal.signal(signal.SIGTERM, signal_handler) signal.signal(signal.SIGINT, signal_handler) if options.uninstall: uninstalling = True standard_logging_setup("/var/log/ipaserver-uninstall.log", debug=options.debug) installation_cleanup = False else: standard_logging_setup("/var/log/ipaserver-install.log", debug=options.debug) print "\nThe log file for this installation can be found in /var/log/ipaserver-install.log" if not options.external_ca and not options.external_cert_file and is_ipa_configured(): installation_cleanup = False sys.exit("IPA server is already configured on this system.\n" + "If you want to reinstall the IPA server, please uninstall " + "it first using 'ipa-server-install --uninstall'.") client_fstore = sysrestore.FileStore('/var/lib/ipa-client/sysrestore') if client_fstore.has_files(): installation_cleanup = False sys.exit("IPA client is already configured on this system.\n" + "Please uninstall it before configuring the IPA server, " + "using 'ipa-client-install --uninstall'") 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") global fstore fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') global sstore sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') # Configuration for ipalib, we will bootstrap and finalize later, after # we are sure we have the configuration file ready. cfg = dict( context='installer', in_server=True, debug=options.debug ) if options.uninstall: # We will need at least api.env, finalize api now. This system is # already installed, so the configuration file is there. api.bootstrap(**cfg) api.finalize() if not options.unattended: print "\nThis is a NON REVERSIBLE operation and will delete all data and configuration!\n" if not user_input("Are you sure you want to continue with the uninstall procedure?", False): print "" print "Aborting uninstall operation." sys.exit(1) try: conn = ipaldap.IPAdmin( api.env.host, ldapi=True, realm=api.env.realm ) conn.do_external_bind(pwd.getpwuid(os.geteuid()).pw_name) except Exception: msg = ("\nWARNING: Failed to connect to Directory Server to find " "information about replication agreements. Uninstallation " "will continue despite the possible existing replication " "agreements.\n\n") print textwrap.fill(msg, width=80, replace_whitespace=False) else: rm = replication.ReplicationManager( realm=api.env.realm, hostname=api.env.host, dirman_passwd=None, conn=conn ) agreements = rm.find_ipa_replication_agreements() if agreements: other_masters = [a.get('cn')[0][4:] for a in agreements] msg = ( "\nReplication agreements with the following IPA masters " "found: %s. Removing any replication agreements before " "uninstalling the server is strongly recommended. You can " "remove replication agreements by running the following " "command on any other IPA master:\n" % ", ".join( other_masters) ) cmd = "$ ipa-replica-manage del %s\n" % api.env.host print textwrap.fill(msg, width=80, replace_whitespace=False) print cmd if not (options.unattended or user_input("Are you sure you " "want to continue " "with the uninstall " "procedure?", False)): print "" print "Aborting uninstall operation." sys.exit(1) return uninstall() if options.external_ca: if cainstance.is_step_one_done(): print "CA is already installed.\nRun the installer with --external_cert_file and --external_ca_file." sys.exit(1) elif options.external_cert_file: if not cainstance.is_step_one_done(): # This can happen if someone passes external_ca_file without # already having done the first stage of the CA install. print "CA is not installed yet. To install with an external CA is a two-stage process.\nFirst run the installer with --external-ca." sys.exit(1) # This will override any settings passed in on the cmdline if ipautil.file_exists(ANSWER_CACHE): if options.dm_password is not None: dm_password = options.dm_password else: dm_password = read_password("Directory Manager", confirm=False) if dm_password is None: sys.exit("Directory Manager password required") try: options._update_loose(read_cache(dm_password)) except Exception, e: sys.exit("Cannot process the cache file: %s" % str(e)) if options.external_cert_file: try: extcert = load_certificate_from_file(options.external_cert_file) except IOError, e: print "Can't load the PEM certificate: %s." % str(e) sys.exit(1) except nss.error.NSPRError: print "'%s' is not a valid PEM-encoded certificate." % options.external_cert_file sys.exit(1) certsubject = DN(str(extcert.subject)) wantsubject = DN(('CN','Certificate Authority'), options.subject) if certsubject != wantsubject: print "Subject of the external certificate is not correct (got %s, expected %s)." % (certsubject, wantsubject) sys.exit(1) try: extchain = load_certificate_chain_from_file(options.external_ca_file) except IOError, e: print "Can't load the external CA chain: %s." % str(e) sys.exit(1) except nss.error.NSPRError: print "'%s' is not a valid PEM-encoded certificate chain." % options.external_ca_file sys.exit(1) certdict = dict((DN(str(cert.subject)), cert) for cert in extchain) del extchain certissuer = DN(str(extcert.issuer)) if certissuer not in certdict: print "The external certificate is not signed by the external CA (unknown issuer %s)." % certissuer sys.exit(1) cert = extcert del extcert while cert.issuer != cert.subject: certissuer = DN(str(cert.issuer)) if certissuer not in certdict: print "The external CA chain is incomplete (%s is missing from the chain)." % certissuer sys.exit(1) del cert cert = certdict[certissuer] del certdict del cert # We only set up the CA if the PKCS#12 options are not given. if options.dirsrv_pkcs12: setup_ca = False else: setup_ca = True # Figure out what external CA step we're in. See cainstance.py for more # info on the 3 states. if options.external_cert_file: external = 2 elif options.external_ca: external = 1 else: external = 0 print "==============================================================================" print "This program will set up the FreeIPA Server." print "" print "This includes:" if setup_ca: print " * Configure a stand-alone CA (dogtag) for certificate management" if options.conf_ntp: print " * Configure the Network Time Daemon (ntpd)" print " * Create and configure an instance of Directory Server" print " * Create and configure a Kerberos Key Distribution Center (KDC)" print " * Configure Apache (httpd)" if options.setup_dns: print " * Configure DNS (bind)" if options.setup_pkinit: print " * Configure the KDC to enable PKINIT" if not options.conf_ntp: print "" print "Excluded by options:" print " * Configure the Network Time Daemon (ntpd)" if not options.unattended: print "" print "To accept the default shown in brackets, press the Enter key." print "" if external != 2: # Make sure the 389-ds ports are available check_dirsrv(options.unattended) if options.conf_ntp: try: ipaclient.ntpconf.check_timedate_services() except ipaclient.ntpconf.NTPConflictingService, e: print "WARNING: conflicting time&date synchronization service '%s'" \ " will be disabled" % e.conflicting_service print "in favor of ntpd" print "" except ipaclient.ntpconf.NTPConfigurationError: pass # Check to see if httpd is already configured to listen on 443 if httpinstance.httpd_443_configured(): sys.exit("Aborting installation") realm_name = "" host_name = "" domain_name = "" ip_address = "" master_password = "" dm_password = "" admin_password = "" reverse_zone = None if not options.setup_dns and not options.unattended: if ipautil.user_input("Do you want to configure integrated DNS (BIND)?", False): options.setup_dns = True print "" # check bind packages are installed if options.setup_dns: if not bindinstance.check_inst(options.unattended): sys.exit("Aborting installation") # Don't require an external DNS to say who we are if we are # setting up a local DNS server. options.no_host_dns = True # check the hostname is correctly configured, it must be as the kldap # utilities just use the hostname as returned by getaddrinfo to set # up some of the standard entries host_default = "" if options.host_name: host_default = options.host_name else: host_default = get_fqdn() try: if options.unattended or options.host_name: verify_fqdn(host_default,options.no_host_dns) host_name = host_default else: host_name = read_host_name(host_default,options.no_host_dns) except BadHostError, e: sys.exit(str(e) + "\n") host_name = host_name.lower() root_logger.debug("will use host_name: %s\n" % host_name) system_hostname = get_fqdn() if host_name != system_hostname: print >>sys.stderr print >>sys.stderr, "Warning: hostname %s does not match system hostname %s." \ % (host_name, system_hostname) print >>sys.stderr, "System hostname will be updated during the installation process" print >>sys.stderr, "to prevent service failures." print >>sys.stderr if not options.domain_name: domain_name = read_domain_name(host_name[host_name.find(".")+1:], options.unattended) root_logger.debug("read domain_name: %s\n" % domain_name) try: validate_domain_name(domain_name) except ValueError, e: sys.exit("Invalid domain name: %s" % unicode(e)) else: domain_name = options.domain_name domain_name = domain_name.lower() ip = get_server_ip_address(host_name, fstore, options.unattended, options) ip_address = str(ip) if options.reverse_zone and not bindinstance.verify_reverse_zone(options.reverse_zone, ip): sys.exit(1) if not options.realm_name: realm_name = read_realm_name(domain_name, options.unattended) root_logger.debug("read realm_name: %s\n" % realm_name) else: realm_name = options.realm_name.upper() if not options.subject: options.subject = DN(('O', realm_name)) ca_file = options.root_ca_file if options.http_pkcs12: if options.http_pin is None: options.http_pin = installutils.read_password( "Enter %s unlock" % options.http_pkcs12, confirm=False, validate=False) if options.http_pin is None: sys.exit("%s unlock password required" % options.http_pkcs12) http_pkcs12_info = (options.http_pkcs12, options.http_pin) http_cert_name = installutils.check_pkcs12( http_pkcs12_info, ca_file, host_name) if options.dirsrv_pkcs12: if options.dirsrv_pin is None: options.dirsrv_pin = installutils.read_password( "Enter %s unlock" % options.dirsrv_pkcs12, confirm=False, validate=False) if options.dirsrv_pin is None: sys.exit("%s unlock password required" % options.dirsrv_pkcs12) dirsrv_pkcs12_info = (options.dirsrv_pkcs12, options.dirsrv_pin) dirsrv_cert_name = installutils.check_pkcs12( dirsrv_pkcs12_info, ca_file, host_name) if options.pkinit_pkcs12: if options.pkinit_pin is None: options.pkinit_pin = installutils.read_password( "Enter %s unlock" % options.pkinit_pkcs12, confirm=False, validate=False) if options.pkinit_pin is None: sys.exit("%s unlock password required" % options.pkinit_pkcs12) pkinit_pkcs12_info = (options.pkinit_pkcs12, options.pkinit_pin) if not options.dm_password: dm_password = read_dm_password() if dm_password is None: sys.exit("Directory Manager password required") else: dm_password = options.dm_password if not options.master_password: master_password = ipa_generate_password() else: master_password = options.master_password if not options.admin_password: admin_password = read_admin_password() if admin_password is None: sys.exit("IPA admin password required") else: admin_password = options.admin_password if options.setup_dns: if options.no_forwarders: dns_forwarders = () elif options.forwarders: dns_forwarders = options.forwarders else: dns_forwarders = read_dns_forwarders() if options.reverse_zone: reverse_zone = bindinstance.normalize_zone(options.reverse_zone) elif not options.no_reverse: if options.unattended: reverse_zone = util.get_reverse_zone_default(ip) elif bindinstance.create_reverse(): reverse_zone = util.get_reverse_zone_default(ip) reverse_zone = bindinstance.read_reverse_zone(reverse_zone, ip) if reverse_zone is not None: print "Using reverse zone %s" % reverse_zone else: dns_forwarders = () root_logger.debug("will use dns_forwarders: %s\n" % str(dns_forwarders)) print print "The IPA Master Server will be configured with:" print "Hostname: %s" % host_name print "IP address: %s" % ip_address print "Domain name: %s" % domain_name print "Realm name: %s" % realm_name print if options.setup_dns: print "BIND DNS server will be configured to serve IPA domain with:" print "Forwarders: %s" % ("No forwarders" if not dns_forwarders \ else ", ".join([str(ip) for ip in dns_forwarders])) print "Reverse zone: %s" % ("No reverse zone" if options.no_reverse \ or reverse_zone is None else reverse_zone) print # If domain name and realm does not match, IPA server will not be able # to estabilish trust with Active Directory. Print big fat warning. realm_not_matching_domain = (domain_name.upper() != realm_name) if realm_not_matching_domain: print("WARNING: Realm name does not match the domain name.\n" "You will not be able to estabilish trusts with Active " "Directory unless\nythe realm name of the IPA server matches " "its domain name.\n\n") if not options.unattended and not user_input("Continue to configure the system with these values?", False): sys.exit("Installation aborted") # Installation has started. No IPA sysrestore items are restored in case of # failure to enable root cause investigation installation_cleanup = False # Create the management framework config file and finalize api target_fname = '/etc/ipa/default.conf' fd = open(target_fname, "w") fd.write("[global]\n") fd.write("host=%s\n" % host_name) fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name)) fd.write("realm=%s\n" % realm_name) fd.write("domain=%s\n" % domain_name) fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name)) fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(realm_name)) if setup_ca: fd.write("enable_ra=True\n") fd.write("ra_plugin=dogtag\n") fd.write("dogtag_version=%s\n" % dogtag.install_constants.DOGTAG_VERSION) else: fd.write("enable_ra=False\n") fd.write("ra_plugin=none\n") fd.write("mode=production\n") fd.close() # Must be readable for everyone os.chmod(target_fname, 0644) api.bootstrap(**cfg) api.finalize() if not options.unattended: print "" print "The following operations may take some minutes to complete." print "Please wait until the prompt is returned." print "" if host_name != system_hostname: root_logger.debug("Chosen hostname (%s) differs from system hostname (%s) - change it" \ % (host_name, system_hostname)) # configure /etc/sysconfig/network to contain the custom hostname ipaservices.backup_and_replace_hostname(fstore, sstore, host_name) # Create DS group if it doesn't exist yet dsinstance.create_ds_group() # Create a directory server instance if external != 2: # Configure ntpd if options.conf_ntp: ipaclient.ntpconf.force_ntpd(sstore) ntp = ntpinstance.NTPInstance(fstore) if not ntp.is_configured(): ntp.create_instance() if options.dirsrv_pkcs12: ds = dsinstance.DsInstance(fstore=fstore, cert_nickname=dirsrv_cert_name) ds.create_instance(realm_name, host_name, domain_name, dm_password, dirsrv_pkcs12_info, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject, hbac_allow=not options.hbac_allow, ca_file=ca_file) else: ds = dsinstance.DsInstance(fstore=fstore) ds.create_instance(realm_name, host_name, domain_name, dm_password, idstart=options.idstart, idmax=options.idmax, subject_base=options.subject, hbac_allow=not options.hbac_allow) else: ds = dsinstance.DsInstance(fstore=fstore) ds.init_info( realm_name, host_name, domain_name, dm_password, options.subject, 1101, 1100, None) if setup_ca: ca = cainstance.CAInstance(realm_name, certs.NSS_DIR, dogtag_constants=dogtag.install_constants) if external == 0: ca.configure_instance(host_name, domain_name, dm_password, dm_password, subject_base=options.subject) elif external == 1: # stage 1 of external CA installation options.realm_name = realm_name options.domain_name = domain_name options.master_password = master_password options.dm_password = dm_password options.admin_password = admin_password options.host_name = host_name options.unattended = True options.forwarders = dns_forwarders options.reverse_zone = reverse_zone write_cache(vars(options)) ca.configure_instance(host_name, domain_name, dm_password, dm_password, csr_file="/root/ipa.csr", subject_base=options.subject) else: # stage 2 of external CA installation ca.configure_instance(host_name, domain_name, dm_password, dm_password, cert_file=options.external_cert_file, cert_chain_file=options.external_ca_file, subject_base=options.subject) # Now put the CA cert where other instances exepct it ca.publish_ca_cert("/etc/ipa/ca.crt") # we now need to enable ssl on the ds ds.enable_ssl() ds.restart() if setup_ca: # We need to ldap_enable the CA now that DS is up and running ca.ldap_enable('CA', host_name, dm_password, ipautil.realm_to_suffix(realm_name)) # This is done within stopped_service context, which restarts CA ca.enable_client_auth_to_db() # Upload the CA cert to the directory ds.upload_ca_cert() else: with open(options.root_ca_file) as f: pem_cert = f.read() # Trust the CA cert root_logger.info( 'Trusting certificate authority from %s' % options.root_ca_file) certs.NSSDatabase('/etc/pki/nssdb').import_pem_cert( 'External CA cert', 'CT,,', options.root_ca_file) # Put a CA cert where other instances expect it with open('/etc/ipa/ca.crt', 'wb') as f: f.write(pem_cert) # Install the CA cert for the HTTP server with open('/usr/share/ipa/html/ca.crt', 'wb') as f: f.write(pem_cert) # Upload the CA cert to the directory ds.upload_ca_dercert(base64.b64decode(x509.strip_header(pem_cert))) krb = krbinstance.KrbInstance(fstore) if options.pkinit_pkcs12: krb.create_instance(realm_name, host_name, domain_name, dm_password, master_password, setup_pkinit=options.setup_pkinit, pkcs12_info=pkinit_pkcs12_info, subject_base=options.subject) else: krb.create_instance(realm_name, host_name, domain_name, dm_password, master_password, setup_pkinit=options.setup_pkinit, subject_base=options.subject) # The DS instance is created before the keytab, add the SSL cert we # generated ds.add_cert_to_service() memcache = memcacheinstance.MemcacheInstance() memcache.create_instance('MEMCACHE', host_name, dm_password, ipautil.realm_to_suffix(realm_name)) otpd = otpdinstance.OtpdInstance() otpd.create_instance('OTPD', host_name, dm_password, ipautil.realm_to_suffix(realm_name)) # Create a HTTP instance http = httpinstance.HTTPInstance(fstore) if options.http_pkcs12: http.create_instance( realm_name, host_name, domain_name, dm_password, pkcs12_info=http_pkcs12_info, subject_base=options.subject, auto_redirect=options.ui_redirect, ca_file=ca_file) else: http.create_instance( realm_name, host_name, domain_name, dm_password, subject_base=options.subject, auto_redirect=options.ui_redirect) ipaservices.restore_context("/var/cache/ipa/sessions") set_subject_in_config(realm_name, dm_password, ipautil.realm_to_suffix(realm_name), options.subject) # Apply any LDAP updates. Needs to be done after the configuration file # is created service.print_msg("Applying LDAP updates") ds.apply_updates() # Restart ds and krb after configurations have been changed service.print_msg("Restarting the directory server") ds.restart() service.print_msg("Restarting the KDC") krb.restart() # Create a BIND instance bind = bindinstance.BindInstance(fstore, dm_password) bind.setup(host_name, ip_address, realm_name, domain_name, dns_forwarders, options.conf_ntp, reverse_zone, zonemgr=options.zonemgr, ca_configured=setup_ca) if options.setup_dns: api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password) bind.create_instance() print "" bind.check_global_configuration() print "" else: bind.create_sample_bind_zone() # Restart httpd to pick up the new IPA configuration service.print_msg("Restarting the web server") http.restart() # Set the admin user kerberos password ds.change_admin_password(admin_password) # Call client install script try: args = ["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--domain", domain_name, "--server", host_name, "--realm", realm_name, "--hostname", host_name] if not options.create_sshfp: args.append("--no-dns-sshfp") if options.trust_sshfp: args.append("--ssh-trust-dns") if not options.conf_ssh: args.append("--no-ssh") if not options.conf_sshd: args.append("--no-sshd") if options.mkhomedir: args.append("--mkhomedir") run(args) except Exception, e: sys.exit("Configuration of client side components failed!\nipa-client-install returned: " + str(e)) #Everything installed properly, activate ipa service. ipaservices.knownservices.ipa.enable() print "==============================================================================" print "Setup complete" print "" print "Next steps:" print "\t1. You must make sure these network ports are open:" print "\t\tTCP Ports:" print "\t\t * 80, 443: HTTP/HTTPS" print "\t\t * 389, 636: LDAP/LDAPS" print "\t\t * 88, 464: kerberos" if options.setup_dns: print "\t\t * 53: bind" print "\t\tUDP Ports:" print "\t\t * 88, 464: kerberos" if options.setup_dns: print "\t\t * 53: bind" if options.conf_ntp: print "\t\t * 123: ntp" print "" print "\t2. You can now obtain a kerberos ticket using the command: 'kinit admin'" print "\t This ticket will allow you to use the IPA tools (e.g., ipa user-add)" print "\t and the web user interface." if not ipaservices.knownservices.ntpd.is_running(): print "\t3. Kerberos requires time synchronization between clients" print "\t and servers for correct operation. You should consider enabling ntpd." print "" if setup_ca: print "Be sure to back up the CA certificate stored in /root/cacert.p12" print "This file is required to create replicas. The password for this" print "file is the Directory Manager password" else: print "In order for Firefox autoconfiguration to work you will need to" print "use a SSL signing certificate. See the IPA documentation for more details." if ipautil.file_exists(ANSWER_CACHE): os.remove(ANSWER_CACHE) return 0 if __name__ == '__main__': success = False try: # FIXME: Common option parsing, logging setup, etc should be factored # out from all install scripts safe_options, options = parse_options() if options.uninstall: log_file_name = "/var/log/ipaserver-uninstall.log" else: log_file_name = "/var/log/ipaserver-install.log" # Use private ccache with private_ccache(): installutils.run_script(main, log_file_name=log_file_name, operation_name='ipa-server-install') success = True finally: if not success and installation_cleanup: # Do a cautious clean up as we don't know what failed and what is # the state of the environment try: fstore.restore_file('/etc/hosts') except: pass freeipa-3.3.4/install/tools/ipa-replica-conncheck0000775000175000017500000004137512271663206021374 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Martin Kosek # # Copyright (C) 2011 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 . # from ipapython.config import IPAOptionParser from ipapython import version from ipapython import ipautil from ipapython import dogtag from ipapython.ipautil import CalledProcessError from ipaserver.install import installutils import ipaclient.ipachangeconf from optparse import OptionGroup from ipapython.ipa_log_manager import * import sys import os import signal import tempfile import socket import time import threading import errno from socket import SOCK_STREAM, SOCK_DGRAM import distutils.spawn CONNECT_TIMEOUT = 5 RESPONDERS = [ ] QUIET = False CCACHE_FILE = "/etc/ipa/.conncheck_ccache" KRB5_CONFIG = None class SshExec(object): def __init__(self, user, addr): self.user = user self.addr = addr self.cmd = distutils.spawn.find_executable('ssh') def __call__(self, command, verbose=False): # Bail if ssh is not installed if self.cmd is None: print "WARNING: ssh not installed, skipping ssh test" return ('', '', 0) tmpf = tempfile.NamedTemporaryFile() cmd = [ self.cmd, '-o StrictHostKeychecking=no', '-o UserKnownHostsFile=%s' % tmpf.name, '%s@%s' % (self.user, self.addr), command ] if verbose: cmd.insert(1, '-v') env = {'KRB5_CONFIG': KRB5_CONFIG, 'KRB5CCNAME': CCACHE_FILE} return ipautil.run(cmd, env=env, raiseonerr=False) class CheckedPort(object): def __init__(self, port, port_type, description): self.port = port self.port_type = port_type self.description = description BASE_PORTS = [ CheckedPort(389, SOCK_STREAM, "Directory Service: Unsecure port"), CheckedPort(636, SOCK_STREAM, "Directory Service: Secure port"), CheckedPort(88, SOCK_STREAM, "Kerberos KDC: TCP"), CheckedPort(88, SOCK_DGRAM, "Kerberos KDC: UDP"), CheckedPort(464, SOCK_STREAM, "Kerberos Kpasswd: TCP"), CheckedPort(464, SOCK_DGRAM, "Kerberos Kpasswd: UDP"), CheckedPort(80, SOCK_STREAM, "HTTP Server: Unsecure port"), CheckedPort(443, SOCK_STREAM, "HTTP Server: Secure port"), ] def print_info(msg): if not QUIET: print msg def parse_options(): parser = IPAOptionParser(version=version.VERSION) replica_group = OptionGroup(parser, "on-replica options") replica_group.add_option("-m", "--master", dest="master", help="Master address with running IPA for output connection check") replica_group.add_option("-a", "--auto-master-check", dest="auto_master_check", action="store_true", default=False, help="Automatically execute connection check on master") replica_group.add_option("-r", "--realm", dest="realm", help="Realm name") replica_group.add_option("-k", "--kdc", dest="kdc", help="Master KDC. Defaults to master address") replica_group.add_option("-p", "--principal", dest="principal", default="admin", help="Principal to use to log in to remote master") replica_group.add_option("-w", "--password", dest="password", sensitive=True, help="Password for the principal"), parser.add_option_group(replica_group) master_group = OptionGroup(parser, "on-master options") master_group.add_option("-R", "--replica", dest="replica", help="Address of remote replica machine to check against") parser.add_option_group(master_group) common_group = OptionGroup(parser, "common options") common_group.add_option("-c", "--check-ca", dest="check_ca", action="store_true", default=False, help="Check also ports for Certificate Authority " "(for servers installed before IPA 3.1)") common_group.add_option("", "--hostname", dest="hostname", help="The hostname of this server (FQDN). " "By default a nodename from uname(2) is used.") parser.add_option_group(common_group) parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="Print debugging information") parser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, help="Output only errors") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) if options.master and options.replica: parser.error("on-master and on-replica options are mutually exclusive!") if options.master: if options.auto_master_check and not options.realm: parser.error("Realm is parameter is required to connect to remote master!") if not os.getegid() == 0: parser.error("You can only run on-replica part as root.") if options.master and not options.kdc: options.kdc = options.master if not options.master and not options.replica: parser.error("No action: you should select either --replica or --master option.") if not options.hostname: options.hostname = socket.getfqdn() if options.quiet: global QUIET QUIET = True return safe_options, options def logging_setup(options): log_file = None if os.getegid() == 0: log_file = "/var/log/ipareplica-conncheck.log" standard_logging_setup(log_file, debug=options.debug) def clean_responders(responders): if not responders: return for responder in responders: responder.stop() for responder in responders: responder.join() responders.remove(responder) def sigterm_handler(signum, frame): # do what SIGINT does (raise a KeyboardInterrupt) sigint_handler = signal.getsignal(signal.SIGINT) if callable(sigint_handler): sigint_handler(signum, frame) def configure_krb5_conf(realm, kdc, filename): krbconf = ipaclient.ipachangeconf.IPAChangeConf("IPA Installer") krbconf.setOptionAssignment((" = ", " ")) krbconf.setSectionNameDelimiters(("[","]")) krbconf.setSubSectionDelimiters(("{","}")) krbconf.setIndent((""," "," ")) opts = [{'name':'comment', 'type':'comment', 'value':'File created by ipa-replica-conncheck'}, {'name':'empty', 'type':'empty'}] #[libdefaults] libdefaults = [{'name':'default_realm', 'type':'option', 'value':realm}] libdefaults.append({'name':'dns_lookup_realm', 'type':'option', 'value':'false'}) libdefaults.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'true'}) libdefaults.append({'name':'rdns', 'type':'option', 'value':'false'}) libdefaults.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'}) libdefaults.append({'name':'forwardable', 'type':'option', 'value':'yes'}) opts.append({'name':'libdefaults', 'type':'section', 'value': libdefaults}) opts.append({'name':'empty', 'type':'empty'}) #the following are necessary only if DNS discovery does not work #[realms] realms_info =[{'name':'kdc', 'type':'option', 'value':ipautil.format_netloc(kdc, 88)}, {'name':'master_kdc', 'type':'option', 'value':ipautil.format_netloc(kdc, 88)}, {'name':'admin_server', 'type':'option', 'value':ipautil.format_netloc(kdc, 749)}] realms = [{'name':realm, 'type':'subsection', 'value':realms_info}] opts.append({'name':'realms', 'type':'section', 'value':realms}) opts.append({'name':'empty', 'type':'empty'}) #[appdefaults] pamopts = [{'name':'debug', 'type':'option', 'value':'false'}, {'name':'ticket_lifetime', 'type':'option', 'value':'36000'}, {'name':'renew_lifetime', 'type':'option', 'value':'36000'}, {'name':'forwardable', 'type':'option', 'value':'true'}, {'name':'krb4_convert', 'type':'option', 'value':'false'}] appopts = [{'name':'pam', 'type':'subsection', 'value':pamopts}] opts.append({'name':'appdefaults', 'type':'section', 'value':appopts}) root_logger.debug("Writing temporary Kerberos configuration to %s:\n%s" % (filename, krbconf.dump(opts))) krbconf.newConf(filename, opts) class PortResponder(threading.Thread): def __init__(self, port, port_type, socket_timeout=1): super(PortResponder, self).__init__() self.port = port self.port_type = port_type self.socket_timeout = socket_timeout self._stop_request = False def run(self): while not self._stop_request: try: ipautil.bind_port_responder(self.port, self.port_type, socket_timeout=self.socket_timeout, responder_data="FreeIPA") except socket.timeout: pass except socket.error, e: if e.errno == errno.EADDRINUSE: time.sleep(1) else: raise def stop(self): self._stop_request = True def port_check(host, port_list): ports_failed = [] ports_udp_warning = [] # conncheck could not verify that port is open for port in port_list: 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: ports_udp_warning.append(port) result = "WARNING" else: ports_failed.append(port) result = "FAILED" print_info(" %s (%d): %s" % (port.description, port.port, result)) if ports_udp_warning: print "The following UDP ports could not be verified as open: %s" \ % ", ".join(str(port.port) for port in ports_udp_warning) print "This can happen if they are already bound to an application" print "and ipa-replica-conncheck cannot attach own UDP responder." if ports_failed: msg_ports = [] for port in ports_failed: port_type_text = "TCP" if port.port_type == SOCK_STREAM else "UDP" msg_ports.append('%d (%s)' % (port.port, port_type_text)) raise RuntimeError("Port check failed! Inaccessible port(s): %s" \ % ", ".join(msg_ports)) def main(): safe_options, options = parse_options() logging_setup(options) 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") signal.signal(signal.SIGTERM, sigterm_handler) required_ports = BASE_PORTS if options.check_ca: # Check old Dogtag CA replication port # New installs with unified databases use main DS port (checked above) required_ports.append(CheckedPort(dogtag.Dogtag9Constants.DS_PORT, SOCK_STREAM, "PKI-CA: Directory Service port")) if options.replica: print_info("Check connection from master to remote replica '%s':" % options.replica) port_check(options.replica, required_ports) print_info("\nConnection from master to replica is OK.") # kinit to foreign master if options.master: # check ports on master first print_info("Check connection from replica to remote master '%s':" % options.master) tcp_ports = [ port for port in required_ports if port.port_type == SOCK_STREAM ] udp_ports = [ port for port in required_ports if port.port_type == SOCK_DGRAM ] port_check(options.master, tcp_ports) if udp_ports: print_info("\nThe following list of ports use UDP protocol and would need to be") print_info("checked manually:") for port in udp_ports: result = "SKIPPED" print_info(" %s (%d): %s" % (port.description, port.port, result)) print_info("\nConnection from replica to master is OK.") # create listeners global RESPONDERS print_info("Start listening on required ports for remote master check") for port in required_ports: root_logger.debug("Start listening on port %d (%s)" % (port.port, port.description)) responder = PortResponder(port.port, port.port_type) responder.start() RESPONDERS.append(responder) remote_check_opts = ['--replica %s' % options.hostname] if options.auto_master_check: (krb_fd, krb_name) = tempfile.mkstemp() os.close(krb_fd) configure_krb5_conf(options.realm, options.kdc, krb_name) global KRB5_CONFIG KRB5_CONFIG = krb_name print_info("Get credentials to log in to remote master") if options.principal.find('@') == -1: principal = '%s@%s' % (options.principal, options.realm) user = options.principal else: principal = options.principal user = options.principal.partition('@')[0] if options.password: password=options.password else: password = installutils.read_password(principal, confirm=False, validate=False, retry=False) if password is None: sys.exit("Principal password required") stderr='' (stdout, stderr, returncode) = ipautil.run(['/usr/bin/kinit', principal], env={'KRB5_CONFIG':KRB5_CONFIG, 'KRB5CCNAME':CCACHE_FILE}, stdin=password, raiseonerr=False) if returncode != 0: raise RuntimeError("Cannot acquire Kerberos ticket: %s" % stderr) # Verify kinit was actually successful stderr='' (stdout, stderr, returncode) = ipautil.run(['/usr/bin/kvno', 'host/%s' % options.master], env={'KRB5_CONFIG':KRB5_CONFIG, 'KRB5CCNAME':CCACHE_FILE}, raiseonerr=False) if returncode != 0: raise RuntimeError("Could not get ticket for master server: %s" % stderr) ssh = SshExec(user, options.master) print_info("Check SSH connection to remote master") stdout, stderr, returncode = ssh('echo OK', verbose=True) if returncode != 0: print 'Could not SSH into remote host. Error output:' for line in stderr.splitlines(): print ' %s' % line raise RuntimeError('Could not SSH to remote host.') print_info("Execute check on remote master") stdout, stderr, returncode = ssh( "/usr/sbin/ipa-replica-conncheck " + " ".join(remote_check_opts)) print_info(stdout) if returncode != 0: raise RuntimeError("Remote master check failed with following error message(s):\n%s" % stderr) else: # wait until user test is ready print_info("Listeners are started. Use CTRL+C to terminate the listening part after the test.") print_info("") print_info("Please run the following command on remote master:") print_info("/usr/sbin/ipa-replica-conncheck " + " ".join(remote_check_opts)) time.sleep(3600) print_info("Connection check timeout: terminating listening program") if __name__ == "__main__": try: sys.exit(main()) except SystemExit, e: sys.exit(e) except KeyboardInterrupt: print_info("\nCleaning up...") sys.exit(1) except RuntimeError, e: sys.exit(e) finally: clean_responders(RESPONDERS) for file_name in (CCACHE_FILE, KRB5_CONFIG): if file_name: try: os.remove(file_name) except OSError: pass freeipa-3.3.4/install/tools/Makefile.am0000664000175000017500000000111112271663206017343 0ustar mkosekmkosekNULL = SUBDIRS = \ man \ $(NULL) sbin_SCRIPTS = \ ipa-ca-install \ ipa-dns-install \ ipa-server-install \ ipa-adtrust-install \ ipa-replica-conncheck \ ipa-replica-install \ ipa-replica-prepare \ ipa-replica-manage \ ipa-csreplica-manage \ ipa-server-certinstall \ ipactl \ ipa-compat-manage \ ipa-nis-manage \ ipa-managed-entries \ ipa-ldap-updater \ ipa-upgradeconfig \ ipa-backup \ ipa-restore \ ipa-advise \ $(NULL) EXTRA_DIST = \ README \ $(sbin_SCRIPTS) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/tools/ipa-replica-prepare0000775000175000017500000000156512271663206021074 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Petr Viktorin # # 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 . # from ipaserver.install.ipa_replica_prepare import ReplicaPrepare ReplicaPrepare.run_cli() freeipa-3.3.4/install/tools/ipa-advise0000775000175000017500000000152712271663206017272 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Tomas Babej # # Copyright (C) 2013 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 . # from ipaserver.advise.base import IpaAdvise IpaAdvise.run_cli() freeipa-3.3.4/install/tools/ipa-csreplica-manage0000775000175000017500000003750312271663206021215 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Rob Crittenden # # Based on ipa-replica-manage by Karl MacMillan # # Copyright (C) 2011 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 . # import sys import os import krbV from ipapython.ipa_log_manager import * from ipaserver.install import replication, installutils, bindinstance from ipalib import api, errors, util from ipapython import ipautil, ipaldap, version, dogtag from ipapython.dn import DN CACERT = "/etc/ipa/ca.crt" # dict of command name and tuples of min/max num of args needed commands = { "list":(0, 1, "[master fqdn]", ""), "connect":(1, 2, " [other master fqdn]", "must provide the name of the servers to connect"), "disconnect":(1, 2, " [other master fqdn]", "must provide the name of the server to disconnect"), "del":(1, 1, "", "must provide hostname of master to delete"), "re-initialize":(0, 0, "", ""), "force-sync":(0, 0, "", "") } def parse_options(): from optparse import OptionParser parser = OptionParser(version=version.VERSION) parser.add_option("-H", "--host", dest="host", help="starting host") parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="provide additional information") parser.add_option("-f", "--force", dest="force", action="store_true", default=False, help="ignore some types of errors") parser.add_option("--from", dest="fromhost", help="Host to get data from") options, args = parser.parse_args() valid_syntax = False if len(args): n = len(args) - 1 k = commands.keys() for cmd in k: if cmd == args[0]: v = commands[cmd] err = None if n < v[0]: err = v[3] elif n > v[1]: err = "too many arguments" else: valid_syntax = True if err: parser.error("Invalid syntax: %s\nUsage: %s [options] %s" % (err, cmd, v[2])) if not valid_syntax: cmdstr = " | ".join(commands.keys()) parser.error("must provide a command [%s]" % cmdstr) return options, args def list_replicas(realm, host, replica, dirman_passwd, verbose): peers = {} try: # connect to main IPA LDAP server conn = ipaldap.IPAdmin(host, 636, cacert=CACERT) conn.do_simple_bind(bindpw=dirman_passwd) dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL) for ent in entries: try: cadn = DN(('cn', 'CA'), DN(ent.dn)) entry = conn.get_entry(cadn) peers[ent.single_value('cn')] = ['master', ''] except errors.NotFound: peers[ent.single_value('cn')] = ['CA not configured', ''] except Exception, e: sys.exit( "Failed to get data from '%s' while trying to list replicas: %s" % (host, e)) finally: conn.unbind() if not replica: for k, p in peers.iteritems(): print '%s: %s' % (k, p[0]) return try: repl = replication.get_cs_replication_manager(realm, replica, dirman_passwd) except Exception, e: sys.exit(str(e)) entries = repl.find_replication_agreements() for entry in entries: print '%s' % entry.single_value('nsds5replicahost', None) if verbose: print " last init status: %s" % entry.single_value( 'nsds5replicalastinitstatus', None) print " last init ended: %s" % str( ipautil.parse_generalized_time( entry.single_value('nsds5replicalastinitend'))) print " last update status: %s" % entry.single_value( 'nsds5replicalastupdatestatus', None) print " last update ended: %s" % str( ipautil.parse_generalized_time( entry.single_value('nsds5replicalastupdateend'))) def del_link(realm, replica1, replica2, dirman_passwd, force=False): repl2 = None try: repl1 = replication.get_cs_replication_manager(realm, replica1, dirman_passwd) repl1.hostnames = [replica1, replica2] repl_list1 = repl1.find_replication_agreements() # Find the DN of the replication agreement to remove replica1_dn = None for e in repl_list1: if e.single_value('nsDS5ReplicaHost', None) == replica2: replica1_dn = e.dn break if replica1_dn is None: sys.exit("'%s' has no replication agreement for '%s'" % (replica1, replica2)) repl1.hostnames = [replica1, replica2] except errors.NetworkError, e: sys.exit("Unable to connect to %s: %s" % (replica1, e)) except Exception, e: sys.exit("Failed to get data from '%s': %s" % (replica1, e)) try: repl2 = replication.get_cs_replication_manager(realm, replica2, dirman_passwd) repl2.hostnames = [replica1, replica2] repl_list = repl2.find_replication_agreements() # Now that we've confirmed that both hostnames are vaild, make sure # that we aren't removing the last link from either side. 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" sys.exit(1) if not force and len(repl_list1) <= 1: print "Cannot remove the last replication link of '%s'" % replica1 print "Please use the 'del' command to remove it from the domain" sys.exit(1) # Find the DN of the replication agreement to remove replica2_dn = None for e in repl_list: if e.single_value('nsDS5ReplicaHost', None) == replica1: replica2_dn = e.dn break # This should never happen if replica2_dn is None: sys.exit("'%s' has no replication agreement for '%s'" % (replica1, replica2)) except errors.NotFound: print "'%s' has no replication agreement for '%s'" % (replica2, replica1) if not force: return except Exception, e: print "Failed to get data from '%s': %s" % (replica2, e) if not force: sys.exit(1) if repl2: failed = False try: repl2.delete_agreement(replica1, replica2_dn) repl2.delete_referral(replica1, repl1.port) except Exception, e: print "Unable to remove agreement on %s: %s" % (replica2, e) failed = True if failed: if force: print "Forcing removal on '%s'" % replica1 else: sys.exit(1) if not repl2 and force: print "Forcing removal on '%s'" % replica1 repl1.delete_agreement(replica2, replica1_dn) repl1.delete_referral(replica2, repl2.port) print "Deleted replication agreement from '%s' to '%s'" % (replica1, replica2) def del_master(realm, hostname, options): force_del = False delrepl = None # 1. Connect to the local dogtag DS server try: thisrepl = replication.get_cs_replication_manager(realm, options.host, options.dirman_passwd) except Exception, e: sys.exit("Failed to connect to server %s: %s" % (options.host, e)) # 2. Ensure we have an agreement with the master if thisrepl.get_replication_agreement(hostname) is None: sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname)) # 3. Connect to the dogtag DS to be removed. try: delrepl = replication.get_cs_replication_manager(realm, hostname, options.dirman_passwd) except Exception, e: if not options.force: print "Unable to delete replica %s: %s" % (hostname, e) sys.exit(1) else: print "Unable to connect to replica %s, forcing removal" % hostname force_del = True # 4. Get list of agreements. if delrepl is None: # server not up, just remove it from this server replica_names = [options.host] else: replica_entries = delrepl.find_ipa_replication_agreements() replica_names = [rep.single_value('nsds5replicahost', None) for rep in replica_entries] # 5. Remove each agreement for r in replica_names: try: del_link(realm, r, hostname, options.dirman_passwd, force=True) except Exception, e: sys.exit("There were issues removing a connection: %s" % e) # 6. And clean up the removed replica DNS entries if any. try: if bindinstance.dns_container_exists(options.host, api.env.basedn, dm_password=options.dirman_passwd): api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=options.dirman_passwd) bind = bindinstance.BindInstance() bind.remove_ipa_ca_dns_records(hostname, realm.lower()) except Exception, e: print "Failed to cleanup %s DNS entries: %s" % (hostname, e) print "You may need to manually remove them from the tree" def add_link(realm, replica1, replica2, dirman_passwd, options): try: repl2 = replication.get_cs_replication_manager(realm, replica2, dirman_passwd) except Exception, e: sys.exit(str(e)) try: conn = ipaldap.IPAdmin(replica2, 636, cacert=CACERT) conn.do_simple_bind(bindpw=dirman_passwd) dn = DN(('cn', 'CA'), ('cn', replica2), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) conn.get_entries(dn, conn.SCOPE_ONELEVEL) conn.unbind() except errors.NotFound: sys.exit('%s does not have a CA configured.' % replica2) except errors.NetworkError, e: sys.exit("Unable to connect to %s: %s" % (ipautil.format_netloc(replica2, 636), str(e))) except Exception, e: sys.exit("Failed to get data while trying to bind to '%s': %s" % (replica1, str(e))) try: repl1 = replication.get_cs_replication_manager(realm, replica1, dirman_passwd) entries = repl1.find_replication_agreements() for e in entries: if e.single_value('nsDS5ReplicaHost', None) == replica2: sys.exit('This replication agreement already exists.') repl1.hostnames = [replica1, replica2] except errors.NotFound: sys.exit("Cannot find replica '%s'" % replica1) except errors.NetworkError, e: sys.exit("Unable to connect to %s: %s" % (replica1, e)) except Exception, e: sys.exit( "Failed to get data from '%s' while trying to get current " "agreements: %s" % (replica1, e)) repl1.setup_replication( replica2, repl2.port, 0, DN(('cn', 'Directory Manager')), dirman_passwd, is_cs_replica=True, local_port=repl1.port) print "Connected '%s' to '%s'" % (replica1, replica2) def re_initialize(realm, options): if not options.fromhost: sys.exit("re-initialize requires the option --from ") thishost = installutils.get_fqdn() try: repl = replication.get_cs_replication_manager(realm, options.fromhost, options.dirman_passwd) thisrepl = replication.get_cs_replication_manager(realm, thishost, options.dirman_passwd) except Exception, e: sys.exit(str(e)) filter = repl.get_agreement_filter(host=thishost) try: entry = repl.conn.get_entries( DN(('cn', 'config')), repl.conn.SCOPE_SUBTREE, filter) except errors.NotFound: root_logger.error("Unable to find %s -> %s replication agreement" % (options.fromhost, thishost)) sys.exit(1) if len(entry) > 1: root_logger.error("Found multiple agreements for %s. Only initializing the first one returned: %s" % (thishost, entry[0].dn)) repl.hostnames = thisrepl.hostnames = [thishost, options.fromhost] thisrepl.enable_agreement(options.fromhost) repl.enable_agreement(thishost) repl.initialize_replication(entry[0].dn, repl.conn) repl.wait_for_repl_init(repl.conn, entry[0].dn) def force_sync(realm, thishost, fromhost, dirman_passwd): try: repl = replication.get_cs_replication_manager(realm, fromhost, dirman_passwd) repl.force_sync(repl.conn, thishost) except Exception, e: sys.exit(str(e)) def main(): options, args = parse_options() # Just initialize the environment. This is so the installer can have # access to the plugin environment api_env = {'in_server' : True, 'verbose' : options.verbose, } if os.getegid() != 0: api_env['log'] = None # turn off logging for non-root api.bootstrap(**api_env) api.finalize() dirman_passwd = None realm = krbV.default_context().default_realm if options.host: host = options.host else: host = installutils.get_fqdn() options.host = host if options.dirman_passwd: dirman_passwd = options.dirman_passwd else: dirman_passwd = installutils.read_password("Directory Manager", confirm=False, validate=False, retry=False) if dirman_passwd is None: sys.exit("Directory Manager password required") options.dirman_passwd = dirman_passwd if args[0] == "list": replica = None if len(args) == 2: replica = args[1] list_replicas(realm, host, replica, dirman_passwd, options.verbose) elif args[0] == "del": del_master(realm, args[1], options) elif args[0] == "re-initialize": re_initialize(realm, options) elif args[0] == "force-sync": if not options.fromhost: sys.exit("force-sync requires the option --from ") force_sync(realm, host, options.fromhost, options.dirman_passwd) elif args[0] == "connect": if len(args) == 3: replica1 = args[1] replica2 = args[2] elif len(args) == 2: replica1 = host replica2 = args[1] add_link(realm, replica1, replica2, dirman_passwd, options) elif args[0] == "disconnect": if len(args) == 3: replica1 = args[1] replica2 = args[2] elif len(args) == 2: replica1 = host replica2 = args[1] del_link(realm, replica1, replica2, dirman_passwd, options.force) try: main() except KeyboardInterrupt: sys.exit(1) except SystemExit, e: sys.exit(e) except Exception, e: sys.exit("unexpected error: %s" % e) freeipa-3.3.4/install/tools/ipa-ca-install0000775000175000017500000002107312271663206020044 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Rob Crittenden # # Copyright (C) 2011 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 . # import sys import socket import os, shutil from ipapython import ipautil from ipapython import services as ipaservices from ipaserver.install import installutils, service from ipaserver.install import certs from ipaserver.install.installutils import (HostnameLocalhost, ReplicaConfig, expand_replica_info, read_replica_info, get_host_name, BadHostError, private_ccache) from ipaserver.install import dsinstance, cainstance, bindinstance from ipaserver.install.replication import replica_conn_check from ipapython import version from ipalib import api, util from ipapython.dn import DN from ipapython.config import IPAOptionParser from ipapython import sysrestore from ipapython import dogtag from ipapython.ipa_log_manager import * log_file_name = "/var/log/ipareplica-ca-install.log" REPLICA_INFO_TOP_DIR = None def parse_options(): usage = "%prog [options] REPLICA_FILE" parser = IPAOptionParser(usage=usage, version=version.VERSION) parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="gather extra debugging information") parser.add_option("-p", "--password", dest="password", sensitive=True, help="Directory Manager (existing master) password") parser.add_option("-w", "--admin-password", dest="admin_password", sensitive=True, help="Admin user Kerberos password used for connection check") parser.add_option("--no-host-dns", dest="no_host_dns", action="store_true", default=False, help="Do not use DNS for hostname lookup during installation") parser.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true", default=False, help="skip connection check to remote master") parser.add_option("--skip-schema-check", dest="skip_schema_check", action="store_true", default=False, help="skip check for updated CA DS schema on the remote master") parser.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) if len(args) != 1: parser.error("you must provide a file generated by ipa-replica-prepare") return safe_options, options, args[0] def get_dirman_password(): return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) def install_dns_records(config, options): if not bindinstance.dns_container_exists(config.master_host_name, ipautil.realm_to_suffix(config.realm_name), dm_password=config.dirman_password): return bind = bindinstance.BindInstance(dm_password=config.dirman_password) try: api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=config.dirman_password) bind.add_ipa_ca_dns_records(config.host_name, config.domain_name) finally: if api.Backend.ldap2.isconnected(): api.Backend.ldap2.disconnect() def main(): safe_options, options, filename = parse_options() if os.geteuid() != 0: sys.exit("\nYou must be root to run this script.\n") standard_logging_setup(log_file_name, debug=options.debug) root_logger.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options)) if not ipautil.file_exists(filename): sys.exit("Replica file %s does not exist" % filename) global sstore sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') if not dsinstance.DsInstance().is_configured(): sys.exit("IPA server is not configured on this system.\n") api.bootstrap(in_server=True) api.finalize() if api.env.ra_plugin == 'selfsign': sys.exit('A selfsign CA can not be added') # get the directory manager password dirman_password = options.password if not dirman_password: if options.unattended: sys.exit('Directory Manager password required') try: dirman_password = get_dirman_password() except KeyboardInterrupt: sys.exit(0) if dirman_password is None: sys.exit("Directory Manager password required") if not options.admin_password and not options.skip_conncheck and \ options.unattended: sys.exit('admin password required') try: top_dir, dir = expand_replica_info(filename, dirman_password) global REPLICA_INFO_TOP_DIR REPLICA_INFO_TOP_DIR = top_dir except Exception, e: print "ERROR: Failed to decrypt or open the replica file." print "Verify you entered the correct Directory Manager password." sys.exit(1) config = ReplicaConfig() read_replica_info(dir, config) config.dirman_password = dirman_password try: host = get_host_name(options.no_host_dns) except BadHostError, e: root_logger.error(str(e)) sys.exit(1) 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): sys.exit(0) config.host_name = host print "" except KeyboardInterrupt: sys.exit(0) config.dir = dir config.setup_ca = True if not ipautil.file_exists(config.dir + "/cacert.p12"): print 'CA cannot be installed in CA-less setup.' sys.exit(1) portfile = config.dir + "/dogtag_directory_port.txt" if not ipautil.file_exists(portfile): dogtag_master_ds_port = str(dogtag.Dogtag9Constants.DS_PORT) else: with open(portfile) as fd: dogtag_master_ds_port = fd.read() if not options.skip_conncheck: replica_conn_check( config.master_host_name, config.host_name, config.realm_name, True, dogtag_master_ds_port, options.admin_password) if options.skip_schema_check: root_logger.info("Skipping CA DS schema check") else: cainstance.replica_ca_install_check(config, dogtag_master_ds_port) # Configure the CA if necessary CA = cainstance.install_replica_ca( config, dogtag_master_ds_port, postinstall=True) # We need to ldap_enable the CA now that DS is up and running CA.ldap_enable('CA', config.host_name, config.dirman_password, ipautil.realm_to_suffix(config.realm_name)) # This is done within stopped_service context, which restarts CA CA.enable_client_auth_to_db() # Install CA DNS records install_dns_records(config, options) # We need to restart apache as we drop a new config file in there ipaservices.knownservices.httpd.restart(capture_output=True) #update dogtag version in config file try: fd = open("/etc/ipa/default.conf", "a") fd.write( "dogtag_version=%s\n" % dogtag.install_constants.DOGTAG_VERSION) fd.close() except IOError, e: print "Failed to update /etc/ipa/default.conf" root_logger.error(str(e)) sys.exit(1) fail_message = ''' Your system may be partly configured. Run /usr/sbin/ipa-server-install --uninstall to clean up. ''' if __name__ == '__main__': try: with private_ccache(): installutils.run_script(main, log_file_name=log_file_name, operation_name='ipa-ca-install', fail_message=fail_message) finally: # always try to remove decrypted replica file try: if REPLICA_INFO_TOP_DIR: shutil.rmtree(REPLICA_INFO_TOP_DIR) except OSError: pass freeipa-3.3.4/install/tools/ipa-backup0000775000175000017500000000153512271663206017263 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Rob Crittenden # # Copyright (C) 2013 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 . # from ipaserver.install.ipa_backup import Backup Backup.run_cli() freeipa-3.3.4/install/tools/ipa-nis-manage0000775000175000017500000001607312271663206020040 0ustar mkosekmkosek#!/usr/bin/python # Authors: Rob Crittenden # Authors: Simo Sorce # # Copyright (C) 2009 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 . # import sys import os try: from optparse import OptionParser from ipapython import ipautil, config from ipapython import services as ipaservices from ipaserver.install import installutils from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax from ipaserver.plugins.ldap2 import ldap2 from ipalib import api, errors from ipapython.ipa_log_manager import * from ipapython.dn import DN 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) nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config')) compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config')) def parse_options(): usage = "%prog [options] \n" usage += "%prog [options]\n" parser = OptionParser(usage=usage, formatter=config.IPAFormatter()) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Display debugging information about the update(s)") parser.add_option("-y", dest="password", help="File containing the Directory Manager password") config.add_standard_options(parser) options, args = parser.parse_args() config.init_config(options) return 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, retry=False) return password def get_entry(dn, conn): """ Return the entry for the given DN. If the entry is not found return None. """ entry = None try: (dn, entry) = conn.get_entry(dn) except errors.NotFound: pass return entry def main(): retval = 0 files = ['/usr/share/ipa/nis.uldif'] servicemsg = "" if os.getegid() != 0: sys.exit('Must be root to use this tool.') installutils.check_server_configuration() options, args = parse_options() if len(args) != 1: sys.exit("You must specify one action, either enable or disable") elif args[0] != "enable" and args[0] != "disable": sys.exit("Unrecognized action [" + args[0] + "]") standard_logging_setup(None, debug=options.debug) dirman_password = "" if options.password: try: pw = ipautil.template_file(options.password, []) except IOError: sys.exit("File \"%s\" not found or not readable" % options.password) dirman_password = pw.strip() else: dirman_password = get_dirman_password() if dirman_password is None: sys.exit("Directory Manager password required") if not dirman_password: sys.exit("No password supplied") api.bootstrap(context='cli', debug=options.debug) api.finalize() conn = None try: try: conn = ldap2(shared_instance=False, base_dn='') conn.connect( bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password ) except errors.ExecutionError, lde: sys.exit("An error occurred while connecting to the server: %s" % str(lde)) except errors.AuthorizationError: sys.exit("Incorrect password") if args[0] == "enable": compat = get_entry(compat_dn, conn) if compat is None or compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'off': sys.exit("The compat plugin needs to be enabled: ipa-compat-manage enable") entry = None try: entry = get_entry(nis_config_dn, conn) except errors.ExecutionError, lde: print "An error occurred while talking to the server." print lde retval = 1 # Enable either the portmap or rpcbind service try: portmap = ipaservices.knownservices.portmap portmap.enable() servicemsg = portmap.service_name except ipautil.CalledProcessError, cpe: if cpe.returncode == 1: try: rpcbind = ipaservices.knownservices.rpcbind rpcbind.enable() servicemsg = rpcbind.service_name except ipautil.CalledProcessError, cpe: print "Unable to enable either %s or %s" % (portmap.service_name, rpcbind.service_name) retval = 3 # The cn=config entry for the plugin may already exist but it # could be turned off, handle both cases. if entry is None: print "Enabling plugin" ld = LDAPUpdate(dm_password=dirman_password, sub_dict={}, ldapi=True) if ld.update(files) != True: retval = 1 elif entry.get('nsslapd-pluginenabled', [''])[0].lower() == 'off': print "Enabling plugin" # Already configured, just enable the plugin mod = {'nsslapd-pluginenabled': 'on'} conn.update_entry(nis_config_dn, mod) else: print "Plugin already Enabled" retval = 2 elif args[0] == "disable": try: mod = {'nsslapd-pluginenabled': 'off'} conn.update_entry(nis_config_dn, mod) except errors.NotFound: print "Plugin is already disabled" retval = 2 except errors.EmptyModlist: print "Plugin is already disabled" retval = 2 except errors.LDAPError, lde: print "An error occurred while talking to the server." print lde retval = 1 else: retval = 1 if retval == 0: print "This setting will not take effect until you restart Directory Server." if args[0] == "enable": print "The %s service may need to be started." % servicemsg finally: if conn and conn.isconnected(): conn.disconnect() return retval if __name__ == '__main__': installutils.run_script(main, operation_name='ipa-nis-manage') freeipa-3.3.4/install/tools/ipa-upgradeconfig0000664000175000017500000011525112271663206020631 0ustar mkosekmkosek#!/usr/bin/python # # Authors: # Rob Crittenden # # Copyright (C) 2009 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 . """ Upgrade configuration files to a newer template. """ import sys import re import os import shutil import pwd import fileinput import ConfigParser from ipalib import api import SSSDConfig import ipalib.util import ipalib.errors from ipapython import ipautil, sysrestore, version, services from ipapython.config import IPAOptionParser from ipapython.ipa_log_manager import * from ipapython import certmonger from ipapython import dogtag from ipaserver.install import installutils from ipaserver.install import dsinstance from ipaserver.install import httpinstance from ipaserver.install import memcacheinstance from ipaserver.install import bindinstance from ipaserver.install import service from ipaserver.install import cainstance from ipaserver.install import certs from ipaserver.install import otpdinstance from ipaserver.install import sysupgrade def parse_options(): parser = IPAOptionParser(version=version.VERSION) parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="print debugging information") parser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, help="Output only errors") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) return safe_options, options class KpasswdInstance(service.SimpleServiceInstance): def __init__(self): service.SimpleServiceInstance.__init__(self, "ipa_kpasswd") def uninstall_ipa_kpasswd(): """ We can't use the full service uninstaller because that will attempt to stop and disable the service which by now doesn't exist. We just want to clean up sysrestore.state to remove all references to ipa_kpasswd. """ ipa_kpasswd = KpasswdInstance() running = ipa_kpasswd.restore_state("running") enabled = not ipa_kpasswd.restore_state("enabled") if enabled is not None and not enabled: ipa_kpasswd.remove() def backup_file(filename, ext): """Make a backup of filename using ext as the extension. Do not overwrite previous backups.""" if not os.path.isabs(filename): raise ValueError("Absolute path required") backupfile = filename + ".bak" (reldir, file) = os.path.split(filename) while os.path.exists(backupfile): backupfile = backupfile + "." + str(ext) try: shutil.copy2(filename, backupfile) except IOError, e: if e.errno == 2: # No such file or directory pass else: raise e def update_conf(sub_dict, filename, template_filename): template = ipautil.template_file(template_filename, sub_dict) fd = open(filename, "w") fd.write(template) fd.close() def find_hostname(): """Find the hostname currently configured in ipa-rewrite.conf""" filename="/etc/httpd/conf.d/ipa-rewrite.conf" if not ipautil.file_exists(filename): return None pattern = "^[\s#]*.*https:\/\/([A-Za-z0-9\.\-]*)\/.*" p = re.compile(pattern) for line in fileinput.input(filename): if p.search(line): fileinput.close() return p.search(line).group(1) fileinput.close() raise RuntimeError("Unable to determine the fully qualified hostname from %s" % filename) def find_autoredirect(fqdn): """ When upgrading ipa-rewrite.conf we need to see if the automatic redirect was disabled during install time (or afterward). So sift through the configuration file and see if we can determine the status. Returns True if autoredirect is enabled, False otherwise """ filename = '/etc/httpd/conf.d/ipa-rewrite.conf' if os.path.exists(filename): pattern = "^RewriteRule \^/\$ https://%s/ipa/ui \[L,NC,R=301\]" % fqdn p = re.compile(pattern) for line in fileinput.input(filename): if p.search(line): fileinput.close() return True fileinput.close() return False return True def find_version(filename): """Find the version of a configuration file If no VERSION entry exists in the file, returns 0. If the file does not exist, returns -1. """ if os.path.exists(filename): pattern = "^[\s#]*VERSION\s+([0-9]+)\s+.*" p = re.compile(pattern) for line in fileinput.input(filename): if p.search(line): fileinput.close() return p.search(line).group(1) fileinput.close() # no VERSION found return 0 else: return -1 def upgrade(sub_dict, filename, template, add=False): """ Get the version from the current and template files and update the installed configuration file if there is a new template. If add is True then create a new configuration file. """ old = int(find_version(filename)) new = int(find_version(template)) if old < 0 and not add: root_logger.error("%s not found." % filename) sys.exit(1) if new < 0: root_logger.error("%s not found." % template) if old == 0: # The original file does not have a VERSION entry. This means it's now # managed by IPA, but previously was not. root_logger.warning("%s is now managed by IPA. It will be " "overwritten. A backup of the original will be made.", filename) if old < new or (add and old == 0): backup_file(filename, new) update_conf(sub_dict, filename, template) root_logger.info("Upgraded %s to version %d", filename, new) def check_certs(): """Check ca.crt is in the right place, and try to fix if not""" root_logger.info('[Verifying that root certificate is published]') if not os.path.exists("/usr/share/ipa/html/ca.crt"): ca_file = "/etc/httpd/alias/cacert.asc" if os.path.exists(ca_file): old_umask = os.umask(022) # make sure its readable by httpd try: shutil.copyfile(ca_file, "/usr/share/ipa/html/ca.crt") finally: os.umask(old_umask) else: root_logger.error("Missing Certification Authority file.") root_logger.error("You should place a copy of the CA certificate in /usr/share/ipa/html/ca.crt") else: root_logger.debug('Certificate file exists') def upgrade_pki(ca, fstore): """ Update/add the dogtag proxy configuration. The IPA side of this is handled in ipa-pki-proxy.conf. This requires enabling SSL renegotiation. """ configured_constants = dogtag.configured_constants() root_logger.info('[Verifying that CA proxy configuration is correct]') if not ca.is_configured(): root_logger.info('CA is not configured') return http = httpinstance.HTTPInstance(fstore) http.enable_mod_nss_renegotiate() if not installutils.get_directive(configured_constants.CS_CFG_PATH, 'proxy.securePort', '=') and \ os.path.exists('/usr/bin/pki-setup-proxy'): ipautil.run(['/usr/bin/pki-setup-proxy', '-pki_instance_root=/var/lib' ,'-pki_instance_name=pki-ca','-subsystem_type=ca']) root_logger.debug('Proxy configuration updated') else: root_logger.debug('Proxy configuration up-to-date') def update_dbmodules(realm, filename="/etc/krb5.conf"): newfile = [] found_dbrealm = False found_realm = False prefix = '' root_logger.info('[Verifying that KDC configuration is using ipa-kdb backend]') st = os.stat(filename) fd = open(filename) lines = fd.readlines() fd.close() if ' db_library = ipadb.so\n' in lines: root_logger.debug('dbmodules already updated in %s', filename) return for line in lines: if line.startswith('[dbmodules]'): found_dbrealm = True if found_dbrealm and line.find(realm) > -1: found_realm = True prefix = '#' if found_dbrealm and line.find('}') > -1 and found_realm: found_realm = False newfile.append('#%s' % line) prefix = '' continue newfile.append('%s%s' % (prefix, line)) # Append updated dbmodules information newfile.append(' %s = {\n' % realm) newfile.append(' db_library = ipadb.so\n') newfile.append(' }\n') # Write out new file fd = open(filename, 'w') fd.write("".join(newfile)) fd.close() root_logger.debug('%s updated', filename) def cleanup_kdc(fstore): """ Clean up old KDC files if they exist. We need to remove the actual file and any references in the uninstall configuration. """ root_logger.info('[Checking for deprecated KDC configuration files]') for file in ['kpasswd.keytab', 'ldappwd']: filename = '/var/kerberos/krb5kdc/%s' % file installutils.remove_file(filename) if fstore.has_file(filename): fstore.untrack_file(filename) root_logger.debug('Uninstalling %s', filename) def cleanup_adtrust(fstore): """ Clean up any old Samba backup files that were deprecated. """ root_logger.info('[Checking for deprecated backups of Samba ' 'configuration files]') for backed_up_file in ['/etc/samba/smb.conf']: if fstore.has_file(backed_up_file): fstore.untrack_file(backed_up_file) root_logger.debug('Removing %s from backup', backed_up_file) def setup_firefox_extension(fstore): """Set up the Firefox configuration extension, if it's not set up yet """ root_logger.info('[Setting up Firefox extension]') http = httpinstance.HTTPInstance(fstore) realm = api.env.realm domain = api.env.domain http.setup_firefox_extension(realm, domain) def upgrade_ipa_profile(ca, domain, fqdn): """ Update the IPA Profile provided by dogtag Returns True if restart is needed, False otherwise. """ root_logger.info('[Verifying that CA service certificate profile is updated]') if ca.is_configured(): ski = ca.enable_subject_key_identifier() if ski: root_logger.debug('Subject Key Identifier updated.') else: root_logger.debug('Subject Key Identifier already set.') audit = ca.set_audit_renewal() uri = ca.set_crl_ocsp_extensions(domain, fqdn) if audit or ski or uri: return True else: root_logger.info('CA is not configured') return False def named_remove_deprecated_options(): """ From IPA 3.3, persistent search is a default mechanism for new DNS zone detection. Remove psearch, zone_refresh and cache_ttl options, as they have been deprecated in bind-dyndb-ldap configuration file. When some change in named.conf is done, this functions returns True. """ root_logger.info('[Removing deprecated DNS configuration options]') if not bindinstance.named_conf_exists(): # DNS service may not be configured root_logger.info('DNS is not configured') return False deprecated_options = ['zone_refresh', 'psearch', 'cache_ttl'] removed_options = [] try: # Remove all the deprecated options for option in deprecated_options: value = bindinstance.named_conf_get_directive(option) if value is not None: bindinstance.named_conf_set_directive(option, None) removed_options.append(option) except IOError, e: root_logger.error('Cannot modify DNS configuration in %s: %s', bindinstance.NAMED_CONF, e) # Log only the changed options if not removed_options: root_logger.debug('No changes made') return False root_logger.debug('The following configuration options have been removed: ' '{options}'.format(options = ', '.join(removed_options))) return True def named_set_minimum_connections(): """ Sets the minimal number of connections. When some change in named.conf is done, this functions returns True. """ changed = False root_logger.info('[Ensuring minimal number of connections]') if not bindinstance.named_conf_exists(): # DNS service may not be configured root_logger.info('DNS is not configured') return changed # make sure number of connections is right minimum_connections = 4 try: connections = bindinstance.named_conf_get_directive('connections') except IOError, e: root_logger.debug('Cannot retrieve connections option from %s: %s', bindinstance.NAMED_CONF, e) return changed 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 is not None and 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') 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.info('DNS is not configured') return changed try: 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: 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 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 named_update_gssapi_configuration(): """ Update GSSAPI configuration in named.conf to a recent API. tkey-gssapi-credential and tkey-domain is replaced with tkey-gssapi-keytab. Details can be found in https://fedorahosted.org/freeipa/ticket/3429. When some change in named.conf is done, this functions returns True """ root_logger.info('[Updating GSSAPI configuration in DNS]') if not bindinstance.named_conf_exists(): # DNS service may not be configured root_logger.info('DNS is not configured') return False if sysupgrade.get_upgrade_state('named.conf', 'gssapi_updated'): root_logger.debug('Skip GSSAPI configuration check') return False try: gssapi_keytab = bindinstance.named_conf_get_directive('tkey-gssapi-keytab', bindinstance.NAMED_SECTION_OPTIONS) except IOError, e: root_logger.error('Cannot retrieve tkey-gssapi-keytab option from %s: %s', bindinstance.NAMED_CONF, e) return False else: if gssapi_keytab: root_logger.debug('GSSAPI configuration already updated') sysupgrade.set_upgrade_state('named.conf', 'gssapi_updated', True) return False try: tkey_credential = bindinstance.named_conf_get_directive('tkey-gssapi-credential', bindinstance.NAMED_SECTION_OPTIONS) tkey_domain = bindinstance.named_conf_get_directive('tkey-domain', bindinstance.NAMED_SECTION_OPTIONS) except IOError, e: root_logger.error('Cannot retrieve tkey-gssapi-credential option from %s: %s', bindinstance.NAMED_CONF, e) return False if not tkey_credential or not tkey_domain: root_logger.error('Either tkey-gssapi-credential or tkey-domain is missing in %s. ' 'Skip update.', bindinstance.NAMED_CONF) return False try: bindinstance.named_conf_set_directive('tkey-gssapi-credential', None, bindinstance.NAMED_SECTION_OPTIONS) bindinstance.named_conf_set_directive('tkey-domain', None, bindinstance.NAMED_SECTION_OPTIONS) bindinstance.named_conf_set_directive('tkey-gssapi-keytab', '/etc/named.keytab', bindinstance.NAMED_SECTION_OPTIONS) except IOError, e: root_logger.error('Cannot update GSSAPI configuration in %s: %s', bindinstance.NAMED_CONF, e) return False else: root_logger.debug('GSSAPI configuration updated') sysupgrade.set_upgrade_state('named.conf', 'gssapi_updated', True) return True def named_update_pid_file(): """ Make sure that named reads the pid file from the right file """ root_logger.info('[Updating pid-file configuration in DNS]') if not bindinstance.named_conf_exists(): # DNS service may not be configured root_logger.info('DNS is not configured') return False if sysupgrade.get_upgrade_state('named.conf', 'pid-file_updated'): root_logger.debug('Skip pid-file configuration check') return False try: pid_file = bindinstance.named_conf_get_directive('pid-file', bindinstance.NAMED_SECTION_OPTIONS) except IOError, e: root_logger.error('Cannot retrieve pid-file option from %s: %s', bindinstance.NAMED_CONF, e) return False else: if pid_file: root_logger.debug('pid-file configuration already updated') sysupgrade.set_upgrade_state('named.conf', 'pid-file_updated', True) return False try: bindinstance.named_conf_set_directive('pid-file', '/run/named/named.pid', bindinstance.NAMED_SECTION_OPTIONS) except IOError, e: root_logger.error('Cannot update pid-file configuration in %s: %s', bindinstance.NAMED_CONF, e) return False else: root_logger.debug('pid-file configuration updated') sysupgrade.set_upgrade_state('named.conf', 'pid-file_updated', True) return True def enable_certificate_renewal(ca): """ If the CA subsystem certificates are not being tracked for renewal then tell certmonger to start tracking them. Returns True when CA needs to be restarted """ root_logger.info('[Enable certificate renewal]') if not ca.is_configured(): root_logger.info('CA is not configured') return False # Using the nickname find the certmonger request_id criteria = (('cert_storage_location', '/etc/httpd/alias', certmonger.NPATH),('cert_nickname', 'ipaCert', None)) request_id = certmonger.get_request_id(criteria) if request_id is not None: root_logger.debug('Certificate renewal already configured') return False if not sysupgrade.get_upgrade_state('dogtag', 'renewal_configured'): if ca.is_master(): ca.configure_renewal() else: ca.configure_certmonger_renewal() ca.configure_clone_renewal() ca.configure_agent_renewal() ca.track_servercert() sysupgrade.set_upgrade_state('dogtag', 'renewal_configured', True) root_logger.debug('CA subsystem certificate renewal enabled') return True return False def certificate_renewal_stop_ca(ca): """ Validate the certmonger configuration on certificates that already have renewal configured. As of certmonger 0.65 it now does locking from the point where it generates the CSR to the end of the post-command. This is to ensure that only one certmonger renewal, and hopefully, one process at a time holds the NSS database open in read/write. """ root_logger.info('[Certificate renewal should stop the CA]') if not ca.is_configured(): root_logger.info('CA is not configured') return False nss_dir = dogtag.configured_constants().ALIAS_DIR # Using the nickname find the certmonger request_id criteria = (('cert_storage_location', nss_dir, certmonger.NPATH),('cert_nickname', 'auditSigningCert cert-pki-ca', None)) id = certmonger.get_request_id(criteria) if id is None: root_logger.error('Unable to find certmonger request ID for auditSigning Cert') return False if sysupgrade.get_upgrade_state('dogtag', 'stop_ca_during_renewal'): return False # State not set, lets see if we are already configured pre_command = certmonger.get_request_value(id, 'pre_certsave_command') if pre_command is not None: if pre_command.strip().endswith('stop_pkicad'): root_logger.info('Already configured to stop CA') return False # Ok, now we need to stop tracking, then we can start tracking them # again with new configuration: cainstance.stop_tracking_certificates(dogtag.configured_constants()) if ca.is_master(): ca.configure_renewal() else: ca.configure_certmonger_renewal() ca.configure_clone_renewal() ca.configure_agent_renewal() ca.track_servercert() sysupgrade.set_upgrade_state('dogtag', 'stop_ca_during_renewal', True) root_logger.debug('CA subsystem certificate renewal configured to stop the CA') return True def copy_crl_file(old_path, new_path=None): """ Copy CRL to new location, update permissions and SELinux context """ if new_path is None: filename = os.path.basename(old_path) new_path = os.path.join(dogtag.configured_constants().CRL_PUBLISH_PATH, filename) root_logger.debug('copy_crl_file: %s -> %s', old_path, new_path) if os.path.islink(old_path): # update symlink to the most most recent CRL file filename = os.path.basename(os.readlink(old_path)) realpath = os.path.join(dogtag.configured_constants().CRL_PUBLISH_PATH, filename) root_logger.debug('copy_crl_file: Create symlink %s -> %s', new_path, realpath) os.symlink(realpath, new_path) else: shutil.copy2(old_path, new_path) pent = pwd.getpwnam(cainstance.PKI_USER) os.chown(new_path, pent.pw_uid, pent.pw_gid) services.restore_context(new_path) def migrate_crl_publish_dir(ca): """ Move CRL publish dir from /var/lib/pki-ca/publish to IPA controlled tree: /var/lib/ipa/pki-ca/publish """ root_logger.info('[Migrate CRL publish directory]') if sysupgrade.get_upgrade_state('dogtag', 'moved_crl_publish_dir'): root_logger.info('CRL tree already moved') return False if not ca.is_configured(): root_logger.info('CA is not configured') return False caconfig = dogtag.configured_constants() try: old_publish_dir = installutils.get_directive(caconfig.CS_CFG_PATH, 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', separator='=') except OSError, e: root_logger.error('Cannot read CA configuration file "%s": %s', caconfig.CS_CFG_PATH, e) return False # Prepare target publish dir (creation, permissions, SELinux context) # Run this every update to ensure proper values publishdir = ca.prepare_crl_publish_dir() if old_publish_dir == caconfig.CRL_PUBLISH_PATH: # publish dir is already updated root_logger.info('Publish directory already set to new location') sysupgrade.set_upgrade_state('dogtag', 'moved_crl_publish_dir', True) return False # Copy all CRLs to new directory root_logger.info('Copy all CRLs to new publish directory') try: crl_files_unsorted = cainstance.get_crl_files(old_publish_dir) except OSError, e: root_logger.error('Cannot move CRL files to new directory: %s', e) else: # Move CRL files at the end of the list to make sure that the actual # CRL files are copied first crl_files = sorted(crl_files_unsorted, key=lambda f: os.path.islink(f)) for f in crl_files: try: copy_crl_file(f) except Exception, e: root_logger.error('Cannot move CRL file to new directory: %s', e) try: installutils.set_directive(caconfig.CS_CFG_PATH, 'ca.publish.publisher.instance.FileBaseCRLPublisher.directory', publishdir, quotes=False, separator='=') except OSError, e: root_logger.error('Cannot update CA configuration file "%s": %s', caconfig.CS_CFG_PATH, e) return False sysupgrade.set_upgrade_state('dogtag', 'moved_crl_publish_dir', True) root_logger.info('CRL publish directory has been migrated, ' 'request pki-ca restart') return True def add_ca_dns_records(): root_logger.info('[Add missing CA DNS records]') if sysupgrade.get_upgrade_state('dns', 'ipa_ca_records'): root_logger.info('IPA CA DNS records already processed') return try: api.Backend.ldap2.connect(autobind=True) except ipalib.errors.PublicError, e: root_logger.error("Cannot connect to LDAP to add DNS records: %s", e) return ret = api.Command['dns_is_enabled']() if not ret['result']: root_logger.info('DNS is not configured') sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True) return bind = bindinstance.BindInstance() bind.convert_ipa_ca_cnames(api.env.domain) # DNS is enabled, so let bindinstance find out if CA is enabled # and let it add the record in that case bind.add_ipa_ca_dns_records(api.env.host, api.env.domain, ca_configured=None) sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True) def find_subject_base(): """ Try to find the current value of certificate subject base. 1) Look in sysupgrade first 2) If no value is found there, look in DS (start DS if necessary) 3) Last resort, look in the certmap.conf itself 4) If all fails, log loudly and return None """ root_logger.debug('Trying to find certificate subject base in sysupgrade') subject_base = sysupgrade.get_upgrade_state('certmap.conf', 'subject_base') if subject_base: root_logger.debug( 'Found certificate subject base in sysupgrade: %s', subject_base ) return subject_base root_logger.debug('Unable to find certificate subject base in sysupgrade') root_logger.debug('Trying to find certificate subject base in DS') ds_is_running = services.knownservices.dirsrv.is_running() if not ds_is_running: try: services.knownservices.dirsrv.start() except ipautil.CalledProcessError as e: root_logger.error('Cannot start DS to find certificate ' 'subject base: %s', e) else: ds_is_running = True if ds_is_running: try: api.Backend.ldap2.connect(autobind=True) except ipalib.errors.PublicError, e: root_logger.error('Cannot connect to DS to find certificate ' 'subject base: %s', e) else: ret = api.Command['config_show']() api.Backend.ldap2.disconnect() subject_base = str(ret['result']['ipacertificatesubjectbase'][0]) root_logger.debug( 'Found certificate subject base in DS: %s', subject_base ) if not subject_base: root_logger.debug('Unable to find certificate subject base in DS') root_logger.debug('Trying to find certificate subject base in ' 'certmap.conf') certmap_dir = dsinstance.config_dirname( dsinstance.realm_to_serverid(api.env.realm) ) try: with open(os.path.join(certmap_dir, 'certmap.conf')) as f: for line in f: if line.startswith('certmap ipaca'): subject_base = line.strip().split(',')[-1] root_logger.debug( 'Found certificate subject base in certmap.conf: ' '%s', subject_base ) except IOError as e: root_logger.error('Cannot open certmap.conf to find certificate ' 'subject base: %s', e.strerror) if subject_base: sysupgrade.set_upgrade_state( 'certmap.conf', 'subject_base', subject_base ) return subject_base root_logger.debug('Unable to find certificate subject base in ' 'certmap.conf') root_logger.error('Unable to determine certificate subject base. ' 'certmap.conf will not be updated.') def uninstall_selfsign(ds, http): root_logger.info('[Removing self-signed CA]') """Replace self-signed CA by a CA-less install""" if api.env.ra_plugin != 'selfsign': root_logger.debug('Self-signed CA is not installed') return root_logger.warning( 'Removing self-signed CA. Certificates will need to managed manually.') p = ConfigParser.SafeConfigParser() p.read('/etc/ipa/default.conf') p.set('global', 'enable_ra', 'False') p.set('global', 'ra_plugin', 'none') with open('/etc/ipa/default.conf', 'w') as f: p.write(f) ds.stop_tracking_certificates() http.stop_tracking_certificates() def fix_schema_file_syntax(ds): """Fix syntax errors in schema files https://fedorahosted.org/freeipa/ticket/3578 """ root_logger.info('[Fix DS schema file syntax]') # This is not handled by normal schema updates, because pre-1.3.2 DS will # ignore (auto-fix) these syntax errors, and 1.3.2 and above will choke on # them before checking dynamic schema updates. if sysupgrade.get_upgrade_state('ds', 'fix_schema_syntax'): root_logger.info('Syntax already fixed') return serverid = dsinstance.realm_to_serverid(api.env.realm) ds.stop(serverid) ds_dir = dsinstance.config_dirname(serverid) # 1. 60ipadns.ldif: Add parenthesis to idnsRecord filename = os.path.join(ds_dir, 'schema', '60ipadns.ldif') result_lines = [] with open(filename) as file: for line in file: line = line.strip('\n') if (line.startswith('objectClasses:') and "NAME 'idnsRecord'" in line and line.count('(') == 2 and line.count(')') == 1): root_logger.debug('Add closing parenthesis in idnsRecord') line += ' )' result_lines.append(line) with open(filename, 'w') as file: file.write('\n'.join(result_lines)) # 2. 65ipasudo.ldif: Remove extra dollar from ipaSudoRule filename = os.path.join(ds_dir, 'schema', '65ipasudo.ldif') result_lines = [] with open(filename) as file: for line in file: line = line.strip('\n') if (line.startswith('objectClasses:') and "NAME 'ipaSudoRule'" in line): root_logger.debug('Remove extra dollar sign in ipaSudoRule') line = line.replace('$$', '$') result_lines.append(line) with open(filename, 'w') as file: file.write('\n'.join(result_lines)) # Done ds.start(serverid) sysupgrade.set_upgrade_state('ds', 'fix_schema_syntax', True) def set_sssd_domain_option(option, value): sssdconfig = SSSDConfig.SSSDConfig() sssdconfig.import_config() domain = sssdconfig.get_domain(str(api.env.domain)) domain.set_option(option, value) sssdconfig.save_domain(domain) sssdconfig.write("/etc/sssd/sssd.conf") def main(): """ Get some basics about the system. If getting those basics fail then this is likely because the machine isn't currently an IPA server so exit gracefully. """ if not os.geteuid()==0: sys.exit("\nYou must be root to run this script.\n") if not installutils.is_ipa_configured(): sys.exit(0) safe_options, options = parse_options() verbose = not options.quiet if options.debug: console_format = '%(levelname)s: %(message)s' else: console_format = '%(message)s' standard_logging_setup('/var/log/ipaupgrade.log', debug=options.debug, verbose=verbose, console_format=console_format, filemode='a') root_logger.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options)) fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') api.bootstrap(context='restart', in_server=True) api.finalize() fqdn = find_hostname() if fqdn is None: # ipa-rewrite.conf doesn't exist, nothing to do sys.exit(0) # Ok, we are an IPA server, do the additional tests check_certs() auto_redirect = find_autoredirect(fqdn) configured_constants = dogtag.configured_constants() sub_dict = dict( REALM=api.env.realm, FQDN=fqdn, AUTOREDIR='' if auto_redirect else '#', CRL_PUBLISH_PATH=configured_constants.CRL_PUBLISH_PATH, DOGTAG_PORT=configured_constants.AJP_PORT, CLONE='#' ) subject_base = find_subject_base() if subject_base: sub_dict['SUBJECT_BASE'] = subject_base ca = cainstance.CAInstance(api.env.realm, certs.NSS_DIR) # migrate CRL publish dir before the location in ipa.conf is updated ca_restart = migrate_crl_publish_dir(ca) if ca.is_configured(): crl = installutils.get_directive(configured_constants.CS_CFG_PATH, 'ca.crl.MasterCRL.enableCRLUpdates', '=') sub_dict['CLONE']='#' if crl.lower() == 'true' else '' certmap_dir = dsinstance.config_dirname( dsinstance.realm_to_serverid(api.env.realm)) upgrade(sub_dict, "/etc/httpd/conf.d/ipa.conf", ipautil.SHARE_DIR + "ipa.conf") upgrade(sub_dict, "/etc/httpd/conf.d/ipa-rewrite.conf", ipautil.SHARE_DIR + "ipa-rewrite.conf") upgrade(sub_dict, "/etc/httpd/conf.d/ipa-pki-proxy.conf", ipautil.SHARE_DIR + "ipa-pki-proxy.conf", add=True) if subject_base: upgrade( sub_dict, os.path.join(certmap_dir, "certmap.conf"), os.path.join(ipautil.SHARE_DIR, "certmap.conf.template") ) upgrade_pki(ca, fstore) update_dbmodules(api.env.realm) uninstall_ipa_kpasswd() http = httpinstance.HTTPInstance(fstore) http.remove_httpd_ccache() http.configure_selinux_for_httpd() http.configure_httpd_ccache() http.change_mod_nss_port_to_http() ds = dsinstance.DsInstance() ds.configure_dirsrv_ccache() fix_schema_file_syntax(ds) uninstall_selfsign(ds, http) simple_service_list = ( (memcacheinstance.MemcacheInstance(), 'MEMCACHE'), (otpdinstance.OtpdInstance(), 'OTPD'), ) for service, ldap_name in simple_service_list: service.ldapi = True try: if not service.is_configured(): # 389-ds needs to be running to create the memcache instance # because we record the new service in cn=masters. ds.start() service.create_instance(ldap_name, fqdn, None, ipautil.realm_to_suffix(api.env.realm), realm=api.env.realm) except ipalib.errors.DuplicateEntry: pass cleanup_kdc(fstore) cleanup_adtrust(fstore) setup_firefox_extension(fstore) add_ca_dns_records() # Any of the following functions returns True iff the named.conf file # has been altered named_conf_changes = ( named_remove_deprecated_options(), named_set_minimum_connections(), named_enable_serial_autoincrement(), named_update_gssapi_configuration(), named_update_pid_file(), ) if any(named_conf_changes): # configuration has changed, restart the name server root_logger.info('Changes to named.conf have been made, restart named') bind = bindinstance.BindInstance(fstore) try: bind.restart() except ipautil.CalledProcessError, e: root_logger.error("Failed to restart %s: %s", bind.service_name, e) ca_restart = any([ ca_restart, enable_certificate_renewal(ca), upgrade_ipa_profile(ca, api.env.domain, fqdn), certificate_renewal_stop_ca(ca), ]) if ca_restart: root_logger.info('pki-ca configuration changed, restart pki-ca') try: ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME) except ipautil.CalledProcessError, e: root_logger.error("Failed to restart %s: %s", ca.service_name, e) set_sssd_domain_option('ipa_server_mode', 'True') if __name__ == '__main__': installutils.run_script(main, operation_name='ipa-upgradeconfig') freeipa-3.3.4/install/tools/ipactl0000775000175000017500000004022212271663206016517 0ustar mkosekmkosek#!/usr/bin/python # Authors: Simo Sorce # # Copyright (C) 2008-2010 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 . # import sys import os import json import ldapurl from ipaserver.install import service, installutils from ipaserver.install.dsinstance import config_dirname, realm_to_serverid from ipaserver.install.installutils import is_ipa_configured, ScriptError from ipalib import api, errors from ipapython.ipaldap import IPAdmin from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket from ipapython import services as ipaservices from ipapython import config, dogtag from ipapython.dn import DN class IpactlError(ScriptError): pass def check_IPA_configuration(): if not is_ipa_configured(): # LSB status code 6: program is not configured raise IpactlError("IPA is not configured " + "(see man pages of ipa-server-install for help)", 6) def is_dirsrv_debugging_enabled(): """ Check the 389-ds instance to see if debugging is enabled. If so we suppress that in our output. returns True or False """ debugging = False serverid = realm_to_serverid(api.env.realm) dselist = [config_dirname(serverid)] for dse in dselist: try: fd = open(dse + 'dse.ldif', 'r') except IOError: continue lines = fd.readlines() fd.close() for line in lines: if line.lower().startswith('nsslapd-errorlog-level'): (option, value) = line.split(':') if int(value) > 0: debugging = True return debugging def get_capture_output(service, debug): """ We want to display any output of a start/stop command with the exception of 389-ds when debugging is enabled because it outputs tons and tons of information. """ if service == 'dirsrv' and not debug and is_dirsrv_debugging_enabled(): print ' debugging enabled, suppressing output.' return True else: return False def parse_options(): usage = "%prog start|stop|restart|status\n" parser = config.IPAOptionParser(usage=usage, formatter=config.IPAFormatter()) parser.add_option("-d", "--debug", action="store_true", dest="debug", help="Display debugging information") options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) return safe_options, options, args def emit_err(err): sys.stderr.write(err + '\n') def get_config(dirsrv): base = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), 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: # 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=api.env.startup_timeout) else: (host, port) = lurl.hostport.split(':') wait_for_open_ports(host, [int(port)], timeout=api.env.startup_timeout) con = IPAdmin(ldap_uri=api.env.ldap_uri) con.do_external_bind() res, truncated = con.find_entries( filter=srcfilter, attrs_list=attrs, base_dn=base, scope=con.SCOPE_SUBTREE, time_limit=10) if truncated: raise errors.LimitsExceeded() except errors.NetworkError: # LSB status code 3: program is not running raise IpactlError("Failed to get list of services to probe status:\n" + "Directory Server is stopped", 3) except errors.NotFound: masters_list = [] dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) attrs = ['cn'] try: entries = con.get_entries(dn, con.SCOPE_ONELEVEL, attrs_list=attrs) except Exception, e: masters_list.append("No master found because of error: %s" % str(e)) else: for dn, master_entry in entries: masters_list.append(master_entry.single_value('cn')) masters = "\n".join(masters_list) raise IpactlError("Failed to get list of services to probe status!\n" "Configured hostname '%s' does not match any master server in LDAP:\n%s" % (api.env.host, masters)) except Exception, e: raise IpactlError("Unknown error when retrieving list of services from LDAP: " + str(e)) svc_list = [] for entry in res: name = entry.single_value('cn') for p in entry['ipaConfigString']: if p.startswith('startOrder '): order = p.split()[1] svc_list.append([order, name]) ordered_list = [] for (order, svc) in sorted(svc_list): if svc in service.SERVICE_LIST: ordered_list.append(service.SERVICE_LIST[svc][0]) return ordered_list def get_config_from_file(): svc_list = [] try: f = open(ipaservices.get_svc_list_file(), 'r') svc_list = json.load(f) except Exception, e: raise IpactlError("Unknown error when retrieving list of services from file: " + str(e)) # the framework can start/stop a number of related services we are not # authoritative for, so filter the list through SERVICES_LIST and order it # accordingly too. def_svc_list = [] for svc in service.SERVICE_LIST: s = service.SERVICE_LIST[svc] def_svc_list.append([s[1], s[0]]) ordered_list = [] for (order, svc) in sorted(def_svc_list): if svc in svc_list: ordered_list.append(svc) return ordered_list def ipa_start(options): if os.path.isfile(ipaservices.get_svc_list_file()): emit_err("Existing service file detected!") emit_err("Assuming stale, cleaning and proceeding") # remove file with list of started services # This is ok as systemd will just skip services # that are already running and just return, so that the # stop() method of the base class will simply fill in the # service file again os.unlink(ipaservices.SVC_LIST_FILE) dirsrv = ipaservices.knownservices.dirsrv try: print "Starting Directory Service" dirsrv.start(capture_output=get_capture_output('dirsrv', options.debug)) except Exception, e: raise IpactlError("Failed to start Directory Service: " + str(e)) ldap_list = [] try: svc_list = get_config(dirsrv) except Exception, e: emit_err("Failed to data from service file: " + str(e)) emit_err("Shutting down") try: dirsrv.stop(capture_output=False) except: pass if isinstance(e, IpactlError): # do not display any other error message raise IpactlError(rval=e.rval) else: raise IpactlError() if len(svc_list) == 0: # no service to start return for svc in svc_list: svchandle = ipaservices.service(svc) try: print "Starting %s Service" % svc svchandle.start(capture_output=get_capture_output(svc, options.debug)) except: emit_err("Failed to start %s Service" % svc) emit_err("Shutting down") for svc in svc_list: svc_off = ipaservices.service(svc) try: svc_off.stop(capture_output=False) except: pass try: dirsrv.stop(capture_output=False) except: pass raise IpactlError("Aborting ipactl") def ipa_stop(options): dirsrv = ipaservices.knownservices.dirsrv try: svc_list = get_config_from_file() except Exception, e: # Issue reading the file ? Let's try to get data from LDAP as a # fallback try: dirsrv.start(capture_output=False) svc_list = get_config(dirsrv) except Exception, e: emit_err("Failed to read data from Directory Service: " + str(e)) emit_err("Shutting down") try: # just try to stop it, do not read a result dirsrv.stop() finally: raise IpactlError() try: print "Stopping Directory Service" dirsrv.stop(capture_output=False) except: raise IpactlError("Failed to stop Directory Service") for svc in reversed(svc_list): svchandle = ipaservices.service(svc) try: print "Stopping %s Service" % svc svchandle.stop(capture_output=False) except: emit_err("Failed to stop %s Service" % svc) # remove file with list of started services try: os.unlink(ipaservices.SVC_LIST_FILE) except OSError: pass def ipa_restart(options): dirsrv = ipaservices.knownservices.dirsrv new_svc_list = [] try: new_svc_list = get_config(dirsrv) except Exception, e: emit_err("Failed to read data from Directory Service: " + str(e)) emit_err("Shutting down") try: dirsrv.stop(capture_output=False) except: pass if isinstance(e, IpactlError): # do not display any other error message raise IpactlError(rval=e.rval) else: raise IpactlError() old_svc_list = [] try: old_svc_list = get_config_from_file() except Exception, e: emit_err("Failed to get service list from file: " + str(e)) # fallback to what's in LDAP old_svc_list = new_svc_list # match service to start/stop svc_list = [] for s in new_svc_list: if s in old_svc_list: svc_list.append(s) #remove commons for s in svc_list: if s in old_svc_list: old_svc_list.remove(s) for s in svc_list: if s in new_svc_list: new_svc_list.remove(s) if len(old_svc_list) != 0: # we need to definitely stop some services for svc in reversed(old_svc_list): svchandle = ipaservices.service(svc) try: print "Stopping %s Service" % svc svchandle.stop(capture_output=False) except: emit_err("Failed to stop %s Service" % svc) try: print "Restarting Directory Service" dirsrv.restart(capture_output=get_capture_output('dirsrv', options.debug)) except Exception, e: emit_err("Failed to restart Directory Service: " + str(e)) emit_err("Shutting down") for svc in reversed(svc_list): svc_off = ipaservices.service(svc) try: svc_off.stop(capture_output=False) except: pass try: dirsrv.stop(capture_output=False) except: pass raise IpactlError("Aborting ipactl") if len(svc_list) != 0: # there are services to restart for svc in svc_list: svchandle = ipaservices.service(svc) try: print "Restarting %s Service" % svc svchandle.restart(capture_output=get_capture_output(svc, options.debug)) except: emit_err("Failed to restart %s Service" % svc) emit_err("Shutting down") for svc in reversed(svc_list): svc_off = ipaservices.service(svc) try: svc_off.stop(capture_output=False) except: pass try: dirsrv.stop(capture_output=False) except: pass raise IpactlError("Aborting ipactl") if len(new_svc_list) != 0: # we still need to start some services for svc in new_svc_list: svchandle = ipaservices.service(svc) try: print "Starting %s Service" % svc svchandle.start(capture_output=get_capture_output(svc, options.debug)) except: emit_err("Failed to start %s Service" % svc) emit_err("Shutting down") for svc in reversed(svc_list): svc_off = ipaservices.service(svc) try: svc_off.stop(capture_output=False) except: pass try: dirsrv.stop(capture_output=False) except: pass raise IpactlError("Aborting ipactl") def ipa_status(options): try: svc_list = get_config_from_file() except IpactlError, e: if os.path.exists(ipaservices.get_svc_list_file()): raise e else: svc_list = [] except Exception, e: raise IpactlError("Failed to get list of services to probe status: " + str(e)) dirsrv = ipaservices.knownservices.dirsrv try: if dirsrv.is_running(): print "Directory Service: RUNNING" else: print "Directory Service: STOPPED" if len(svc_list) == 0: print ("Directory Service must be running in order to " + "obtain status of other services") except: raise IpactlError("Failed to get Directory Service status") if len(svc_list) == 0: return for svc in svc_list: svchandle = ipaservices.service(svc) try: if svchandle.is_running(): print "%s Service: RUNNING" % svc else: print "%s Service: STOPPED" % svc except: emit_err("Failed to get %s Service status" % svc) def main(): if not os.getegid() == 0: # LSB status code 4: user had insufficient privilege raise IpactlError("You must be root to run ipactl.", 4) safe_options, options, args = parse_options() if len(args) != 1: # LSB status code 2: invalid or excess argument(s) raise IpactlError("You must specify one action", 2) elif args[0] != "start" and args[0] != "stop" and args[0] != "restart" and args[0] != "status": raise IpactlError("Unrecognized action [" + args[0] + "]", 2) # check if IPA is configured at all try: check_IPA_configuration() except IpactlError, e: if args[0].lower() == "status": # Different LSB return code for status command: # 4 - program or service status is unknown # This should differentiate uninstalled IPA from status # code 3 - program is not running e.rval = 4 raise e else: raise e api.bootstrap(context='ipactl', debug=options.debug) api.finalize() if '.' not in api.env.host: raise IpactlError("Invalid hostname '%s' in IPA configuration!\n" "The hostname must be fully-qualified" % api.env.host) if args[0].lower() == "start": ipa_start(options) elif args[0].lower() == "stop": ipa_stop(options) elif args[0].lower() == "restart": ipa_restart(options) elif args[0].lower() == "status": ipa_status(options) if __name__ == '__main__': installutils.run_script(main, operation_name='ipactl') freeipa-3.3.4/install/tools/man/0000775000175000017500000000000012271707664016077 5ustar mkosekmkosekfreeipa-3.3.4/install/tools/man/ipa-server-certinstall.10000664000175000017500000000357612271663206022564 0ustar mkosekmkosek.\" A man page for ipa-server-certinstall .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-server-certinstall" "1" "Mar 14 2008" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-server\-certinstall \- Install new SSL server certificates .SH "SYNOPSIS" ipa\-server\-certinstall [\fIOPTION\fR]... PKCS12_FILE .SH "DESCRIPTION" Replace the current SSL Directory and/or Apache server certificate(s) with the certificate in the PKCS#12 file. PKCS#12 is a file format used to safely transport SSL certificates and public/private keypairs. They may be generated and managed using the NSS pk12util command or the OpenSSL pkcs12 command. The service(s) are not automatically restarted. In order to use the newly installed certificate(s) you will need to manually restart the Directory and/or Apache servers. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-dirsrv\fR Install the certificate on the Directory Server .TP \fB\-w\fR, \fB\-\-http\fR Install the certificate in the Apache Web Server .TP \fB\-\-pin\fR=\fIPIN\fR The password of the PKCS#12 file .TP \fB\-\-dirman\-password\fR=\fIDIRMAN_PASSWORD\fR Directory Manager password .SH "EXIT STATUS" 0 if the installation was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-managed-entries.10000664000175000017500000000404312202434255021757 0ustar mkosekmkosek.\" A man page for ipa-managed-entries .\" Copyright (C) 2011 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Jr Aquino .\" .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" ipa\-managed\-entries [options] .SH "DESCRIPTION" Run the command with the \fBenable\fR option to enable the Managed Entry plugin. Run the command with the \fBdisable\fR option to disable the Managed Entry plugin. 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\-p\fR is used. Directory Server will need to be restarted after the Managed Entry plugin has been enabled. .SH "OPTIONS" .TP \fB\-h\fR, \fB\-\-help\fR Show a help message and exit .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-e\fR, \fB\-\-entry\fR DN for the Managed Entry Definition .TP \fB\-l\fR, \fB-\-list\fR List available Managed Entries .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR The Directory Manager password to use for authentication .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 2 if the plugin is already in the required status (enabled or disabled) freeipa-3.3.4/install/tools/man/ipa-restore.10000664000175000017500000001365412271663206020415 0ustar mkosekmkosek.\" A man page for ipa-restore .\" Copyright (C) 2013 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-restore" "1" "Mar 22 2013" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-restore \- Restore an IPA master .SH "SYNOPSIS" ipa\-restore [\fIOPTION\fR]... BACKUP .SH "DESCRIPTION" Only the name of the backup needs to be passed in, not the full path. Backups are stored in a subdirectory in /var/lib/ipa/backup. If a backup is in another location then the full path must be provided. .TP The naming convention for full backups is ipa\-full\-YEAR\-MM\-DD\-HH\-MM\-SS in the GMT time zone. .TP The naming convention for data backups is ipa\-data\-YEAR\-MM\-DD\-HH\-MM\-SS In the GMT time zone. .TP The type of backup is automatically detected. A data restore can be done from either type. .TP \fBWARNING\fR: A full restore will restore files like /etc/passwd, /etc/group, /etc/resolv.conf as well. Any file that IPA may have touched is backed up and restored. .TP An encrypted backup is also automatically detected and the root keyring is used by default. The \-\-keyring option can be used to define the full path to the private and public keys. .TP Within the subdirectory is file, header, that describes the back up including the type, system, date of backup, the version of IPA, the version of the backup and the services on the master. .TP A backup can not be restored on another host. .TP A backup can not be restored in a different version of IPA. .TP Restoring from backup sets the server as the new data master. All other masters will need to be re\-initialized. The first step in restoring a backup is to disable replication on all the other masters. This is to prevent the changelog from overwriting the data in the backup. .TP Use the ipa\-replica\-manage and ipa\-csreplica\-manage commands to re\-initialize other masters. ipa\-csreplica\-manage only needs to be executed on masters that have a CA installed. .SH "REPLICATION" The restoration on other masters needs to be done carefully, to match the replication topology, working outward from the restored master. For example, if your topology is A <\-> B <\-> C and you restored master A you would restore B first, then C. .TP Replication is disabled on all masters that are available when a restoration is done. If a master is down at the time of the restoration you will need to proceed with extreme caution. If this master is brought back up after the restoration is complete it may send out replication updates that apply the very changes you were trying to back out. The only safe answer is to reinstall the master. This would involve deleting all replication agreements to the master. This could have a cascading effect if the master is a hub to other masters. They would need to be connected to other masters before removing the downed master. .TP If the restore point is from a period prior to a replication agreement then the master will need to be re\-installed. For example, you have masters A and B and you create a backup. You then add master C from B. Then you restore from the backup. The restored data is going to lose the replication agreement to C. The master on C will have a replication agreement pointing to B, but B won't have the reverse agreement. Master C won't be registered as an IPA master. It may be possible to manually correct these and re\-connect C to B but it would be very prone to error. .TP If re\-initializing on an IPA master version prior to 3.2 then the replication agreements will need to be manually re\-enabled otherwise the re\-initialization will never complete. To manually enable an agreement use ldapsearch to find the agreement name in cn=mapping tree,cn=config. The value of nsds5ReplicaEnabled needs to be on, and enabled on both sides. Remember that CA replication is done through a separate agreement and will need to be updated separately. .TP If you have older masters you should consider re\-creating them rather than trying to re\-initialize them. .SH "OPTIONS" .TP \fB\-p\fR, \fB\-\-password\fR=\fIPASSWORD\fR The Directory Manager password. \fB\-\-data\fR Restore the data only. The default is to restore everything in the backup. .TP \fB\-\-gpg\-keyring\fR=\fIGPG_KEYRING\fR The full path to a GPG keyring. The keyring consists of two files, a public and a private key (.sec and .pub respectively). Specify the path without an extension. .TP \fB\-\-no\-logs\fR Exclude the IPA service log files in the backup (if they were backed up). Applicable only with a full backup. .TP \fB\-\-online\fR Perform the restore on\-line. Requires the \-\-data option. .TP \fB\-\-instance\fR=\fIINSTANCE\fR The backend to restore within an instance or instances. .TP Restore only the databases in this 389\-ds instance. The default is to restore all found (at most this is the IPA REALM instance and the PKI\-IPA instance). .TP \fB\-\-backend\fR=\fIBACKEND\fR \fB\-\-v\fR, \fB\-\-verbose\fR Print debugging information .TP \fB\-d\fR, \fB\-\-debug\fR Alias for \-\-verbose .TP \fB\-q\fR, \fB\-\-quiet\fR Output only errors .TP \fB\-\-log\-file\fR=\fIFILE\fR Log to the given file .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred .SH "FILES" .PP \fI/var/lib/ipa/backup\fR .RS 4 The default directory for storing backup files. .RE .PP \fl/var/log/iparestore.log\fR .RS 4 The log file for restoration .PP .SH "SEE ALSO" ipa\-backup(1). freeipa-3.3.4/install/tools/man/ipa-nis-manage.10000664000175000017500000000323412202434255020734 0ustar mkosekmkosek.\" A man page for ipa-nis-manage .\" Copyright (C) 2009 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-nis-manage" "1" "May 6 2009" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-nis\-manage \- Enables or disables the NIS listener plugin .SH "SYNOPSIS" ipa\-nis\-manage [options] .SH "DESCRIPTION" Run the command with the \fBenable\fR option to enable the NIS plugin. Run the command with the \fBdisable\fR option to disable the compat plugin. In both cases the user will be prompted to provide the Directory Manager's password unless option \fB\-y\fR is used. Directory Server will need to be restarted after the NIS listener plugin has been enabled. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-y\fR \fIfile\fR File containing the Directory Manager password .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 2 if the plugin is already in the required status (enabled or disabled) freeipa-3.3.4/install/tools/man/ipa-upgradeconfig.80000664000175000017500000000337012202434255021542 0ustar mkosekmkosek.\" A man page for ipa-upgradeconfig .\" Copyright (C) 2010 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-upgradeconfig" "8" "Jun 18 2012" "freeipa" "" .SH "NAME" ipa\-upgradeconfig \- Upgrade the IPA Apache configuration .SH "SYNOPSIS" ipa\-upgradeconfig .SH "DESCRIPTION" A tool to update the IPA Apache configuration during an upgrade. It examines the VERSION value in the head of \fI/etc/httpd/conf.d/ipa.conf\fR and \fI/etc/httpd/conf.d/ipa\-rewrite.conf\fR and compares this with the templates. If an update is needed then new files are written. It also will convert a CA configured to be accessible via ports 9443, 9444, 9445 and 9446 to be proxied by the IPA web server on ports 80 and 443. This is not intended to be run by an end\-user. It is executed when the IPA rpms are upgraded. This must be run as the root user. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-q\fR, \fB\-\-quiet\fR Output only errors .SH "EXIT STATUS" 0 if the update was successful or there was nothing to do 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-dns-install.10000664000175000017500000000446412271663206021161 0ustar mkosekmkosek.\" A man page for ipa-dns-install .\" Copyright (C) 2010 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .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" ipa\-dns\-install [\fIOPTION\fR]... .SH "DESCRIPTION" Adds DNS as an IPA\-managed service. 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 \fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR The IP address of the IPA server. If not provided then this is determined based on the hostname of the server. .TP \fB\-\-forwarder\fR=\fIFORWARDER\fR A forwarder is a DNS server where queries for a specific non\-resolvable address can be directed. To define multiple forwarders use multiple instances of \fB\-\-forwarder\fR .TP \fB\-\-no\-forwarders\fR Do not add any DNS forwarders, send non\-resolvable addresses to the DNS root servers. .TP \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR The reverse DNS zone to use .TP \fB\-\-no\-reverse\fR Do not create new reverse DNS zone. If used on a replica and a reverse DNS zone already exists for the subnet, it will be used. .TP \fB\-\-zonemgr\fR The e\-mail address of the DNS zone manager. Defaults to hostmaster@DOMAIN .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .SH "EXIT STATUS" 0 if the installation was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/Makefile.am0000664000175000017500000000152612271663206020130 0ustar mkosekmkosek# This file will be processed with automake-1.7 to create Makefile.in AUTOMAKE_OPTIONS = 1.7 NULL= man1_MANS = \ ipa-replica-conncheck.1 \ ipa-replica-install.1 \ ipa-replica-manage.1 \ ipa-csreplica-manage.1 \ ipa-replica-prepare.1 \ ipa-server-certinstall.1 \ ipa-server-install.1 \ ipa-dns-install.1 \ ipa-adtrust-install.1 \ ipa-ca-install.1 \ ipa-ldap-updater.1 \ ipa-compat-manage.1 \ ipa-nis-manage.1 \ ipa-managed-entries.1 \ ipa-backup.1 \ ipa-restore.1 \ ipa-advise.1 \ $(NULL) man8_MANS = \ ipactl.8 \ ipa-upgradeconfig.8 \ $(NULL) install-data-hook: @for i in $(man1_MANS) ; do gzip -f $(DESTDIR)$(man1dir)/$$i ; done @for i in $(man8_MANS) ; do gzip -f $(DESTDIR)$(man8dir)/$$i ; done MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) freeipa-3.3.4/install/tools/man/ipa-backup.10000664000175000017500000000522712271663206020174 0ustar mkosekmkosek.\" A man page for ipa-backup .\" Copyright (C) 2013 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-backup" "1" "Mar 22 2013" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-backup \- Back up an IPA master .SH "SYNOPSIS" ipa\-backup [\fIOPTION\fR]... .SH "DESCRIPTION" Two kinds of backups: full and data\-only. .TP The back up is optionally encrypted using either the default root GPG key or a named key. No passphrase is supported. .TP Backups are stored in a subdirectory in /var/lib/ipa/backup. .TP The naming convention for full backups is ipa\-full\-YEAR\-MM\-DD\-HH\-MM\-SS in the GMT time zone. .TP The naming convention for data backups is ipa\-data\-YEAR\-MM\-DD\-HH\-MM\-SS In the GMT time zone. .TP Within the subdirectory is file, header, that describes the back up including the type, system, date of backup, the version of IPA, the version of the backup and the services on the master. .TP A backup can not be restored on another host. .TP A backup can not be restored in a different version of IPA. .SH "OPTIONS" .TP \fB\-\-data\fR Back up data only. The default is to back up all IPA files plus data. .TP \fB\-\-gpg\fR Encrypt the back up file. .TP \fB\-\-gpg\-keyring\fR=\fIGPG_KEYRING\fR The full path to a GPG keyring. The keyring consists of two files, a public and a private key (.sec and .pub respectively). Specify the path without an extension. .TP \fB\-\-logs\fR Include the IPA service log files in the backup. .TP \fB\-\-online\fR Perform the backup on\-line. Requires the \-\-data option. .TP \fB\-\-v\fR, \fB\-\-verbose\fR Print debugging information .TP \fB\-d\fR, \fB\-\-debug\fR Alias for \-\-verbose .TP \fB\-q\fR, \fB\-\-quiet\fR Output only errors .TP \fB\-\-log\-file\fR=\fIFILE\fR Log to the given file .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred .SH "FILES" .PP \fI/var/lib/ipa/backup\fR .RS 4 The default directory for storing backup files. .RE .PP \fl/var/log/ipabackup.log\fR .RS 4 The log file for backups .PP .SH "SEE ALSO" ipa\-restore(1). freeipa-3.3.4/install/tools/man/ipa-replica-prepare.10000664000175000017500000000631312202434255021771 0ustar mkosekmkosek.\" A man page for ipa-replica-prepare .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-replica-prepare" "1" "Mar 14 2008" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-replica\-prepare \- Create an IPA replica file .SH "SYNOPSIS" ipa\-replica\-prepare [\fIOPTION\fR]... hostname .SH "DESCRIPTION" Generates a replica file that may be used with ipa\-replica\-install to create a replica of an IPA server. A replica can only be created on an IPA server installed with ipa\-server\-install (the first server). You must provide the fully\-qualified hostname of the machine you want to install the replica on and a host\-specific replica_file will be created. It is host\-specific because SSL server certificates are generated as part of the process and they are specific to a particular hostname. If IPA manages the DNS for your domain, you should either use the \fB\-\-ip\-address\fR option or add the forward and reverse records manually using IPA plugins. Once the file has been created it will be named replica\-hostname. This file can then be moved across the network to the target machine and a new IPA replica setup by running ipa\-replica\-install replica\-hostname. A replica should only be installed on the same or higher version of IPA on the remote system. .SH "OPTIONS" .TP \fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Directory Server SSL Certificate and Private Key .TP \fB\-\-http_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Apache Server SSL Certificate and Private Key .TP \fB\-\-pkinit_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Kerberos KDC Certificate and Private Key .TP \fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR The password of the Directory Server PKCS#12 file .TP \fB\-\-http_pin\fR=\fIHTTP_PIN\fR The password of the Apache Server PKCS#12 file .TP \fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR The password of the Kerberos KDC PKCS#12 file .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP \fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR IP address of the replica server. If you provide this option, the A and PTR records will be added to the DNS. .TP \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR The reverse DNS zone to use .TP \fB\-\-no\-reverse\fR Do not create reverse DNS zone .TP \fB\-\-ca\fR=\fICA_FILE\fR Location of CA PKCS#12 file, default /root/cacert.p12 .TP \fB\-\-no\-pkinit\fR Disables pkinit setup steps .TP \fB\-\-debug\fR Prints info log messages to the output .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-replica-install.10000664000175000017500000001065712271663206022015 0ustar mkosekmkosek.\" A man page for ipa-replica-install .\" Copyright (C) 2008-2012 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-replica-install" "1" "May 16 2012" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-replica\-install \- Create an IPA replica .SH "SYNOPSIS" ipa\-replica\-install [\fIOPTION\fR]... replica_file .SH "DESCRIPTION" Configures a new IPA server that is a replica of the server that generated it. Once it has been created it is an exact copy of the original IPA server and is an equal master. Changes made to any master are automatically replicated to other masters. The replica_file is created using the ipa\-replica\-prepare utility. If the installation fails you may need to run ipa\-server\-install \-\-uninstall before running ipa\-replica\-install again. The installation will fail if the host you are installing the replica on exists as a host in IPA or an existing replication agreement exists (for example, from a previously failed installation). A replica should only be installed on the same or higher version of IPA on the remote system. .SH "OPTIONS" .SS "BASIC OPTIONS" .TP \fB\-\-setup\-ca\fR Install and configure a CA on this replica. If a CA is not configured then certificate operations will be forwarded to a master with a CA installed. .TP \fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR The IP address of this server. If this address does not match the address the host resolves to and \-\-setup\-dns is not selected the installation will fail. If the server hostname is not resolvable, a record for the hostname and IP_ADDRESS is added to /etc/hosts. .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP \fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR Admin user Kerberos password used for connection check .TP \fB\-\-mkhomedir\fR Create home directories for users on their first login .TP \fB\-N\fR, \fB\-\-no\-ntp\fR Do not configure NTP .TP \fB\-\-no\-ui\-redirect\fR Do not automatically redirect to the Web UI. .TP \fB\-\-ssh\-trust\-dns\fR Configure OpenSSH client to trust DNS SSHFP records. .TP \fB\-\-no\-ssh\fR Do not configure OpenSSH client. .TP \fB\-\-no\-sshd\fR Do not configure OpenSSH server. .TP \fB\-\-skip\-conncheck\fR Skip connection check to remote master .TP \fB\-d\fR, \fB\-\-debug Enable debug logging when more verbose output is needed .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .SS "CERTIFICATE SYSTEM OPTIONS" .TP \fB\-\-no\-pkinit\fR Disables pkinit setup steps .TP \fB\-\-skip\-schema\-check\fR Skip check for updated CA DS schema on the remote master .SS "DNS OPTIONS" .TP \fB\-\-setup\-dns\fR Generate a DNS zone if it does not exist already and configure the DNS server. This option requires that you either specify at least one DNS forwarder through the \fB\-\-forwarder\fR option or use the \fB\-\-no\-forwarders\fR option. .TP \fB\-\-forwarder\fR=\fIIP_ADDRESS\fR Add a DNS forwarder to the DNS configuration. You can use this option multiple times to specify more forwarders, but at least one must be provided, unless the \fB\-\-no\-forwarders\fR option is specified. .TP \fB\-\-no\-forwarders\fR Do not add any DNS forwarders. Root DNS servers will be used instead. .TP \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR The reverse DNS zone to use .TP \fB\-\-no\-reverse\fR Do not create new reverse DNS zone. If a reverse DNS zone already exists for the subnet, it will be used. .TP \fB\-\-no\-host\-dns\fR Do not use DNS for hostname lookup during installation .TP \fB\-\-no\-dns\-sshfp\fR Do not automatically create DNS SSHFP records. .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 3 if the host exists in the IPA server or a replication agreement to the remote master already exists freeipa-3.3.4/install/tools/man/ipa-adtrust-install.10000664000175000017500000001506212271663206022057 0ustar mkosekmkosek.\" A man page for ipa-adtrust-install .\" Copyright (C) 2011 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Sumit Bose .\" .TH "ipa-adtrust-install" "1" "Aug 23 2011" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-adtrust\-install \- Prepare an IPA server to be able to establish trust relationships with AD domains .SH "SYNOPSIS" ipa\-adtrust\-install [\fIOPTION\fR]... .SH "DESCRIPTION" Adds all necessary objects and configuration to allow an IPA server to create a trust to an Active Directory domain. This requires that the IPA server is already installed and configured. Please note you will not be able to estabilish an trust to an Active Directory domain unless the realm name of the IPA server matches its domain name. ipa\-adtrust\-install can be run multiple times to reinstall deleted objects or broken configuration files. E.g. a fresh samba configuration (smb.conf file and registry based configuration can be created. Other items like e.g. the configuration of the local range cannot be changed by running ipa\-adtrust\-install a second time because with changes here other objects might be affected as well. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR The IP address of the IPA server. If not provided then this is determined based on the hostname of the server. .TP \fB\-\-netbios\-name\fR=\fINETBIOS_NAME\fR The NetBIOS name for the IPA domain. If not provided then this is determined based on the leading component of the DNS domain name. Running ipa\-adtrust\-install for a second time with a different NetBIOS name will change the name. Please note that changing the NetBIOS name might break existing trust relationships to other domains. .TP \fB\-\-no\-msdcs\fR Do not create DNS service records for Windows in managed DNS server. Since those DNS service records are the only way to discover domain controllers of other domains they must be added manually to a different DNS server to allow trust realationships work properly. All needed service records are listed when ipa\-adtrust\-install finishes and either \-\-no\-msdcs was given or no IPA DNS service is configured. Typically service records for the following service names are needed for the IPA domain which should point to all IPA servers: .IP \(bu _ldap._tcp .IP \(bu _kerberos._tcp .IP \(bu _kerberos._udp .IP \(bu _ldap._tcp.dc._msdcs .IP \(bu _kerberos._tcp.dc._msdcs .IP \(bu _kerberos._udp.dc._msdcs .IP \(bu _ldap._tcp.Default-First-Site-Name._sites.dc._msdcs .IP \(bu _kerberos._tcp.Default-First-Site-Name._sites.dc._msdcs .IP \(bu _kerberos._udp.Default-First-Site-Name._sites.dc._msdcs .TP \fB\-\-add\-sids\fR Add SIDs to existing users and groups as a final step of the ipa\-adtrust\-install run. If there a many existing users and groups and a couple of replicas in the environment this operation might lead to a high replication traffic and a performance degradation of all IPA servers in the environment. To avoid this the SID generation can be run after ipa\-adtrust\-install is run and scheduled independently. To start this task you have to load an edited version of ipa-sidgen-task-run.ldif with the ldapmodify command info the directory server. .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .TP \fB\-U\fR, \fB\-\-rid-base\fR=\fIRID_BASE\fR First RID value of the local domain. The first Posix ID of the local domain will be assigned to this RID, the second to RID+1 etc. See the online help of the idrange CLI for details. .TP \fB\-U\fR, \fB\-\-secondary-rid-base\fR=\fISECONDARY_RID_BASE\fR Start value of the secondary RID range, which is only used in the case a user and a group share numerically the same Posix ID. See the online help of the idrange CLI for details. .TP \fB\-A\fR, \fB\-\-admin\-name\fR=\fIADMIN_NAME\fR The name of the user with administrative privileges for this IPA server. Defaults to 'admin'. .TP \fB\-a\fR, \fB\-\-admin\-password\fR=\fIpassword\fR The password of the user with administrative privileges for this IPA server. Will be asked interactively if \fB\-U\fR is not specified. .TP The credentials of the admin user will be used to obtain Kerberos ticket before configuring cross-realm trusts support and afterwards, to ensure that the ticket contains MS-PAC information required to actually add a trust with Active Directory domain via 'ipa trust-add --type=ad' command. .TP \fB\-\-enable\-compat\fR Enables support for trusted domains users for old clients through Schema Compatibility plugin. SSSD supports trusted domains natively starting with version 1.9. For platforms that lack SSSD or run older SSSD version one needs to use this option. When enabled, slapi\-nis package needs to be installed and schema\-compat\-plugin will be configured to provide lookup of users and groups from trusted domains via SSSD on IPA server. These users and groups will be available under \fBcn=users,cn=compat,$SUFFIX\fR and \fBcn=groups,cn=compat,$SUFFIX\fR trees. SSSD will normalize names of users and groups to lower case. .IP In addition to providing these users and groups through the compat tree, this option enables authentication over LDAP for trusted domain users with DN under compat tree, i.e. using bind DN \fBuid=administrator@ad.domain,cn=users,cn=compat,$SUFFIX\fR. .IP LDAP authentication performed by the compat tree is done via PAM '\fBsystem\-auth\fR' service. This service exists by default on Linux systems and is provided by pam package as /etc/pam.d/system\-auth. If your IPA install does not have default HBAC rule 'allow_all' enabled, then make sure to define in IPA special service called '\fBsystem\-auth\fR' and create an HBAC rule to allow access to anyone to this rule on IPA masters. .IP As '\fBsystem\-auth\fR' PAM service is not used directly by any other application, it is safe to use it for trusted domain users via compatibility path. .TP .SH "EXIT STATUS" 0 if the installation was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-server-install.10000664000175000017500000001401712271663206021676 0ustar mkosekmkosek.\" A man page for ipa-server-install .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-server-install" "1" "Jun 28 2012" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-server\-install \- Configure an IPA server .SH "SYNOPSIS" ipa\-server\-install [\fIOPTION\fR]... .SH "DESCRIPTION" Configures the services needed by an IPA server. This includes setting up a Kerberos Key Distribution Center (KDC) and a Kadmin daemon with an LDAP back\-end, configuring Apache, configuring NTP and optionally configuring and starting an LDAP-backed DNS server. By default a dogtag\-based CA will be configured to issue server certificates. .SH "OPTIONS" .SS "BASIC OPTIONS" .TP \fB\-r\fR \fIREALM_NAME\fR, \fB\-\-realm\fR=\fIREALM_NAME\fR The Kerberos realm name for the IPA server. You will not be able to estabilish trust with Active Directory unless the realm name is uppercased domain name. .TP \fB\-n\fR \fIDOMAIN_NAME\fR, \fB\-\-domain\fR=\fIDOMAIN_NAME\fR Your DNS domain name .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\-P\fR \fIMASTER_PASSWORD\fR, \fB\-\-master\-password\fR=\fIMASTER_PASSWORD\fR The kerberos master password (normally autogenerated) .TP \fB\-a\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR The password for the IPA admin user .TP \fB\-\-mkhomedir\fR Create home directories for users on their first login .TP \fB\-\-hostname\fR=\fIHOST_NAME\fR The fully\-qualified DNS name of this server. If the hostname does not match system hostname, the system hostname will be updated accordingly to prevent service failures. .TP \fB\-\-ip\-address\fR=\fIIP_ADDRESS\fR The IP address of this server. If this address does not match the address the host resolves to and --setup-dns is not selected the installation will fail. If the server hostname is not resolvable, a record for the hostname and IP_ADDRESS is added to /etc/hosts. .TP \fB\-N\fR, \fB\-\-no\-ntp\fR Do not configure NTP .TP \fB\-\-idstart\fR=\fIIDSTART\fR The starting user and group id number (default random) .TP \fB\-\-idmax\fR=\fIIDMAX\fR The maximum user and group id number (default: idstart+199999). If set to zero, the default value will be used. .TP \fB\-\-no_hbac_allow\fR Don't install allow_all HBAC rule. This rule lets any user from any host access any service on any other host. It is expected that users will remove this rule before moving to production. .TP \fB\-\-no\-ui\-redirect\fR Do not automatically redirect to the Web UI. .TP \fB\-\-ssh\-trust\-dns\fR Configure OpenSSH client to trust DNS SSHFP records. .TP \fB\-\-no\-ssh\fR Do not configure OpenSSH client. .TP \fB\-\-no\-sshd\fR Do not configure OpenSSH server. .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .SS "CERTIFICATE SYSTEM OPTIONS" .TP \fB\-\-external\-ca\fR Generate a CSR to be signed by an external CA .TP \fB\-\-external_cert_file\fR=\fIFILE\fR PEM file containing a certificate signed by the external CA. Must be given with \-\-external_ca_file. .TP \fB\-\-external_ca_file\fR=\fIFILE\fR PEM file containing the external CA chain .TP \fB\-\-no\-pkinit\fR Disables pkinit setup steps .TP \fB\-\-dirsrv_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Directory Server SSL Certificate .TP \fB\-\-http_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Apache Server SSL Certificate .TP \fB\-\-pkinit_pkcs12\fR=\fIFILE\fR PKCS#12 file containing the Kerberos KDC SSL certificate .TP \fB\-\-dirsrv_pin\fR=\fIDIRSRV_PIN\fR The password of the Directory Server PKCS#12 file .TP \fB\-\-http_pin\fR=\fIHTTP_PIN\fR The password of the Apache Server PKCS#12 file .TP \fB\-\-pkinit_pin\fR=\fIPKINIT_PIN\fR The password of the Kerberos KDC PKCS#12 file .TP \fB\-\-subject\fR=\fISUBJECT\fR The certificate subject base (default O=REALM.NAME) .SS "DNS OPTIONS" .TP \fB\-\-setup\-dns\fR Generate a DNS zone if it does not exist already and configure the DNS server. This option requires that you either specify at least one DNS forwarder through the \fB\-\-forwarder\fR option or use the \fB\-\-no\-forwarders\fR option. Note that you can set up a DNS at any time after the initial IPA server install by running .B ipa-dns-install (see .BR ipa-dns-install (1)). .TP \fB\-\-forwarder\fR=\fIIP_ADDRESS\fR Add a DNS forwarder to the DNS configuration. You can use this option multiple times to specify more forwarders, but at least one must be provided, unless the \fB\-\-no\-forwarders\fR option is specified. .TP \fB\-\-no\-forwarders\fR Do not add any DNS forwarders. Root DNS servers will be used instead. .TP \fB\-\-reverse\-zone\fR=\fIREVERSE_ZONE\fR The reverse DNS zone to use .TP \fB\-\-no\-reverse\fR Do not create reverse DNS zone .TP \fB\-\-zonemgr\fR The e\-mail address of the DNS zone manager. Defaults to hostmaster@DOMAIN .TP \fB\-\-no\-host\-dns\fR Do not use DNS for hostname lookup during installation .TP \fB\-\-no\-dns\-sshfp\fR Do not automatically create DNS SSHFP records. .SS "UNINSTALL OPTIONS" .TP \fB\-\-uninstall\fR Uninstall an existing IPA installation .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended uninstallation that will never prompt for user input .SH "EXIT STATUS" 0 if the (un)installation was successful 1 if an error occurred .SH "SEE ALSO" .BR ipa-dns-install (1) freeipa-3.3.4/install/tools/man/ipa-compat-manage.10000664000175000017500000000343012202434255021424 0ustar mkosekmkosek.\" A man page for ipa-compat-manage .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Simo Sorce .\" .TH "ipa-compat-manage" "1" "Dec 2 2008" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-compat\-manage \- Enables or disables the schema compatibility plugin .SH "SYNOPSIS" ipa\-compat\-manage [options] .SH "DESCRIPTION" Run the command with the \fBenable\fR option to enable the compat plugin. Run the command with the \fBdisable\fR option to disable the compat plugin. Run the command with the \fBstatus\fR to determine the current status of the compat plugin. In all cases the user will be prompted to provide the Directory Manager's password unless option \fB\-y\fR is used. Directory Server will need to be restarted after the schema compatibility plugin has been enabled. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-y\fR \fIfile\fR File containing the Directory Manager password .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 2 if the plugin is already in the required status (enabled or disabled) freeipa-3.3.4/install/tools/man/ipa-csreplica-manage.10000664000175000017500000000736312202434255022117 0ustar mkosekmkosek.\" A man page for ipa-csreplica-manage .\" Copyright (C) 2011 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-csreplica-manage" "1" "Jul 14 2011" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-csreplica\-manage \- Manage an IPA CS replica .SH "SYNOPSIS" ipa\-csreplica\-manage [\fIOPTION\fR]... [connect|disconnect|del|list|re\-initialize|force\-sync] .SH "DESCRIPTION" Manages the CA replication agreements of an IPA server. .TP \fBconnect\fR [SERVER_A] \- Adds a new replication agreement between SERVER_A/localhost and SERVER_B .TP \fBdisconnect\fR [SERVER_A] \- Removes a replication agreement between SERVER_A/localhost and SERVER_B .TP \fBdel\fR \- Removes all replication agreements and data about SERVER .TP \fBlist\fR [SERVER] \- Lists all the servers or the list of agreements of SERVER .TP \fBre\-initialize\fR \- Forces a full re\-initialization of the IPA CA server retrieving data from the server specified with the \-\-from option .TP \fBforce\-sync\fR \- Immediately flush any data to be replicated from a server specified with the \-\-from option .TP The connect and disconnect options are used to manage the replication topology. When a replica is created it is only connected with the master that created it. The connect option may be used to connect it to other existing replicas. .TP The disconnect option cannot be used to remove the last link of a replica. To remove a replica from the topology use the del option. .TP If a replica is deleted and then re\-added within a short time-frame then the 389\-ds instance on the master that created it should be restarted before re\-installing the replica. The master will have the old service principals cached which will cause replication to fail. .SH "OPTIONS" .TP \fB\-H\fR \fIHOST\fR, \fB\-\-host\fR=\fIHOST\fR The IPA server to manage. The default is the machine on which the command is run Not honoured by the re\-initialize command. .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR The Directory Manager password to use for authentication .TP \fB\-v\fR, \fB\-\-verbose\fR Provide additional information .TP \fB\-f\fR, \fB\-\-force\fR Ignore some types of errors .TP \fB\-\-from\fR=\fISERVER\fR The server to pull the data from, used by the re\-initialize and force\-sync commands. .SH "EXAMPLES" .TP List a server's replication agreements. # ipa\-csreplica\-manage list srv1.example.com srv2.example.com srv3.example.com .TP Re\-initialize a replica: # ipa\-csreplica\-manage re\-initialize \-\-from srv2.example.com This will re\-initialize the data on the server where you execute the command, retrieving the data from the srv2.example.com replica .TP Add a new replication agreement: # ipa\-csreplica\-manage connect srv2.example.com srv4.example.com .TP Remove an existing replication agreement: # ipa\-csreplica\-manage disconnect srv1.example.com srv3.example.com .TP Completely remove a replica: # ipa\-csreplica\-manage del srv4.example.com .TP Using connect/disconnect you can manage the replication topology. .SH "EXIT STATUS" 0 if the command was successful .TP 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-advise.10000664000175000017500000000264212271663206020200 0ustar mkosekmkosek.\" A man page for ipa-advise .\" Copyright (C) 2013 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Tomas Babej .\" .TH "ipa-advise" "1" "Jun 10 2013" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-advise \- Provide configurations advice for various use cases. .SH "SYNOPSIS" ipa\-advise ADVICE .SH "DESCRIPTION" Provides customized advice for various IPA configuration issues. .TP For the list of possible ADVICEs available, run the ipa\-advise with no arguments. .SH "OPTIONS" .TP \fB\-\-v\fR, \fB\-\-verbose\fR Print debugging information .TP \fB\-d\fR, \fB\-\-debug\fR Alias for \-\-verbose .TP \fB\-q\fR, \fB\-\-quiet\fR Output only errors .TP \fB\-\-log\-file\fR=\fIFILE\fR Log to the given file .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurredfreeipa-3.3.4/install/tools/man/ipactl.80000664000175000017500000000343212202434255017431 0ustar mkosekmkosek.\" A man page for ipactl .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipactl" "8" "Mar 14 2008" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipactl \- IPA Server Control Interface .SH "SYNOPSIS" ipactl \fIcommand\fR .SH "DESCRIPTION" A tool to help an administer control an IPA environment. IPA glues several discrete services together to work in concert and the order that these services are started and stopped is important. ipactl ensures that they are started and stopped in the correct order. IPA stores the available masters and the services configured on each one. The first thing ipactl does is start (if it is not already running) the IPA 389\-ds instance to query what services it controls. The hostname used in the query needs to match the hostname of the value stored in LDAP. This can be controlled with the host option in \fI/etc/ipa/default.conf\fR. This should be a fully\-qualified hostname. .SH "OPTIONS" .TP start Start all of the services that make up IPA .TP stop Stop all of the services that make up IPA .TP restart Stop then start all of the services that make up IPA freeipa-3.3.4/install/tools/man/ipa-replica-manage.10000664000175000017500000002772012271663206021576 0ustar mkosekmkosek.\" A man page for ipa-replica-manage .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-replica-manage" "1" "Mar 1 2013" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-replica\-manage \- Manage an IPA replica .SH "SYNOPSIS" ipa\-replica\-manage [\fIOPTION\fR]... [COMMAND] .SH "DESCRIPTION" Manages the replication agreements of an IPA server. The available commands are: .TP \fBconnect\fR [SERVER_A] \- Adds a new replication agreement between SERVER_A/localhost and SERVER_B .TP \fBdisconnect\fR [SERVER_A] \- Removes a replication agreement between SERVER_A/localhost and SERVER_B .TP \fBdel\fR \- Removes all replication agreements and data about SERVER .TP \fBlist\fR [SERVER] \- Lists all the servers or the list of agreements of SERVER .TP \fBre\-initialize\fR \- Forces a full re\-initialization of the IPA server retrieving data from the server specified with the \-\-from option .TP \fBforce\-sync\fR \- Immediately flush any data to be replicated from a server specified with the \-\-from option .TP \fBlist\-ruv\fR \- List the replication IDs on this server. .TP \fBclean\-ruv\fR [REPLICATION_ID] \- Run the CLEANALLRUV task to remove a replication ID. .TP \fBabort\-clean\-ruv\fR [REPLICATION_ID] \- Abort a running CLEANALLRUV task. .TP \fBlist\-clean\-ruv\fR \- List all running CLEANALLRUV and abort CLEANALLRUV tasks. .TP \fBdnarange\-show [SERVER]\fR \- List the DNA ranges .TP \fBdnarange\-set SERVER START\-END\fR \- Set the DNA range on a master .TP \fBdnanextrange\-show [SERVER]\fR \- List the next DNA ranges .TP \fBdnanextrange\-set SERVER START\-END\fR \- Set the DNA next range on a master .TP The connect and disconnect options are used to manage the replication topology. When a replica is created it is only connected with the master that created it. The connect option may be used to connect it to other existing replicas. .TP The disconnect option cannot be used to remove the last link of a replica. To remove a replica from the topology use the del option. .TP If a replica is deleted and then re\-added within a short time\-frame then the 389\-ds instance on the master that created it should be restarted before re\-installing the replica. The master will have the old service principals cached which will cause replication to fail. .TP Each IPA master server has a unique replication ID. This ID is used by 389\-ds\-base when storing information about replication status. The output consists of the masters and their respective replication ID. See \fBclean\-ruv\fR .TP When a master is removed, all other masters need to remove its replication ID from the list of masters. Normally this occurs automatically when a master is deleted with ipa\-replica\-manage. If one or more masters was down or unreachable when ipa\-replica\-manage was executed then this replica ID may still exist. The clean\-ruv command may be used to clean up an unused replication ID. .TP \fBNOTE\fR: clean\-ruv is \fBVERY DANGEROUS\fR. Execution against the wrong replication ID can result in inconsistent data on that master. The master should be re\-initialized from another if this happens. .TP The replication topology is examined when a master is deleted and will attempt to prevent a master from being orphaned. For example, if your topology is A <\-> B <\-> C and you attempt to delete master B it will fail because that would leave masters and A and C orphaned. .TP The list of masters is stored in cn=masters,cn=ipa,cn=etc,dc=example,dc=com. This should be cleaned up automatically when a master is deleted. If it occurs that you have deleted the master and all the agreements but these entries still exist then you will not be able to re\-install IPA on it, the installation will fail with: .TP An IPA master host cannot be deleted or disabled using standard commands (host\-del, for example). .TP An orphaned master may be cleaned up using the del directive with the \-\-cleanup option. This will remove the entries from cn=masters,cn=ipa,cn=etc that otherwise prevent host\-del from working, its dna profile, s4u2proxy configuration, service principals and remove it from the default DUA profile defaultServerList. .SH "OPTIONS" .TP \fB\-H\fR \fIHOST\fR, \fB\-\-host\fR=\fIHOST\fR The IPA server to manage. The default is the machine on which the command is run Not honoured by the re\-initialize command. .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR The Directory Manager password to use for authentication .TP \fB\-v\fR, \fB\-\-verbose\fR Provide additional information .TP \fB\-f\fR, \fB\-\-force\fR Ignore some types of errors, don't prompt when deleting a master .TP \fB\-c\fR, \fB\-\-no\-lookup\fR Do not perform DNS lookup checks. .TP \fB\-c\fR, \fB\-\-cleanup\fR When deleting a master with the \-\-force flag, remove leftover references to an already deleted master. .TP \fB\-\-binddn\fR=\fIADMIN_DN\fR Bind DN to use with remote server (default is cn=Directory Manager) \- Be careful to quote this value on the command line .TP \fB\-\-bindpw\fR=\fIADMIN_PWD\fR Password for Bind DN to use with remote server (default is the DM_PASSWORD above) .TP \fB\-\-winsync\fR Specifies to create/use a Windows Sync Agreement .TP \fB\-\-cacert\fR=\fI/path/to/cacertfile\fR Full path and filename of CA certificate to use with TLS/SSL to the remote server \- this CA certificate will be installed in the directory server's certificate database .TP \fB\-\-win\-subtree\fR=\fIcn=Users,dc=example,dc=com\fR DN of Windows subtree containing the users you want to sync (default cn=Users, \- this is typically what Windows AD uses as the default value) \- Be careful to quote this value on the command line .TP \fB\-\-passsync\fR=\fIPASSSYNC_PWD\fR Password for the IPA system user used by the Windows PassSync plugin to synchronize passwords. Required when using \-\-winsync. This does not mean you have to use the PassSync service. .TP \fB\-\-from\fR=\fISERVER\fR The server to pull the data from, used by the re\-initialize and force\-sync commands. .SH "RANGES" IPA uses the 389\-ds Distributed Numeric Assignment (DNA) Plugin to allocate POSIX ids for users and groups. A range is created when IPA is installed and half the range is assigned to the first IPA master for the purposes of allocation. .TP New IPA masters do not automatically get a DNA range assignment. A range assignment is done only when a user or POSIX group is added on that master. .TP The DNA plugin also supports an "on\-deck" or next range configuration. When the primary range is exhaused, rather than going to another master to ask for more, it will use its on\-deck range if one is defined. Each master can have only one range and one on\-deck range defined. .TP When a master is removed an attempt is made to save its DNA range(s) onto another master in its on\-deck range. IPA will not attempt to extend or merge ranges. If there are no available on\-deck range slots then this is reported to the user. The range is effectively lost unless it is manually merged into the range of another master. .TP The DNA range and on\-deck (next) values can be managed using the dnarange\-set and dnanextrange\-set commands. The rules for managing these ranges are: \- The range must be completely contained within a local range as defined by the ipa idrange command. \- The range cannot overlap the DNA range or on\-deck range on another IPA master. \- The range cannot overlap the ID range of an AD Trust. \- The primary DNA range cannot be removed. \- An on\-deck range range can be removed by setting it to 0\-0. The assumption is that the range will be manually moved or merged elsewhere. .TP The range and next range of a specific master can be displayed by passing the FQDN of that master to the dnarange\-show or dnanextrange\-show command. .TP Performing range changes as a delegated administrator (e.g. not using the Directory Manager password) requires additional 389\-ds ACIs. These are installed in upgraded masters but not existing ones. The changs are made in cn=config which is not replicated. The result is that DNA ranges cannot be managed on non\-upgraded masters as a delegated administrator. .SH "EXAMPLES" .TP List all masters: # ipa\-replica\-manage list srv1.example.com srv2.example.com srv3.example.com srv4.example.com .TP List a server's replication agreements. # ipa\-replica\-manage list srv1.example.com srv2.example.com srv3.example.com .TP Re\-initialize a replica: # ipa\-replica\-manage re\-initialize \-\-from srv2.example.com This will re\-initialize the data on the server where you execute the command, retrieving the data from the srv2.example.com replica .TP Add a new replication agreement: # ipa\-replica\-manage connect srv2.example.com srv4.example.com .TP Remove an existing replication agreement: # ipa\-replica\-manage disconnect srv1.example.com srv3.example.com .TP Completely remove a replica: # ipa\-replica\-manage del srv4.example.com .TP Using connect/disconnect you can manage the replication topology. .TP List the replication IDs in use: # ipa\-replica\-manage list\-ruv srv1.example.com:389: 7 srv2.example.com:389: 4 .TP Remove references to an orphaned and deleted master: # ipa\-replica\-manage del \-\-force \-\-cleanup master.example.com .SH "WINSYNC" Creating a Windows AD Synchronization agreement is similar to creating an IPA replication agreement, there are just a couple of extra steps. A special user entry is created for the PassSync service. The DN of this entry is uid=passsync,cn=sysaccounts,cn=etc,. You are not required to use PassSync to use a Windows synchronization agreement but setting a password for the user is required. The following examples use the AD administrator account as the synchronization user. This is not mandatory but the user must have read\-access to the subtree. .TP 1. Transfer the base64\-encoded Windows AD CA Certificate to your IPA Server .TP 2. Remove any existing kerberos credentials # kdestroy .TP 3. Add the winsync replication agreement # ipa\-replica\-manage connect \-\-winsync \-\-passsync= \-\-cacert=/path/to/adscacert/WIN\-CA.cer \-\-binddn "cn=administrator,cn=users,dc=ad,dc=example,dc=com" \-\-bindpw \-v .TP You will be prompted to supply the Directory Manager's password. .TP Create a winsync replication agreement: # ipa\-replica\-manage connect \-\-winsync \-\-passsync=MySecret \-\-cacert=/root/WIN\-CA.cer \-\-binddn "cn=administrator,cn=users,dc=ad,dc=example,dc=com" \-\-bindpw MySecret \-v windows.ad.example.com .TP Remove a winsync replication agreement: # ipa\-replica\-manage disconnect windows.ad.example.com .SH "PASSSYNC" PassSync is a Windows service that runs on AD Domain Controllers to intercept password changes. It sends these password changes to the IPA LDAP server over TLS. These password changes bypass normal IPA password policy settings and the password is not set to immediately expire. This is because by the time IPA receives the password change it has already been accepted by AD so it is too late to reject it. .TP IPA maintains a list of DNs that are excempt from password policy. A special user is added automatically when a winsync replication agreement is created. The DN of this user is added to the excemption list stored in passSyncManagersDNs in the entry cn=ipa_pwd_extop,cn=plugins,cn=config. .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/ipa-ldap-updater.10000664000175000017500000001116312271663206021305 0ustar mkosekmkosek.\" A man page for ipa-ldap-updater .\" Copyright (C) 2008 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-ldap-updater" "1" "Sep 12 2008" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-ldap\-updater \- Update the IPA LDAP configuration .SH "SYNOPSIS" ipa\-ldap\-updater [options] input_file(s) ipa\-ldap\-updater [options] .SH "DESCRIPTION" ipa\-ldap\-updater is used to apply updates to the IPA LDAP server when the IPA packages are being updated. It is not intended to be executed by end\-users. When run with no file arguments, ipa\-ldap\-updater will process all files with the extension .update in /usr/share/ipa/updates. An update file describes an LDAP entry and a set of operations to be performed on that entry. It can be used to add new entries or modify existing entries. Blank lines and lines beginning with # are ignored. There are 7 keywords: * default: the starting value * add: add a value (or values) to an attribute * remove: remove a value (or values) from an attribute * only: set an attribute to this * onlyifexist: set an attribute to this only if the entry exists * deleteentry: remove the entry * replace: replace an existing value, format is old: new * addifnew: add a new attribute and value only if the attribute doesn't already exist. Only works with single\-value attributes. * addifexist: add a new attribute and value only if the entry exists. This is used to update optional entries. Values is a comma\-separated field so multi\-values may be added at one time. Double or single quotes may be put around individual values that contain embedded commas. The difference between the default and add keywords is if the DN of the entry exists then default is ignored. So for updating something like schema, which will be under cn=schema, you must always use add (because cn=schema is guaranteed to exist). It will not re\-add the same information again and again. It alsos provide some things that can be templated such as architecture (for plugin paths), realm and domain name. The available template variables are: * $REALM \- the kerberos realm (EXAMPLE.COM) * $FQDN \- the fully\-qualified domain name of the IPA server being updated (ipa.example.com) * $DOMAIN \- the domain name (example.com) * $SUFFIX \- the IPA LDAP suffix (dc=example,dc=com) * $ESCAPED_SUFFIX \- the ldap\-escaped IPA LDAP suffix * $LIBARCH \- set to 64 on x86_64 systems to be used for plugin paths * $TIME \- an integer representation of current time A few rules: 1. Only one rule per line 2. Each line stands alone (e.g. an only followed by an only results in the last only being used) 3. adding a value that exists is ok. The request is ignored, duplicate values are not added 4. removing a value that doesn't exist is ok. It is simply ignored. 5. If a DN doesn't exist it is created from the 'default' entry and all updates are applied 6. If a DN does exist the default values are skipped 7. Only the first rule on a line is respected Adds and updates are applied from shortest to longest length of DN. Deletes are done from longest to shortest. .SH "OPTIONS" .TP \fB\-d\fR, \fB\-\-debug Enable debug logging when more verbose output is needed .TP \fB\-t\fR, \fB\-\-test\fR Run through the update without changing anything. If changes are available then the command returns 2. If no updates are available it returns 0. .TP \fB\-y\fR File containing the Directory Manager password .TP \fB\-l\fR, \fB\-\-ldapi\fR Connect to the LDAP server using the ldapi socket .TP \fB\-p\fR, \fB\-\-\-plugins\fR Execute update plugins as well as any update files. There is no way to execute only the plugins. .TP \fB\-u\fR, \fB\-\-\-upgrade\fR Upgrade an installed server in offline mode (implies \-\-ldapi and \-\-plugins) .TP \fB\-W\fR, \fB\-\-\-password\fR Prompt for the Directory Manager password .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred 2 if run with in test mode (\-t) and updates are available freeipa-3.3.4/install/tools/man/ipa-ca-install.10000664000175000017500000000374712271663206020763 0ustar mkosekmkosek.\" A man page for ipa-replica-install .\" Copyright (C) 2011 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Rob Crittenden .\" .TH "ipa-ca-install" "1" "Jun 17 2011" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-ca\-install \- Install a CA on a replica .SH "SYNOPSIS" ipa\-ca\-install [\fIOPTION\fR]... replica_file .SH "DESCRIPTION" Adds a CA as an IPA\-managed service. This requires that the IPA server is already installed and configured. The replica_file is created using the ipa\-replica\-prepare utility and should be the same one used when originally installing the replica. .SH "OPTIONS" \fB\-d\fR, \fB\-\-debug\fR Enable debug logging when more verbose output is needed .TP \fB\-p\fR \fIDM_PASSWORD\fR, \fB\-\-password\fR=\fIDM_PASSWORD\fR Directory Manager (existing master) password .TP \fB\-w\fR \fIADMIN_PASSWORD\fR, \fB\-\-admin\-password\fR=\fIADMIN_PASSWORD\fR Admin user Kerberos password used for connection check .TP \fB\-\-no\-host\-dns\fR Do not use DNS for hostname lookup during installation .TP \fB\-\-skip\-conncheck\fR Skip connection check to remote master .TP \fB\-\-skip\-schema\-check\fR Skip check for updated CA DS schema on the remote master .TP \fB\-U\fR, \fB\-\-unattended\fR An unattended installation that will never prompt for user input .SH "EXIT STATUS" 0 if the command was successful 1 if an error occurred freeipa-3.3.4/install/tools/man/Makefile.in0000664000175000017500000004031412271707662020144 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # This file will be processed with automake-1.7 to create Makefile.in VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = tools/man DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 am__installdirs = "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" man8dir = $(mandir)/man8 NROFF = nroff MANS = $(man1_MANS) $(man8_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = 1.7 NULL = man1_MANS = \ ipa-replica-conncheck.1 \ ipa-replica-install.1 \ ipa-replica-manage.1 \ ipa-csreplica-manage.1 \ ipa-replica-prepare.1 \ ipa-server-certinstall.1 \ ipa-server-install.1 \ ipa-dns-install.1 \ ipa-adtrust-install.1 \ ipa-ca-install.1 \ ipa-ldap-updater.1 \ ipa-compat-manage.1 \ ipa-nis-manage.1 \ ipa-managed-entries.1 \ ipa-backup.1 \ ipa-restore.1 \ ipa-advise.1 \ $(NULL) man8_MANS = \ ipactl.8 \ ipa-upgradeconfig.8 \ $(NULL) MAINTAINERCLEANFILES = \ Makefile.in \ $(NULL) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/man/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/man/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-man1: $(man1_MANS) @$(NORMAL_INSTALL) @list1='$(man1_MANS)'; \ list2=''; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list='$(man1_MANS)'; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(man8_MANS) @$(NORMAL_INSTALL) @list1='$(man8_MANS)'; \ list2=''; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list='$(man8_MANS)'; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man1 uninstall-man8 .MAKE: install-am install-data-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-data-hook install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-man1 \ install-man8 install-pdf install-pdf-am install-ps \ install-ps-am install-strip installcheck installcheck-am \ installdirs maintainer-clean maintainer-clean-generic \ mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags-am \ uninstall uninstall-am uninstall-man uninstall-man1 \ uninstall-man8 install-data-hook: @for i in $(man1_MANS) ; do gzip -f $(DESTDIR)$(man1dir)/$$i ; done @for i in $(man8_MANS) ; do gzip -f $(DESTDIR)$(man8dir)/$$i ; done # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/tools/man/ipa-replica-conncheck.10000664000175000017500000001054112271663206022272 0ustar mkosekmkosek.\" A man page for ipa-replica-conncheck .\" Copyright (C) 2011 Red Hat, Inc. .\" .\" 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 . .\" .\" Author: Martin Kosek .\" .TH "ipa-replica-conncheck" "1" "Jun 2 2011" "FreeIPA" "FreeIPA Manual Pages" .SH "NAME" ipa\-replica\-conncheck \- Check a replica\-master network connection before installation .SH "SYNOPSIS" ipa\-replica\-conncheck [\fIOPTION\fR]... .SH "DESCRIPTION" When an IPA replica is being installed a network connection between a replica machine and a replicated IPA master machine has to be prepared for master\-replica communication. In case of a flawed connection the installation may fail with inconvenient error messages. A common connection problem is a misconfigured firewall with closed required port on a replica or master machine. The connection is checked by running a set of tests from both master and replica machines. The program is incorporated to ipa\-replica\-install(1) but can be also run separately. .SH "OPTIONS" .SS "REPLICA MACHINE OPTIONS" This set of options is used when the connection check is run on a prepared IPA replica machine. .TP \fB\-m\fR \fIMASTER\fR, \fB\-\-master\fR=\fIMASTER\fR Remote master machine address .TP \fB\-a\fR, \fB\-\-auto\-master\-check\fR Automatically log in to master machine and execute the master machine part of the connection check. The following options for replica part are only evaluated when this option is set .TP \fB\-r\fR \fIREALM\fR, \fB\-\-realm\fR=\fIREALM\fR The Kerberos realm name for the IPA server .TP \fB\-k\fR \fIKDC\fR, \fB\-\-kdc\fR=\fIKDC\fR KDC server address. Defaults t \fIMASTER\fR .TP \fB\-p\fR \fIPRINCIPAL\fR, \fB\-\-principal\fR=\fIPRINCIPAL\fR Authorized Kerberos principal to use to log in to master machine. Defaults to \fIadmin\fR .TP \fB\-w\fR \fIPASSWORD\fR, \fB\-\-password\fR=\fIPASSWORD\fR Password for given principal. The password will be prompted interactively when this option is missing .SS "MASTER MACHINE OPTIONS" This set of options is used when the connection check is run on a master machine against a running ipa\-replica\-conncheck(1) on a replica machine. .TP \fB\-R\fR \fIREPLICA\fR, \fB\-\-replica\fR=\fIREPLICA\fR Remote replica machine address .SS "COMMON OPTIONS" .TP \fB\-c\fR, \fB\-\-check\-ca\fR Include in a check also a set of dogtag connection requirements. Only needed when the master was installed with Dogtag 9 or lower. .TP \fB\-h\fR \fIHOSTNAME\fR, \fB\-\-hostname\fR=\fIHOSTNAME\fR The hostname of this server (FQDN). By default a nodename from uname(2) is used .TP \fB\-d\fR, \fB\-\-debug\fR Print debugging information .TP \fB\-q\fR, \fB\-\-quiet\fR Output only errors .SH "EXAMPLES" .TP \fBipa-replica-conncheck -m master.example.com\fR Run a replica machine connection check against a remote master \fImaster.example.com\fR. If the connection to the remote master machine is successful the program will switch to listening mode and prompt for running the master machine part. The second part check the connection from master to replica. .TP \fBipa-replica-conncheck -R replica.example.com\fR Run a master machine connection check part. This is either run automatically by replica part of the connection check program (when \fI-a\fR option is set) or manually by the user. A running ipa-replica-conncheck(1) in a listening mode must be already running on a replica machine. .TP \fBipa-replica-conncheck -m master.example.com -a -r EXAMPLE.COM -w password\fR Run a replica\-master connection check. In case of a success switch to listening mode, automatically log to \fImaster.example.com\fR in a realm \fIEXAMPLE.COM\fR with a password \fIpassword\fR and run the second part of the connection check. .SH "EXIT STATUS" 0 if the connection check was successful 1 if an error occurred .SH "SEE ALSO" .BR ipa-replica-install (1) freeipa-3.3.4/install/tools/ipa-replica-install0000775000175000017500000007441012271663206021103 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Karl MacMillan # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import sys import socket import os, pwd, shutil from optparse import OptionGroup from contextlib import contextmanager import dns.resolver import dns.reversename import dns.exception from ipapython import ipautil from ipaserver.install import dsinstance, installutils, krbinstance, service from ipaserver.install import bindinstance, httpinstance, ntpinstance from ipaserver.install import memcacheinstance from ipaserver.install import otpdinstance from ipaserver.install.replication import replica_conn_check, ReplicationManager from ipaserver.install.installutils import (ReplicaConfig, expand_replica_info, read_replica_info ,get_host_name, BadHostError, private_ccache) from ipaserver.plugins.ldap2 import ldap2 from ipaserver.install import cainstance from ipalib import api, errors, util from ipapython import version from ipapython.config import IPAOptionParser from ipapython import sysrestore from ipapython import services as ipaservices from ipapython.ipa_log_manager import * from ipapython import dogtag from ipapython.dn import DN import ipaclient.ntpconf log_file_name = "/var/log/ipareplica-install.log" CACERT = "/etc/ipa/ca.crt" REPLICA_INFO_TOP_DIR = None DIRMAN_DN = DN(('cn', 'directory manager')) def parse_options(): usage = "%prog [options] REPLICA_FILE" parser = IPAOptionParser(usage=usage, version=version.VERSION) basic_group = OptionGroup(parser, "basic options") basic_group.add_option("--setup-ca", dest="setup_ca", action="store_true", default=False, help="configure a dogtag CA") basic_group.add_option("--ip-address", dest="ip_address", type="ip", ip_local=True, help="Replica server IP Address") basic_group.add_option("-p", "--password", dest="password", sensitive=True, help="Directory Manager (existing master) password") basic_group.add_option("-w", "--admin-password", dest="admin_password", sensitive=True, help="Admin user Kerberos password used for connection check") basic_group.add_option("--mkhomedir", dest="mkhomedir", action="store_true", default=False, help="create home directories for users " "on their first login") basic_group.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false", help="do not configure ntp", default=True) basic_group.add_option("--no-ui-redirect", dest="ui_redirect", action="store_false", default=True, help="Do not automatically redirect to the Web UI") basic_group.add_option("--ssh-trust-dns", dest="trust_sshfp", default=False, action="store_true", help="configure OpenSSH client to trust DNS SSHFP records") basic_group.add_option("--no-ssh", dest="conf_ssh", default=True, action="store_false", help="do not configure OpenSSH client") basic_group.add_option("--no-sshd", dest="conf_sshd", default=True, action="store_false", help="do not configure OpenSSH server") basic_group.add_option("--skip-conncheck", dest="skip_conncheck", action="store_true", default=False, help="skip connection check to remote master") basic_group.add_option("-d", "--debug", dest="debug", action="store_true", default=False, help="gather extra debugging information") basic_group.add_option("-U", "--unattended", dest="unattended", action="store_true", default=False, help="unattended installation never prompts the user") parser.add_option_group(basic_group) cert_group = OptionGroup(parser, "certificate system options") cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false", default=True, help="disables pkinit setup steps") cert_group.add_option("--skip-schema-check", dest="skip_schema_check", action="store_true", default=False, help="skip check for updated CA DS schema on the remote master") parser.add_option_group(cert_group) dns_group = OptionGroup(parser, "DNS options") dns_group.add_option("--setup-dns", dest="setup_dns", action="store_true", default=False, help="configure bind with our zone") dns_group.add_option("--forwarder", dest="forwarders", action="append", type="ip", help="Add a DNS forwarder") dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true", default=False, help="Do not add any DNS forwarders, use root servers instead") dns_group.add_option("--reverse-zone", dest="reverse_zone", help="The reverse DNS zone to use") dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true", default=False, help="Do not create new reverse DNS zone") dns_group.add_option("--no-host-dns", dest="no_host_dns", action="store_true", 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") parser.add_option_group(dns_group) options, args = parser.parse_args() safe_options = parser.get_safe_opts(options) if len(args) != 1: parser.error("you must provide a file generated by ipa-replica-prepare") if not options.setup_dns: if options.forwarders: parser.error("You cannot specify a --forwarder option without the --setup-dns option") if options.no_forwarders: parser.error("You cannot specify a --no-forwarders option without the --setup-dns option") if options.reverse_zone: parser.error("You cannot specify a --reverse-zone option without the --setup-dns option") if options.no_reverse: parser.error("You cannot specify a --no-reverse option without the --setup-dns option") elif options.forwarders and options.no_forwarders: parser.error("You cannot specify a --forwarder option together with --no-forwarders") elif not options.forwarders and not options.no_forwarders: parser.error("You must specify at least one --forwarder option or --no-forwarders option") elif options.reverse_zone and options.no_reverse: parser.error("You cannot specify a --reverse-zone option together with --no-reverse") return safe_options, options, args[0] def get_dirman_password(): return installutils.read_password("Directory Manager (existing master)", confirm=False, validate=False) def set_owner(config, dir): pw = pwd.getpwnam(dsinstance.DS_USER) os.chown(dir, pw.pw_uid, pw.pw_gid) def make_pkcs12_info(directory, cert_name, password_name): """Make pkcs12_info :param directory: Base directory (config.dir) :param cert_name: Cert filename (e.g. "dscert.p12") :param password_name: Cert filename (e.g. "dirsrv_pin.txt") :return: a (full cert path, password) tuple, or None if cert is not found """ cert_path = os.path.join(directory, cert_name) if ipautil.file_exists(cert_path): password_file = os.path.join(directory, password_name) password = open(password_file).read().strip() return cert_path, password else: return None def install_replica_ds(config): dsinstance.check_ports() # if we have a pkcs12 file, create the cert db from # that. Otherwise the ds setup will create the CA # cert pkcs12_info = make_pkcs12_info(config.dir, "dscert.p12", "dirsrv_pin.txt") ds = dsinstance.DsInstance() ds.create_replica( realm_name=config.realm_name, master_fqdn=config.master_host_name, fqdn=config.host_name, domain_name=config.domain_name, dm_password=config.dirman_password, subject_base=config.subject_base, pkcs12_info=pkcs12_info, ca_is_configured=ipautil.file_exists(config.dir + "/cacert.p12"), ca_file=config.dir + "/ca.crt", ) return ds def install_krb(config, setup_pkinit=False): krb = krbinstance.KrbInstance() #pkinit files pkcs12_info = make_pkcs12_info(config.dir, "pkinitcert.p12", "pkinit_pin.txt") krb.create_replica(config.realm_name, config.master_host_name, config.host_name, config.domain_name, config.dirman_password, setup_pkinit, pkcs12_info) return krb def install_ca_cert(config): cafile = config.dir + "/ca.crt" if not ipautil.file_exists(cafile): raise RuntimeError("Ca cert file is not available") try: shutil.copy(cafile, CACERT) os.chmod(CACERT, 0444) except Exception, e: print "error copying files: " + str(e) sys.exit(1) def install_http(config, auto_redirect): # if we have a pkcs12 file, create the cert db from # that. Otherwise the ds setup will create the CA # cert pkcs12_info = make_pkcs12_info(config.dir, "httpcert.p12", "http_pin.txt") memcache = memcacheinstance.MemcacheInstance() memcache.create_instance('MEMCACHE', config.host_name, config.dirman_password, ipautil.realm_to_suffix(config.realm_name)) http = httpinstance.HTTPInstance() http.create_instance( config.realm_name, config.host_name, config.domain_name, config.dirman_password, False, pkcs12_info, auto_redirect=auto_redirect, ca_file = config.dir + "/ca.crt") # Now copy the autoconfiguration files try: if ipautil.file_exists(config.dir + "/preferences.html"): shutil.copy(config.dir + "/preferences.html", "/usr/share/ipa/html/preferences.html") if ipautil.file_exists(config.dir + "/configure.jar"): shutil.copy(config.dir + "/configure.jar", "/usr/share/ipa/html/configure.jar") if ipautil.file_exists(config.dir + "/krb.js"): shutil.copy(config.dir + "/krb.js", "/usr/share/ipa/html/krb.js") shutil.copy(config.dir + "/kerberosauth.xpi", "/usr/share/ipa/html/kerberosauth.xpi") except Exception, e: print "error copying files: " + str(e) sys.exit(1) http.setup_firefox_extension(config.realm_name, config.domain_name) return http def install_bind(config, options): api.Backend.ldap2.connect(bind_dn=DIRMAN_DN, bind_pw=config.dirman_password) if options.forwarders: forwarders = options.forwarders else: forwarders = () bind = bindinstance.BindInstance(dm_password=config.dirman_password) if options.reverse_zone: if not bindinstance.verify_reverse_zone(options.reverse_zone, config.ip): sys.exit(1) reverse_zone = bindinstance.normalize_zone(options.reverse_zone) else: reverse_zone = bindinstance.find_reverse_zone(config.ip) if reverse_zone is None and not options.no_reverse: reverse_zone = util.get_reverse_zone_default(config.ip) if not options.unattended and bindinstance.create_reverse(): reverse_zone = bindinstance.read_reverse_zone(reverse_zone, config.ip) if reverse_zone is not None: print "Using reverse zone %s" % reverse_zone bind.setup(config.host_name, config.ip_address, config.realm_name, config.domain_name, forwarders, options.conf_ntp, reverse_zone, ca_configured=options.setup_ca) bind.create_instance() print "" bind.check_global_configuration() print "" @contextmanager def temporary_ldap2_connection(host_name, bind_pw, bind_dn=DIRMAN_DN): """Context in which the ldap2 backend is connected to the given host When the context is entered, forcefully change the ldap2's URI and connect with the given password. When it's exited, disconnect and restore ldap2 to previous configuration. Needed to use the standard IPA tools on the remote master, before the DS on localhost is installed. """ # TODO: We shouldn't have to resort to such hacks cur_uri = api.Backend.ldap2.ldap_uri # ldap2 is finalized at this point, so use __setattr__ directly object.__setattr__(api.Backend.ldap2, 'ldap_uri', 'ldaps://%s' % ipautil.format_netloc(host_name)) api.Backend.ldap2.connect(bind_dn=DIRMAN_DN, bind_pw=bind_pw, tls_cacertfile=CACERT) yield api.Backend.ldap2.disconnect() #set it back to the default object.__setattr__(api.Backend.ldap2, 'ldap_uri', cur_uri) def install_dns_records(config, options): if not bindinstance.dns_container_exists(config.master_host_name, ipautil.realm_to_suffix(config.realm_name), dm_password=config.dirman_password): return # We have to force to connect to the remote master because we do this step # before our DS server is installed. with temporary_ldap2_connection( config.master_host_name, config.dirman_password): try: bind = bindinstance.BindInstance(dm_password=config.dirman_password) reverse_zone = bindinstance.find_reverse_zone(config.ip) bind.add_master_dns_records(config.host_name, config.ip_address, config.realm_name, config.domain_name, reverse_zone, options.conf_ntp, options.setup_ca) except errors.NotFound, e: root_logger.debug('Replica DNS records could not be added ' 'on master: %s', str(e)) # we should not fail here no matter what except Exception, e: root_logger.info('Replica DNS records could not be added ' 'on master: %s', str(e)) def check_dirsrv(): (ds_unsecure, ds_secure) = dsinstance.check_ports() if not ds_unsecure or not ds_secure: print "IPA requires ports 389 and 636 for the Directory Server." print "These are currently in use:" if not ds_unsecure: print "\t389" if not ds_secure: print "\t636" sys.exit(1) def check_bind(): if not bindinstance.check_inst(unattended=True): print "Aborting installation" sys.exit(1) def check_dns_resolution(host_name, dns_servers): """Check forward and reverse resolution of host_name using dns_servers """ # Point the resolver at specified DNS server server_ips = [] for dns_server in dns_servers: try: server_ips = list( a[4][0] for a in socket.getaddrinfo(dns_server, None)) except socket.error: pass else: break if not server_ips: root_logger.error( 'Could not resolve any DNS server hostname: %s', dns_servers) return False resolver = dns.resolver.Resolver() resolver.nameservers = server_ips root_logger.debug('Search DNS server %s (%s) for %s', dns_server, server_ips, host_name) # Get IP addresses of host_name addresses = set() for rtype in 'A', 'AAAA': try: result = resolver.query(host_name, rtype) except dns.exception.DNSException: rrset = [] else: rrset = result.rrset if rrset: addresses.update(r.address for r in result.rrset) if not addresses: root_logger.error( 'Could not resolve hostname %s using DNS. ' 'Clients may not function properly. ' 'Please check your DNS setup. ' '(Note that this check queries IPA DNS directly and ' 'ignores /etc/hosts.)', host_name) return False no_errors = True # Check each of the IP addresses checked = set() for address in addresses: if address in checked: continue checked.add(address) try: root_logger.debug('Check reverse address %s (%s)', address, host_name) revname = dns.reversename.from_address(address) rrset = resolver.query(revname, 'PTR').rrset except Exception, e: root_logger.debug('Check failed: %s %s', type(e).__name__, e) root_logger.error( 'Reverse DNS resolution of address %s (%s) failed. ' 'Clients may not function properly. ' 'Please check your DNS setup. ' '(Note that this check queries IPA DNS directly and ' 'ignores /etc/hosts.)', address, host_name) no_errors = False else: host_name_obj = dns.name.from_text(host_name) if rrset: names = [r.target.to_text() for r in rrset] else: names = [] root_logger.debug( 'Address %s resolves to: %s. ', address, ', '.join(names)) if not rrset or not any( r.target == host_name_obj for r in rrset): root_logger.error( 'The IP address %s of host %s resolves to: %s. ' 'Clients may not function properly. ' 'Please check your DNS setup. ' '(Note that this check queries IPA DNS directly and ' 'ignores /etc/hosts.)', address, host_name, ', '.join(names)) no_errors = False return no_errors def main(): ipaservices.check_selinux_status() safe_options, options, filename = parse_options() if os.geteuid() != 0: sys.exit("\nYou must be root to run this script.\n") standard_logging_setup(log_file_name, debug=options.debug) root_logger.debug('%s was invoked with argument "%s" and options: %s' % (sys.argv[0], filename, safe_options)) if not ipautil.file_exists(filename): sys.exit("Replica file %s does not exist" % filename) client_fstore = sysrestore.FileStore('/var/lib/ipa-client/sysrestore') if client_fstore.has_files(): sys.exit("IPA client is already configured on this system.\n" + "Please uninstall it first before configuring the replica, " + "using 'ipa-client-install --uninstall'.") global sstore sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore') global fstore fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore') # check the bind is installed if options.setup_dns: check_bind() # Check to see if httpd is already configured to listen on 443 if httpinstance.httpd_443_configured(): sys.exit("Aborting installation") check_dirsrv() if options.conf_ntp: try: ipaclient.ntpconf.check_timedate_services() except ipaclient.ntpconf.NTPConflictingService, e: print "WARNING: conflicting time&date synchronization service '%s'" \ " will" % e.conflicting_service print "be disabled in favor of ntpd" print "" except ipaclient.ntpconf.NTPConfigurationError: pass # get the directory manager password dirman_password = options.password if not dirman_password: try: dirman_password = get_dirman_password() except KeyboardInterrupt: sys.exit(0) if dirman_password is None: sys.exit("Directory Manager password required") try: top_dir, dir = expand_replica_info(filename, dirman_password) global REPLICA_INFO_TOP_DIR REPLICA_INFO_TOP_DIR = top_dir except Exception, e: print "ERROR: Failed to decrypt or open the replica file." print "Verify you entered the correct Directory Manager password." sys.exit(1) config = ReplicaConfig() read_replica_info(dir, config) root_logger.debug('Installing replica file with version %d (0 means no version in prepared file).' % config.version) if config.version and config.version > version.NUM_VERSION: root_logger.error('A replica file from a newer release (%d) cannot be installed on an older version (%d)' % (config.version, version.NUM_VERSION)) sys.exit(1) config.dirman_password = dirman_password try: host = get_host_name(options.no_host_dns) except BadHostError, e: root_logger.error(str(e)) sys.exit(1) 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?", False): sys.exit(0) config.host_name = host print "" except KeyboardInterrupt: sys.exit(0) config.dir = dir config.setup_ca = options.setup_ca if config.setup_ca and not ipautil.file_exists(config.dir + "/cacert.p12"): print 'CA cannot be installed in CA-less setup.' sys.exit(1) installutils.verify_fqdn(config.master_host_name, options.no_host_dns) portfile = config.dir + "/dogtag_directory_port.txt" if not ipautil.file_exists(portfile): dogtag_master_ds_port = str(dogtag.Dogtag9Constants.DS_PORT) else: with open(portfile) as fd: dogtag_master_ds_port = fd.read() # check connection if not options.skip_conncheck: replica_conn_check( config.master_host_name, config.host_name, config.realm_name, options.setup_ca, dogtag_master_ds_port, options.admin_password) # check replica host IP resolution config.ip = installutils.get_server_ip_address(config.host_name, fstore, True, options) config.ip_address = str(config.ip) # Create the management framework config file # Note: We must do this before bootstraping and finalizing ipalib.api old_umask = os.umask(022) # must be readable for httpd try: fd = open("/etc/ipa/default.conf", "w") fd.write("[global]\n") fd.write("host=%s\n" % config.host_name) fd.write("basedn=%s\n" % str(ipautil.realm_to_suffix(config.realm_name))) fd.write("realm=%s\n" % config.realm_name) fd.write("domain=%s\n" % config.domain_name) fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % ipautil.format_netloc(config.host_name)) fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(config.realm_name)) if ipautil.file_exists(config.dir + "/cacert.p12"): fd.write("enable_ra=True\n") fd.write("ra_plugin=dogtag\n") fd.write("dogtag_version=%s\n" % dogtag.install_constants.DOGTAG_VERSION) else: fd.write("enable_ra=False\n") fd.write("ra_plugin=none\n") fd.write("mode=production\n") fd.close() finally: os.umask(old_umask) api.bootstrap(in_server=True, context='installer') api.finalize() # Create DS group if it doesn't exist yet group_exists = dsinstance.create_ds_group() sstore.backup_state("install", "group_exists", group_exists) #Automatically disable pkinit w/ dogtag until that is supported options.setup_pkinit = False # Install CA cert so that we can do SSL connections with ldap install_ca_cert(config) ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name) replman = conn = None try: # Try out the password conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='') conn.connect(bind_dn=DIRMAN_DN, bind_pw=config.dirman_password, tls_cacertfile=CACERT) replman = ReplicationManager(config.realm_name, config.master_host_name, config.dirman_password) found = False try: entry = conn.find_entries(u'fqdn=%s' % host, ['fqdn'], DN(api.env.container_host, api.env.basedn)) print "The host %s already exists on the master server.\nYou should remove it before proceeding:" % host print " %% ipa host-del %s" % host found = True except errors.NotFound: pass # If remote host has DNS, check forward/reverse resolution with temporary_ldap2_connection( config.master_host_name, config.dirman_password): dns_masters = api.Object['dnsrecord'].get_dns_masters() if dns_masters: if not options.no_host_dns: master = config.master_host_name root_logger.debug('Check forward/reverse DNS resolution') resolution_ok = ( check_dns_resolution(master, dns_masters) and check_dns_resolution(config.host_name, dns_masters)) if not resolution_ok and not options.unattended: if not ipautil.user_input("Continue?", False): sys.exit(0) else: root_logger.debug('No IPA DNS servers, ' 'skipping forward/reverse resolution check') # Check that we don't already have a replication agreement try: (agreement_cn, agreement_dn) = replman.agreement_dn(host) entry = conn.get_entry(agreement_dn, ['*']) print "A replication agreement for this host already exists. It needs to be removed. Run this on the master that generated the info file:" print " %% ipa-replica-manage del %s --force" % host found = True except errors.NotFound: pass if found: sys.exit(3) except errors.ACIError: sys.exit("\nThe password provided is incorrect for LDAP server %s" % config.master_host_name) except errors.LDAPError: sys.exit("\nUnable to connect to LDAP server %s" % config.master_host_name) finally: if conn and conn.isconnected(): conn.disconnect() if replman and replman.conn: replman.conn.unbind() if options.skip_schema_check: root_logger.info("Skipping CA DS schema check") else: cainstance.replica_ca_install_check(config, dogtag_master_ds_port) # Configure ntpd if options.conf_ntp: ipaclient.ntpconf.force_ntpd(sstore) ntp = ntpinstance.NTPInstance() ntp.create_instance() # Configure dirsrv ds = install_replica_ds(config) # Configure the CA if necessary CA = cainstance.install_replica_ca(config, dogtag_master_ds_port) # Always try to install DNS records install_dns_records(config, options) # We need to ldap_enable the CA now that DS is up and running if CA and config.setup_ca: CA.ldap_enable('CA', config.host_name, config.dirman_password, ipautil.realm_to_suffix(config.realm_name)) # This is done within stopped_service context, which restarts CA CA.enable_client_auth_to_db() krb = install_krb(config, setup_pkinit=options.setup_pkinit) http = install_http(config, auto_redirect=options.ui_redirect) otpd = otpdinstance.OtpdInstance() otpd.create_instance('OTPD', config.host_name, config.dirman_password, ipautil.realm_to_suffix(config.realm_name)) if CA: CA.configure_certmonger_renewal() CA.import_ra_cert(dir + "/ra.p12") CA.fix_ra_perms() ipaservices.knownservices.httpd.restart() # The DS instance is created before the keytab, add the SSL cert we # generated ds.add_cert_to_service() # Apply any LDAP updates. Needs to be done after the replica is synced-up service.print_msg("Applying LDAP updates") ds.apply_updates() # Restart ds and krb after configurations have been changed service.print_msg("Restarting the directory server") ds.restart() service.print_msg("Restarting the KDC") krb.restart() if options.setup_dns: install_bind(config, options) # Restart httpd to pick up the new IPA configuration service.print_msg("Restarting the web server") http.restart() # Call client install script try: args = ["/usr/sbin/ipa-client-install", "--on-master", "--unattended", "--domain", config.domain_name, "--server", config.host_name, "--realm", config.realm_name] if not options.create_sshfp: args.append("--no-dns-sshfp") if options.trust_sshfp: args.append("--ssh-trust-dns") if not options.conf_ssh: args.append("--no-ssh") if not options.conf_sshd: args.append("--no-sshd") if options.mkhomedir: args.append("--mkhomedir") ipautil.run(args) except Exception, e: print "Configuration of client side components failed!" print "ipa-client-install returned: " + str(e) raise RuntimeError("Failed to configure the client") ds.replica_populate() #Everything installed properly, activate ipa service. ipaservices.knownservices.ipa.enable() fail_message = ''' Your system may be partly configured. Run /usr/sbin/ipa-server-install --uninstall to clean up. ''' if __name__ == '__main__': try: with private_ccache(): installutils.run_script(main, log_file_name=log_file_name, operation_name='ipa-replica-install', fail_message=fail_message) finally: # always try to remove decrypted replica file try: if REPLICA_INFO_TOP_DIR: shutil.rmtree(REPLICA_INFO_TOP_DIR) except OSError: pass freeipa-3.3.4/install/tools/ipa-replica-manage0000775000175000017500000014010612271663206020661 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Karl MacMillan # # Copyright (C) 2007 Red Hat # see file 'COPYING' for use and warranty information # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, 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 . # import sys import os import re, krbV import traceback from urllib2 import urlparse import ldap import socket from ipapython import ipautil from ipaserver.install import replication, dsinstance, installutils from ipaserver.install import bindinstance from ipaserver.plugins import ldap2 from ipapython import version, ipaldap from ipalib import api, errors, util from ipapython.ipa_log_manager import * from ipapython.dn import DN from ipapython.config import IPAOptionParser from ipaclient import ipadiscovery from xmlrpclib import MAXINT CACERT = "/etc/ipa/ca.crt" # dict of command name and tuples of min/max num of args needed commands = { "list":(0, 1, "[master fqdn]", ""), "list-ruv":(0, 0, "", ""), "connect":(1, 2, " [other master fqdn]", "must provide the name of the servers to connect"), "disconnect":(1, 2, " [other master fqdn]", "must provide the name of the server to disconnect"), "del":(1, 1, "", "must provide hostname of master to delete"), "re-initialize":(0, 0, "", ""), "force-sync":(0, 0, "", ""), "clean-ruv":(1, 1, "Replica ID of to clean", "must provide replica ID to clean"), "abort-clean-ruv":(1, 1, "Replica ID to abort cleaning", "must provide replica ID to abort cleaning"), "list-clean-ruv":(0, 0, "", ""), "dnarange-show":(0, 1, "[master fqdn]", ""), "dnanextrange-show":(0, 1, "", ""), "dnarange-set":(2, 2, " ", "must provide a master and ID range"), "dnanextrange-set":(2, 2, " ", "must provide a master and ID range"), } def parse_options(): parser = IPAOptionParser(version=version.VERSION) parser.add_option("-H", "--host", dest="host", help="starting host") parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="provide additional information") parser.add_option("-f", "--force", dest="force", action="store_true", default=False, help="ignore some types of errors") parser.add_option("-c", "--cleanup", dest="cleanup", action="store_true", default=False, help="DANGER: clean up references to a ghost master") parser.add_option("--binddn", dest="binddn", default=None, type="dn", help="Bind DN to use with remote server") parser.add_option("--bindpw", dest="bindpw", default=None, help="Password for Bind DN to use with remote server") parser.add_option("--winsync", dest="winsync", action="store_true", default=False, help="This is a Windows Sync Agreement") parser.add_option("--cacert", dest="cacert", default=None, help="Full path and filename of CA certificate to use with TLS/SSL to the remote server") parser.add_option("--win-subtree", dest="win_subtree", default=None, help="DN of Windows subtree containing the users you want to sync (default cn=Users, v[1]: err = "too many arguments" else: valid_syntax = True if err: parser.error("Invalid syntax: %s\nUsage: %s [options] %s" % (err, cmd, v[2])) if not valid_syntax: cmdstr = " | ".join(commands.keys()) parser.error("must provide a command [%s]" % cmdstr) return options, args def test_connection(realm, host, nolookup=False): """ Make a GSSAPI connection to the remote LDAP server to test out credentials. This is used so we can fall back to promping for the DM password. returns True if connection successful, False otherwise """ try: if not nolookup: enforce_host_existence(host) replman = replication.ReplicationManager(realm, host, None) ents = replman.find_replication_agreements() del replman return True except errors.ACIError: return False except errors.NotFound: # We do a search in cn=config. NotFound in this case means no # permission return False except ldap.LOCAL_ERROR: # more than likely a GSSAPI error return False def list_replicas(realm, host, replica, dirman_passwd, verbose, nolookup=False): if not nolookup: enforce_host_existence(host) if replica is not None: enforce_host_existence(replica) is_replica = False winsync_peer = None peers = {} try: conn = ipaldap.IPAdmin(host, 636, cacert=CACERT) if dirman_passwd: conn.do_simple_bind(bindpw=dirman_passwd) else: conn.do_sasl_gssapi_bind() except Exception, e: print "Failed to connect to host '%s': %s" % (host, str(e)) return dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) try: entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL) except Exception: print "Failed to read master data from '%s': %s" % (host, str(e)) return else: for ent in entries: peers[ent.single_value('cn')] = ['master', ''] dn = DN(('cn', 'replicas'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) try: entries = conn.get_entries(dn, conn.SCOPE_ONELEVEL) except Exception: pass else: for ent in entries: config_string = ent.single_value('ipaConfigString') peers[ent.single_value('cn')] = config_string.split(':') if not replica: for k, p in peers.iteritems(): print '%s: %s' % (k, p[0]) return # ok we are being ask for info about a specific replica for k, p in peers.iteritems(): if replica == k: is_replica = True if p[0] == 'winsync': winsync_peer = p[1] if not is_replica: print "Cannot find %s in public server list" % replica return try: if winsync_peer: repl = replication.ReplicationManager(realm, winsync_peer, dirman_passwd) cn, dn = repl.agreement_dn(replica) entries = repl.conn.get_entries( dn, conn.SCOPE_BASE, "(objectclass=nsDSWindowsReplicationAgreement)") ent_type = 'winsync' else: repl = replication.ReplicationManager(realm, replica, dirman_passwd) entries = repl.find_replication_agreements() ent_type = 'replica' except Exception, e: print "Failed to get data from '%s': %s" % (replica, e) return for entry in entries: print '%s: %s' % (entry.single_value('nsds5replicahost', None), ent_type) if verbose: print " last init status: %s" % entry.single_value( 'nsds5replicalastinitstatus', None) print " last init ended: %s" % str(ipautil.parse_generalized_time( entry.single_value('nsds5replicalastinitend'))) print " last update status: %s" % entry.single_value( 'nsds5replicalastupdatestatus', None) print " last update ended: %s" % str( ipautil.parse_generalized_time( entry.single_value('nsds5replicalastupdateend'))) def del_link(realm, replica1, replica2, dirman_passwd, force=False): """ Delete a replication agreement from host A to host B. @realm: the Kerberos realm @replica1: the hostname of master A @replica2: the hostname of master B @dirman_passwd: the Directory Manager password @force: force deletion even if one server is down """ repl2 = None try: repl1 = replication.ReplicationManager(realm, replica1, dirman_passwd) type1 = repl1.get_agreement_type(replica2) repl_list = repl1.find_ipa_replication_agreements() if not force and len(repl_list) <= 1 and type1 == replication.IPA_REPLICA: print "Cannot remove the last replication link of '%s'" % replica1 print "Please use the 'del' command to remove it from the domain" return False except errors.NotFound: print "'%s' has no replication agreement for '%s'" % (replica1, replica2) return False except Exception, e: print "Failed to determine agreement type for '%s': %s" % (replica1, e) return False if type1 == replication.IPA_REPLICA: try: repl2 = replication.ReplicationManager(realm, replica2, dirman_passwd) 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" return False except errors.NotFound: print "'%s' has no replication agreement for '%s'" % (replica2, replica1) if not force: return False except Exception, e: print "Failed to get list of agreements from '%s': %s" % (replica2, e) if not force: return False if repl2 and type1 == replication.IPA_REPLICA: failed = False try: repl2.set_readonly(readonly=True) repl2.force_sync(repl2.conn, replica1) cn, dn = repl2.agreement_dn(repl1.conn.host) repl2.wait_for_repl_update(repl2.conn, dn, 30) (range_start, range_max) = repl2.get_DNA_range(repl2.conn.host) (next_start, next_max) = repl2.get_DNA_next_range(repl2.conn.host) if range_start is not None: if not store_DNA_range(repl1, range_start, range_max, repl2.conn.host, realm, dirman_passwd): print "Unable to save DNA range %d-%d" % (range_start, range_max) if next_start is not None: if not store_DNA_range(repl1, next_start, next_max, repl2.conn.host, realm, dirman_passwd): print "Unable to save DNA range %d-%d" % (next_start, next_max) repl2.set_readonly(readonly=False) repl2.delete_agreement(replica1) repl2.delete_referral(replica1) repl2.set_readonly(readonly=False) except Exception, e: print "Unable to remove agreement on %s: %s" % (replica2, e) failed = True if failed: if force: print "Forcing removal on '%s'" % replica1 print "Any DNA range on '%s' will be lost" % replica2 else: return False if not repl2 and force: print "Forcing removal on '%s'" % replica1 print "Any DNA range on '%s' will be lost" % replica2 repl1.delete_agreement(replica2) repl1.delete_referral(replica2) if type1 == replication.WINSYNC: try: dn = DN(('cn', replica2), ('cn', 'replicas'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) entries = repl1.conn.get_entries(dn, repl1.conn.SCOPE_SUBTREE) if entries: entries.sort(key=len, reverse=True) for entry in entries: repl1.conn.delete_entry(entry) except Exception, e: print "Error deleting winsync replica shared info: %s" % e print "Deleted replication agreement from '%s' to '%s'" % (replica1, replica2) return True def get_ruv(realm, host, dirman_passwd, nolookup=False): """ Return the RUV entries as a list of tuples: (hostname, rid) """ if not nolookup: enforce_host_existence(host) try: thisrepl = replication.ReplicationManager(realm, host, dirman_passwd) except Exception, e: print "Failed to connect to server %s: %s" % (host, e) sys.exit(1) search_filter = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))' try: entries = thisrepl.conn.get_entries( api.env.basedn, thisrepl.conn.SCOPE_SUBTREE, search_filter, ['nsds50ruv']) except errors.NotFound: print "No RUV records found." sys.exit(0) servers = [] for e in entries: for ruv in e['nsds50ruv']: if ruv.startswith('{replicageneration'): continue data = re.match('\{replica (\d+) (ldap://.*:\d+)\}(\s+\w+\s+\w*){0,1}', ruv) if data: rid = data.group(1) (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(data.group(2)) servers.append((netloc, rid)) else: print "unable to decode: %s" % ruv return servers def list_ruv(realm, host, dirman_passwd, verbose, nolookup=False): """ List the Replica Update Vectors on this host to get the available replica IDs. """ servers = get_ruv(realm, host, dirman_passwd, nolookup) for (netloc, rid) in servers: print "%s: %s" % (netloc, rid) def get_rid_by_host(realm, sourcehost, host, dirman_passwd, nolookup=False): """ Try to determine the RID by host name. """ servers = get_ruv(realm, sourcehost, dirman_passwd, nolookup) for (netloc, rid) in servers: if '%s:389' % host == netloc: return int(rid) def clean_ruv(realm, ruv, options): """ Given an RID create a CLEANALLRUV task to clean it up. """ try: ruv = int(ruv) except ValueError: sys.exit("Replica ID must be an integer: %s" % ruv) servers = get_ruv(realm, options.host, options.dirman_passwd, options.nolookup) found = False for (netloc, rid) in servers: if ruv == int(rid): found = True hostname = netloc break if not found: sys.exit("Replica ID %s not found" % ruv) print "Clean the Replication Update Vector for %s" % hostname print print "Cleaning the wrong replica ID will cause that server to no" print "longer replicate so it may miss updates while the process" print "is running. It would need to be re-initialized to maintain" print "consistency. Be very careful." if not options.force and not ipautil.user_input("Continue to clean?", False): sys.exit("Aborted") thisrepl = replication.ReplicationManager(realm, options.host, options.dirman_passwd) thisrepl.cleanallruv(ruv) print "Cleanup task created" def abort_clean_ruv(realm, ruv, options): """ Given an RID abort a CLEANALLRUV task. """ try: ruv = int(ruv) except ValueError: sys.exit("Replica ID must be an integer: %s" % ruv) servers = get_ruv(realm, options.host, options.dirman_passwd, options.nolookup) found = False for (netloc, rid) in servers: if ruv == int(rid): found = True hostname = netloc break if not found: sys.exit("Replica ID %s not found" % ruv) servers = get_ruv(realm, options.host, options.dirman_passwd, options.nolookup) found = False for (netloc, rid) in servers: if ruv == int(rid): found = True hostname = netloc break if not found: sys.exit("Replica ID %s not found" % ruv) print "Aborting the clean Replication Update Vector task for %s" % hostname print thisrepl = replication.ReplicationManager(realm, options.host, options.dirman_passwd) thisrepl.abortcleanallruv(ruv) print "Cleanup task stopped" def list_clean_ruv(realm, host, dirman_passwd, verbose, nolookup=False): """ List all clean RUV tasks. """ if not nolookup: enforce_host_existence(host) repl = replication.ReplicationManager(realm, host, dirman_passwd) dn = DN(('cn', 'cleanallruv'),('cn', 'tasks'), ('cn', 'config')) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL) except errors.NotFound: print "No CLEANALLRUV tasks running" else: print "CLEANALLRUV tasks" for entry in entries: name = entry.single_value('cn').replace('clean ', '') status = entry.single_value('nsTaskStatus', None) print "RID %s: %s" % (name, status) if verbose: print str(dn) print entry.single_value('nstasklog', None) print dn = DN(('cn', 'abort cleanallruv'),('cn', 'tasks'), ('cn', 'config')) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL) except errors.NotFound: print "No abort CLEANALLRUV tasks running" else: print "Abort CLEANALLRUV tasks" for entry in entries: name = entry.single_value('cn').replace('abort ', '') status = entry.single_value('nsTaskStatus', None) print "RID %s: %s" % (name, status) if verbose: print str(dn) print entry.single_value('nstasklog', None) def check_last_link(delrepl, realm, dirman_passwd, force): """ We don't want to orphan a server when deleting another one. If you have a topology that looks like this: A B | | | | | | C---- D If we try to delete host D it will orphan host B. What we need to do is if the master being deleted has only a single agreement, connect to that master and make sure it has agreements with more than just this master. @delrepl: a ReplicationManager object of the master being deleted returns: hostname of orphaned server or None """ replica_entries = delrepl.find_ipa_replication_agreements() replica_names = [rep.single_value('nsds5replicahost', None) for rep in replica_entries] orphaned = [] # Connect to each remote server and see what agreements it has for replica in replica_names: try: repl = replication.ReplicationManager(realm, replica, dirman_passwd) except errors.NetworkError: print "Unable to validate that '%s' will not be orphaned." % replica if not force and not ipautil.user_input("Continue to delete?", False): sys.exit("Aborted") continue entries = repl.find_ipa_replication_agreements() names = [rep.single_value('nsds5replicahost', None) for rep in entries] if len(names) == 1 and names[0] == delrepl.hostname: orphaned.append(replica) if len(orphaned): return ', '.join(orphaned) else: return None def enforce_host_existence(host, message=None): if host is not None and not ipautil.host_exists(host): if message is None: message = "Unknown host %s" % host sys.exit(message) def del_master(realm, hostname, options): force_del = False delrepl = None # 1. Connect to the local server try: thisrepl = replication.ReplicationManager(realm, options.host, options.dirman_passwd) except Exception, e: print "Failed to connect to server %s: %s" % (options.host, e) sys.exit(1) # 2. Ensure we have an agreement with the master agreement = thisrepl.get_replication_agreement(hostname) if agreement is None: if options.cleanup: """ We have no agreement with the current master, so this is a candidate for cleanup. This is VERY dangerous to do because it removes that master from the list of masters. If the master were to try to come back online it wouldn't work at all. """ print "Cleaning a master is irreversible." print "This should not normally be require, so use cautiously." if not ipautil.user_input("Continue to clean master?", False): sys.exit("Cleanup aborted") thisrepl.replica_cleanup(hostname, realm, force=True) sys.exit(0) else: sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname)) # 3. If an IPA agreement connect to the master to be removed. repltype = thisrepl.get_agreement_type(hostname) if repltype == replication.IPA_REPLICA: winsync = False try: delrepl = replication.ReplicationManager(realm, hostname, options.dirman_passwd) except Exception, e: print "Connection to '%s' failed: %s" % (hostname, e) if not options.force: print "Unable to delete replica '%s'" % hostname sys.exit(1) else: print "Forcing removal of %s" % hostname force_del = True if force_del: dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), thisrepl.suffix) entries = thisrepl.conn.get_entries( dn, thisrepl.conn.SCOPE_ONELEVEL) replica_names = [] for entry in entries: replica_names.append(entry.single_value('cn')) # The host we're removing gets included in this list, remove it. # Otherwise we try to delete an agreement from the host to itself. try: replica_names.remove(hostname) except ValueError: pass else: # Get list of agreements. replica_entries = delrepl.find_ipa_replication_agreements() replica_names = [rep.single_value('nsds5replicahost', None) for rep in replica_entries] else: # WINSYNC replica, delete agreement from current host winsync = True replica_names = [options.host] if not winsync and not options.force: print "Deleting a master is irreversible." print "To reconnect to the remote master you will need to prepare " \ "a new replica file" print "and re-install." if not ipautil.user_input("Continue to delete?", False): sys.exit("Deletion aborted") # Check for orphans if the remote server is up. if delrepl and not winsync: masters_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) try: masters = delrepl.conn.get_entries( masters_dn, delrepl.conn.SCOPE_ONELEVEL) except Exception, e: masters = [] print "Failed to read masters data from '%s': %s" % ( delrepl.hostname, e) print "Skipping calculation to determine if one or more masters would be orphaned." if not options.force: sys.exit(1) # This only applies if we have more than 2 IPA servers, otherwise # there is no chance of an orphan. if len(masters) > 2: orphaned_server = check_last_link(delrepl, realm, options.dirman_passwd, options.force) if orphaned_server is not None: print "Deleting this server will orphan '%s'. " % orphaned_server print "You will need to reconfigure your replication topology to delete this server." sys.exit(1) # Check that we are not leaving the installation without CA and/or DNS this_services = [] other_services = [] for master_cn in [m.single_value('cn') for m in masters]: master_dn = DN(('cn', master_cn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm)) try: services = delrepl.conn.get_entries(master_dn, delrepl.conn.SCOPE_ONELEVEL) except errors.NotFound: continue services_cns = [s.single_value('cn') for s in services] if master_cn == hostname: this_services = services_cns else: other_services.append(services_cns) if 'CA' in this_services and not any(['CA' in o for o in other_services]): print "Deleting this server is not allowed as it would leave your installation without a CA." sys.exit(1) if 'DNS' in this_services and not any(['DNS' in o for o in other_services]): print "Deleting this server will leave your installation without a DNS." if not options.force and not ipautil.user_input("Continue to delete?", False): sys.exit("Deletion aborted") else: print "Skipping calculation to determine if one or more masters would be orphaned." # Save the RID value before we start deleting if repltype == replication.IPA_REPLICA: rid = get_rid_by_host(realm, options.host, hostname, options.dirman_passwd, options.nolookup) # 4. Remove each agreement print "Deleting replication agreements between %s and %s" % (hostname, ', '.join(replica_names)) for r in replica_names: try: if not del_link(realm, r, hostname, options.dirman_passwd, force=True): print "Unable to remove replication agreement for %s from %s." % (hostname, r) except Exception, e: print ("There were issues removing a connection for %s " "from %s: %s" % (hostname, r, e)) # 5. Clean RUV for the deleted master if repltype == replication.IPA_REPLICA and rid is not None: try: thisrepl.cleanallruv(rid) except KeyboardInterrupt: print "Wait for task interrupted. It will continue to run in the background" # 6. Finally clean up the removed replica common entries. try: thisrepl.replica_cleanup(hostname, realm, force=True) except Exception, e: print "Failed to cleanup %s entries: %s" % (hostname, e) print "You may need to manually remove them from the tree" # 7. And clean up the removed replica DNS entries if any. try: if bindinstance.dns_container_exists(options.host, thisrepl.suffix, dm_password=options.dirman_passwd): if options.dirman_passwd: api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=options.dirman_passwd) else: ccache = krbV.default_context().default_ccache() api.Backend.ldap2.connect(ccache=ccache) bind = bindinstance.BindInstance() bind.remove_master_dns_records(hostname, realm, realm.lower()) bind.remove_ipa_ca_dns_records(hostname, realm.lower()) except Exception, e: print "Failed to cleanup %s DNS entries: %s" % (hostname, e) print "You may need to manually remove them from the tree" def add_link(realm, replica1, replica2, dirman_passwd, options): if not options.nolookup: for check_host in [replica1,replica2]: enforce_host_existence(check_host) if options.winsync: if not options.binddn or not options.bindpw or not options.cacert or not options.passsync: root_logger.error("The arguments --binddn, --bindpw, --passsync and --cacert are required to create a winsync agreement") sys.exit(1) if os.getegid() != 0: root_logger.error("winsync agreements need to be created as root") sys.exit(1) try: repl = replication.ReplicationManager(realm, replica1, dirman_passwd) except errors.NotFound: print "Cannot find replica '%s'" % replica1 return except Exception, e: print "Failed to connect to '%s': %s" % (replica1, e) return # See if we already have an agreement with this host try: if repl.get_agreement_type(replica2) == replication.WINSYNC: agreement = repl.get_replication_agreement(replica2) sys.exit("winsync agreement already exists on subtree %s" % agreement.single_value('nsds7WindowsReplicaSubtree', None)) else: sys.exit("A replication agreement to %s already exists" % replica2) except errors.NotFound: pass if options.cacert: # have to install the given CA cert before doing anything else ds = dsinstance.DsInstance(realm_name = realm, dm_password = dirman_passwd) if not ds.add_ca_cert(options.cacert): print "Could not load the required CA certificate file [%s]" % options.cacert return else: print "Added CA certificate %s to certificate database for %s" % (options.cacert, replica1) # need to wait until cacert is installed as that command may restart # the directory server and kill the connection try: repl1 = replication.ReplicationManager(realm, replica1, dirman_passwd) except errors.NotFound: print "Cannot find replica '%s'" % replica1 return except Exception, e: print "Failed to connect to '%s': %s" % (replica1, e) return if options.winsync: repl1.setup_winsync_replication(replica2, options.binddn, options.bindpw, options.passsync, options.win_subtree, options.cacert) else: # 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 = DN(('cn', replica1), masters_dn) master2_dn = DN(('cn', replica2), masters_dn) repl1.conn.get_entry(master1_dn) repl1.conn.get_entry(master2_dn) repl2 = replication.ReplicationManager(realm, replica2, dirman_passwd) repl2.conn.get_entry(master1_dn) repl2.conn.get_entry(master2_dn) except errors.NotFound: standard_logging_setup(console_format='%(message)s') ds = ipadiscovery.IPADiscovery() ret = ds.search(servers=[replica2]) if ret == ipadiscovery.NOT_IPA_SERVER: sys.exit("Connection unsuccessful: %s is not an IPA Server." % replica2) elif ret == 0: # success sys.exit("Connection unsuccessful: %s is an IPA Server, " "but it might be unknown, foreign or previously deleted " "one." % replica2) else: sys.exit("Connection to %s unsuccessful." % replica2) repl1.setup_gssapi_replication(replica2, DN(('cn', 'Directory Manager')), dirman_passwd) print "Connected '%s' to '%s'" % (replica1, replica2) def re_initialize(realm, thishost, fromhost, dirman_passwd, nolookup=False): if not nolookup: for check_host in [thishost, fromhost]: enforce_host_existence(check_host) thisrepl = replication.ReplicationManager(realm, thishost, dirman_passwd) agreement = thisrepl.get_replication_agreement(fromhost) if agreement is None: sys.exit("'%s' has no replication agreement for '%s'" % (thishost, fromhost)) repltype = thisrepl.get_agreement_type(fromhost) if repltype == replication.WINSYNC: # With winsync we don't have a "remote" agreement, it is all local repl = replication.ReplicationManager(realm, thishost, dirman_passwd) repl.initialize_replication(agreement.dn, repl.conn) repl.wait_for_repl_init(repl.conn, agreement.dn) else: repl = replication.ReplicationManager(realm, fromhost, dirman_passwd) agreement = repl.get_replication_agreement(thishost) thisrepl.enable_agreement(fromhost) repl.enable_agreement(thishost) repl.force_sync(repl.conn, thishost) repl.initialize_replication(agreement.dn, repl.conn) repl.wait_for_repl_init(repl.conn, agreement.dn) # If the agreement doesn't have nsDS5ReplicatedAttributeListTotal it means # we did not replicate memberOf, do so now. if not agreement.single_value('nsDS5ReplicatedAttributeListTotal', None): ds = dsinstance.DsInstance(realm_name = realm, dm_password = dirman_passwd) ds.ldapi = os.getegid() == 0 ds.init_memberof() def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False): if not nolookup: for check_host in [thishost, fromhost]: enforce_host_existence(check_host) thisrepl = replication.ReplicationManager(realm, thishost, dirman_passwd) agreement = thisrepl.get_replication_agreement(fromhost) if agreement is None: sys.exit("'%s' has no replication agreement for '%s'" % (thishost, fromhost)) repltype = thisrepl.get_agreement_type(fromhost) if repltype == replication.WINSYNC: # With winsync we don't have a "remote" agreement, it is all local repl = replication.ReplicationManager(realm, thishost, dirman_passwd) repl.force_sync(repl.conn, fromhost) else: repl = replication.ReplicationManager(realm, fromhost, dirman_passwd) repl.force_sync(repl.conn, thishost) def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False, nolookup=False): """ Display the DNA ranges for all current masters. hostname: hostname of the master we're listing from master: specific master to show, or None for all realm: our realm, needed to create a connection dirman_passwd: the DM password, needed to create a connection nextrange: if False then show main range, if True then show next Returns nothing """ if not nolookup: enforce_host_existence(hostname) if master is not None: enforce_host_existence(master) try: repl = replication.ReplicationManager(realm, hostname, dirman_passwd) except Exception, e: sys.exit("Connection failed: %s" % e) dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), repl.suffix) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL) except Exception: return False for ent in entries: remote = ent.single_value('cn') if master is not None and remote != master: continue try: repl2 = replication.ReplicationManager(realm, remote, dirman_passwd) except Exception, e: print "%s: Connection failed: %s" % (remote, e) continue if not nextrange: try: (start, max) = repl2.get_DNA_range(remote) except errors.NotFound: print "%s: No permission to read DNA configuration" % remote continue if start is None: print "%s: No range set" % remote else: print "%s: %s-%s" % (remote, start, max) else: try: (next_start, next_max) = repl2.get_DNA_next_range(remote) except errors.NotFound: print "%s: No permission to read DNA configuration" % remote continue if next_start is None: print "%s: No on-deck range set" % remote else: print "%s: %s-%s" % (remote, next_start, next_max) return False def store_DNA_range(repl, range_start, range_max, deleted_master, realm, dirman_passwd): """ Given a DNA range try to save it in a remaining master in the on-deck (dnaNextRange) value. Return True if range was saved, False if not This function focuses on finding an available master. repl: ReplicaMaster object for the master we're deleting from range_start: The DNA next value range_max: The DNA max value deleted_master: The hostname of the master to be deleted realm: our realm, needed to create a connection dirman_passwd: the DM password, needed to create a connection """ dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), repl.suffix) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL) except Exception: return False for ent in entries: candidate = ent.single_value('cn') if candidate == deleted_master: continue try: repl2 = replication.ReplicationManager(realm, candidate, dirman_passwd) except Exception, e: print "Connection failed: %s" % e continue (next_start, next_max) = repl2.get_DNA_next_range(candidate) if next_start is None: try: return repl2.save_DNA_next_range(range_start, range_max) except Exception, e: print '%s: %s' % (candidate, e) return False def set_DNA_range(hostname, range, realm, dirman_passwd, next_range=False, nolookup=False): """ Given a DNA range try to change it on the designated master. The range must not overlap with any other ranges and must be within one of the IPA local ranges as defined in cn=ranges. Setting an on-deck range of 0-0 removes the range. Return True if range was saved, False if not hostname: hostname of the master to set the range on range: The DNA range to set realm: our realm, needed to create a connection dirman_passwd: the DM password, needed to create a connection next_range: if True then setting a next-range, otherwise a DNA range. """ def validate_range(range, allow_all_zero=False): """ Do some basic sanity checking on the range. Returns None if ok, a string if an error. """ try: (dna_next, dna_max) = range.split('-', 1) except ValueError, e: return "Invalid range, must be the form x-y" try: dna_next = int(dna_next) dna_max = int(dna_max) except ValueError: return "The range must consist of integers" if dna_next == 0 and dna_max == 0 and allow_all_zero: return None if dna_next <= 0 or dna_max <= 0 or dna_next >= MAXINT or dna_max >= MAXINT: return "The range must consist of positive integers between 1 and %d" % MAXINT if dna_next >= dna_max: return "Invalid range" return None def range_intersection(s1, s2, r1, r2): return max(s1, r1) <= min(s2, r2) if not nolookup: enforce_host_existence(hostname) err = validate_range(range, allow_all_zero=next_range) if err is not None: sys.exit(err) # Normalize the range (dna_next, dna_max) = range.split('-', 1) dna_next = int(dna_next) dna_max = int(dna_max) try: repl = replication.ReplicationManager(realm, hostname, dirman_passwd) except Exception, e: sys.exit("Connection failed: %s" % e) if dna_next > 0: # Verify that the new range doesn't overlap with an existing range dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), repl.suffix) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL) except Exception, e: sys.exit("Failed to read master data from '%s': %s" % (repl.conn.host, str(e))) else: for ent in entries: master = ent.single_value('cn') if master == hostname and not next_range: continue try: repl2 = replication.ReplicationManager(realm, master, dirman_passwd) except Exception, e: print "Connection to %s failed: %s" % (master, e) print "Overlap not checked." continue try: (entry_start, entry_max) = repl2.get_DNA_range(master) except errors.NotFound: print "%s: No permission to read DNA configuration" % master continue if (entry_start is not None and range_intersection(entry_start, entry_max, dna_next, dna_max)): sys.exit("New range overlaps the DNA range on %s" % master) (entry_start, entry_max) = repl2.get_DNA_next_range(master) if (entry_start is not None and range_intersection(entry_start, entry_max, dna_next, dna_max)): sys.exit("New range overlaps the DNA next range on %s" % master) del(repl2) # Verify that this is within one of the IPA domain ranges. dn = DN(('cn','ranges'), ('cn','etc'), repl.suffix) try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_ONELEVEL, "(objectclass=ipaDomainIDRange)") except errors.NotFound, e: sys.exit('Unable to load IPA ranges: %s' % e.message) for ent in entries: entry_start = int(ent.single_value('ipabaseid')) entry_max = entry_start + int(ent.single_value('ipaidrangesize')) if dna_next >= entry_start and dna_max <= entry_max: break else: sys.exit("New range does not fit within existing IPA ranges. See ipa help idrange command") # If this falls within any of the AD ranges then it fails. try: entries = repl.conn.get_entries(dn, repl.conn.SCOPE_BASE, "(objectclass=ipatrustedaddomainrange)") except errors.NotFound: entries = [] for ent in entries: entry_start = int(ent.single_value('ipabaseid')) entry_max = entry_start + int(ent.single_value('ipaidrangesize')) if range_intersection(dna_next, dna_max, entry_start, entry_max): sys.exit("New range overlaps with a Trust range. See ipa help idrange command") if next_range: try: if not repl.save_DNA_next_range(dna_next, dna_max): sys.exit("Updating next range failed") except errors.EmptyModlist: sys.exit("No changes to make") except errors.NotFound: sys.exit("No permission to update ranges") except Exception, e: sys.exit("Updating next range failed: %s" % e) else: try: if not repl.save_DNA_range(dna_next, dna_max): sys.exit("Updating range failed") except errors.EmptyModlist: sys.exit("No changes to make") except errors.NotFound: sys.exit("No permission to update ranges") except Exception, e: sys.exit("Updating range failed: %s" % e) def main(): if os.getegid() == 0: installutils.check_server_configuration() elif not os.path.exists('/etc/ipa/default.conf'): sys.exit("IPA is not configured on this system.") options, args = parse_options() # Just initialize the environment. This is so the installer can have # access to the plugin environment api_env = {'in_server' : True, 'verbose' : options.verbose, } if os.getegid() != 0: api_env['log'] = None # turn off logging for non-root api.bootstrap(**api_env) api.finalize() dirman_passwd = None realm = krbV.default_context().default_realm if options.host: host = options.host else: host = installutils.get_fqdn() options.host = host if options.dirman_passwd: dirman_passwd = options.dirman_passwd else: if not test_connection(realm, host, options.nolookup): dirman_passwd = installutils.read_password("Directory Manager", confirm=False, validate=False, retry=False) if dirman_passwd is None: sys.exit("Directory Manager password required") options.dirman_passwd = dirman_passwd if args[0] == "list": replica = None if len(args) == 2: replica = args[1] list_replicas(realm, host, replica, dirman_passwd, options.verbose, options.nolookup) elif args[0] == "list-ruv": list_ruv(realm, host, dirman_passwd, options.verbose, options.nolookup) elif args[0] == "del": del_master(realm, args[1], options) elif args[0] == "re-initialize": if not options.fromhost: print "re-initialize requires the option --from " sys.exit(1) re_initialize(realm, host, options.fromhost, dirman_passwd, options.nolookup) elif args[0] == "force-sync": if not options.fromhost: print "force-sync requires the option --from " sys.exit(1) force_sync(realm, host, options.fromhost, options.dirman_passwd, options.nolookup) elif args[0] == "connect": if len(args) == 3: replica1 = args[1] replica2 = args[2] elif len(args) == 2: replica1 = host replica2 = args[1] add_link(realm, replica1, replica2, dirman_passwd, options) elif args[0] == "disconnect": if len(args) == 3: replica1 = args[1] replica2 = args[2] elif len(args) == 2: replica1 = host replica2 = args[1] del_link(realm, replica1, replica2, dirman_passwd) elif args[0] == "clean-ruv": clean_ruv(realm, args[1], options) elif args[0] == "abort-clean-ruv": abort_clean_ruv(realm, args[1], options) elif args[0] == "list-clean-ruv": list_clean_ruv(realm, host, dirman_passwd, options.verbose, options.nolookup) elif args[0] == "dnarange-show": if len(args) == 2: master = args[1] else: master = None show_DNA_ranges(host, master, realm, dirman_passwd, False, options.nolookup) elif args[0] == "dnanextrange-show": if len(args) == 2: master = args[1] else: master = None show_DNA_ranges(host, master, realm, dirman_passwd, True, options.nolookup) elif args[0] == "dnarange-set": set_DNA_range(args[1], args[2], realm, dirman_passwd, next_range=False, nolookup=options.nolookup) elif args[0] == "dnanextrange-set": set_DNA_range(args[1], args[2], realm, dirman_passwd, next_range=True, nolookup=options.nolookup) try: main() except KeyboardInterrupt: sys.exit(1) except SystemExit, e: sys.exit(e) except RuntimeError, e: sys.exit(e) except socket.timeout: print "Connection timed out." sys.exit(1) except Exception, e: print "unexpected error: %s" % str(e) sys.exit(1) freeipa-3.3.4/install/tools/Makefile.in0000664000175000017500000005045312271707662017376 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = tools DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(sbindir)" SCRIPTS = $(sbin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = SUBDIRS = \ man \ $(NULL) sbin_SCRIPTS = \ ipa-ca-install \ ipa-dns-install \ ipa-server-install \ ipa-adtrust-install \ ipa-replica-conncheck \ ipa-replica-install \ ipa-replica-prepare \ ipa-replica-manage \ ipa-csreplica-manage \ ipa-server-certinstall \ ipactl \ ipa-compat-manage \ ipa-nis-manage \ ipa-managed-entries \ ipa-ldap-updater \ ipa-upgradeconfig \ ipa-backup \ ipa-restore \ ipa-advise \ $(NULL) EXTRA_DIST = \ README \ $(sbin_SCRIPTS) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-sbinSCRIPTS: $(sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile $(SCRIPTS) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-sbinSCRIPTS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-sbinSCRIPTS .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-sbinSCRIPTS install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-sbinSCRIPTS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/tools/ipa-server-certinstall0000775000175000017500000000157512271663206021652 0ustar mkosekmkosek#! /usr/bin/python -E # Authors: Jan Cholasta # # Copyright (C) 2013 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 . # from ipaserver.install.ipa_server_certinstall import ServerCertInstall ServerCertInstall.run_cli() freeipa-3.3.4/install/conf/0000775000175000017500000000000012271707664015111 5ustar mkosekmkosekfreeipa-3.3.4/install/conf/ipa-pki-proxy.conf0000664000175000017500000000340212271663206020461 0ustar mkosekmkosek# VERSION 3 - DO NOT REMOVE THIS LINE ProxyRequests Off # matches for ee port NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient none ProxyPassMatch ajp://localhost:$DOGTAG_PORT ProxyPassReverse ajp://localhost:$DOGTAG_PORT # matches for admin port and installer NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient none ProxyPassMatch ajp://localhost:$DOGTAG_PORT ProxyPassReverse ajp://localhost:$DOGTAG_PORT # matches for agent port and eeca port NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate NSSVerifyClient require ProxyPassMatch ajp://localhost:$DOGTAG_PORT ProxyPassReverse ajp://localhost:$DOGTAG_PORT # Only enable this on servers that are not generating a CRL ${CLONE}RewriteRule ^/ipa/crl/MasterCRL.bin https://$FQDN/ca/ee/ca/getCRL?op=getCRL&crlIssuingPoint=MasterCRL [L,R=301,NC] freeipa-3.3.4/install/conf/ipa.conf0000664000175000017500000001017512271663206016526 0ustar mkosekmkosek# # VERSION 13 - DO NOT REMOVE THIS LINE # # This file may be overwritten on upgrades. # # LoadModule auth_kerb_module modules/mod_auth_kerb.so ProxyRequests Off #We use xhtml, a file format that the browser validates DirectoryIndex index.html # Substantially increase the request field size to support MS-PAC # requests, ticket #2767. This should easily support a 64KiB PAC. LimitRequestFieldSize 100000 # ipa-rewrite.conf is loaded separately # This is required so the auto-configuration works with Firefox 2+ AddType application/java-archive jar AddType application/x-xpinstall xpi # Proper header for .woff fonts AddType application/x-font-woff woff # Enable compression AddOutputFilterByType DEFLATE text/html text/plain text/xml \ application/javascript application/json text/css # Disable etag http header. Doesn't work well with mod_deflate # https://issues.apache.org/bugzilla/show_bug.cgi?id=45023 # Usage of last-modified header and modified-since validator is sufficient. Header unset ETag FileETag None # FIXME: WSGISocketPrefix is a server-scope directive. The mod_wsgi package # should really be fixed by adding this its /etc/httpd/conf.d/wsgi.conf: WSGISocketPrefix /run/httpd/wsgi # Configure mod_wsgi handler for /ipa WSGIDaemonProcess ipa processes=2 threads=1 maximum-requests=500 WSGIProcessGroup ipa WSGIApplicationGroup ipa WSGIImportScript /usr/share/ipa/wsgi.py process-group=ipa application-group=ipa WSGIScriptAlias /ipa /usr/share/ipa/wsgi.py WSGIScriptReloading Off # Turn off mod_msgi handler for errors, config, crl: SetHandler None SetHandler None SetHandler None KrbConstrainedDelegationLock ipa # Protect /ipa and everything below it in webspace with Apache Kerberos auth AuthType Kerberos AuthName "Kerberos Login" KrbMethodNegotiate on KrbMethodK5Passwd off KrbServiceName HTTP KrbAuthRealms $REALM Krb5KeyTab /etc/httpd/conf/ipa.keytab KrbSaveCredentials on KrbConstrainedDelegation on Require valid-user ErrorDocument 401 /ipa/errors/unauthorized.html # Turn off Apache authentication for sessions Satisfy Any Order Deny,Allow Allow from all Satisfy Any Order Deny,Allow Allow from all Satisfy Any Order Deny,Allow Allow from all Satisfy Any Order Deny,Allow Allow from all # This is where we redirect on failed auth Alias /ipa/errors "/usr/share/ipa/html" # For the MIT Windows config files Alias /ipa/config "/usr/share/ipa/html" # Do no authentication on the directory that contains error messages SetHandler None AllowOverride None Satisfy Any Allow from all # For CRL publishing Alias /ipa/crl "$CRL_PUBLISH_PATH" SetHandler None AllowOverride None Options Indexes FollowSymLinks Satisfy Any Allow from all # webUI is now completely static, and served out of that directory Alias /ipa/ui "/usr/share/ipa/ui" SetHandler None AllowOverride None Satisfy Any Allow from all # Simple wsgi scripts required by ui Alias /ipa/wsgi "/usr/share/ipa/wsgi" AllowOverride None Satisfy Any Allow from all Options ExecCGI AddHandler wsgi-script .py # Protect our CGIs AuthType Kerberos AuthName "Kerberos Login" KrbMethodNegotiate on KrbMethodK5Passwd off KrbServiceName HTTP KrbAuthRealms $REALM Krb5KeyTab /etc/httpd/conf/ipa.keytab KrbSaveCredentials on Require valid-user ErrorDocument 401 /ipa/errors/unauthorized.html # migration related pages Alias /ipa/migration "/usr/share/ipa/migration" AllowOverride None Satisfy Any Allow from all Options ExecCGI AddHandler wsgi-script .py freeipa-3.3.4/install/conf/Makefile.am0000664000175000017500000000055412202434255017134 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR) app_DATA = \ ca_renewal \ ipa.conf \ ipa-pki-proxy.conf \ ipa-rewrite.conf \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/conf/ipa-rewrite.conf0000664000175000017500000000170712271663206020206 0ustar mkosekmkosek# VERSION 6 - DO NOT REMOVE THIS LINE RewriteEngine on # By default forward all requests to /ipa. If you don't want IPA # to be the default on your web server comment this line out. ${AUTOREDIR}RewriteRule ^/$$ https://$FQDN/ipa/ui [L,NC,R=301] # Redirect to the fully-qualified hostname. Not redirecting to secure # port so configuration files can be retrieved without requiring SSL. RewriteCond %{HTTP_HOST} !^$FQDN$$ [NC] RewriteRule ^/ipa/(.*) http://$FQDN/ipa/$$1 [L,R=301] # Redirect to the secure port if not displaying an error or retrieving # configuration. RewriteCond %{SERVER_PORT} !^443$$ RewriteCond %{REQUEST_URI} !^/ipa/(errors|config|crl) RewriteCond %{REQUEST_URI} !^/ipa/[^\?]+(\.js|\.css|\.png|\.gif|\.ico|\.woff|\.svg|\.ttf|\.eot)$$ RewriteRule ^/ipa/(.*) https://$FQDN/ipa/$$1 [L,R=301,NC] # Rewrite for plugin index, make it like it's a static file RewriteRule ^/ipa/ui/js/freeipa/plugins.js$$ /ipa/wsgi/plugins.py [PT] freeipa-3.3.4/install/conf/ca_renewal0000664000175000017500000000035412202434255017121 0ustar mkosekmkosek# A separate helper for fetching dogtag certificates that are renewed on # another system. id=dogtag-ipa-retrieve-agent-submit ca_is_default=0 ca_type=EXTERNAL ca_external_helper=/usr/libexec/certmonger/dogtag-ipa-retrieve-agent-submit freeipa-3.3.4/install/conf/Makefile.in0000664000175000017500000003210712271707662017157 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = conf DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR) app_DATA = \ ca_renewal \ ipa.conf \ ipa-pki-proxy.conf \ ipa-rewrite.conf \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign conf/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign conf/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/configure.ac0000664000175000017500000000472712271663206016455 0ustar mkosekmkosekAC_PREREQ(2.59) m4_include(../version.m4) AC_INIT([ipa-server], IPA_VERSION, [https://hosted.fedoraproject.org/projects/freeipa/newticket]) #AC_CONFIG_SRCDIR([ipaserver/ipaldap.py]) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign]) AM_MAINTAINER_MODE #AC_PROG_CC #AC_STDC_HEADERS #AC_DISABLE_STATIC #AC_PROG_LIBTOOL #AC_HEADER_STDC AC_SUBST(VERSION) AC_SUBST([INSTALL_DATA], ['$(INSTALL) -m 644 -p']) AC_PROG_MKDIR_P AC_PROG_AWK AC_PROG_SED AC_PATH_PROG(XGETTEXT, xgettext, [no]) if test "x$XGETTEXT" = "xno"; then AC_MSG_ERROR([xgettext not found, install gettext]) fi AC_PATH_PROG(MSGFMT, msgfmt, [no]) if test "x$MSGFMT" = "xno"; then AC_MSG_ERROR([msgfmt not found, install gettext]) fi AC_PATH_PROG(MSGINIT, msginit, [no]) if test "x$MSGINIT" = "xno"; then AC_MSG_ERROR([msginit not found, install gettext]) fi AC_PATH_PROG(MSGMERGE, msgmerge, [no]) if test "x$MSGMERGE" = "xno"; then AC_MSG_ERROR([msgmerge not found, install gettext]) fi AC_PATH_PROG(MSGCMP, msgcmp, [no]) 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], [AS_HELP_STRING([--with-gettext-domain=name], [set the name of the i18n message catalog])], [], [with_gettext_domain=ipa]) AC_SUBST(GETTEXT_DOMAIN, $with_gettext_domain) dnl --------------------------------------------------------------------------- dnl - Set the data install directory since we don't use pkgdatadir dnl --------------------------------------------------------------------------- IPA_DATA_DIR="$datadir/ipa" IPA_SYSCONF_DIR="$sysconfdir/ipa" AC_SUBST(IPA_DATA_DIR) AC_SUBST(IPA_SYSCONF_DIR) # Files AC_CONFIG_FILES([ Makefile certmonger/Makefile conf/Makefile ffextension/Makefile ffextension/chrome/Makefile ffextension/chrome/content/Makefile ffextension/locale/Makefile ffextension/locale/en-US/Makefile html/Makefile migration/Makefile share/Makefile share/advise/Makefile share/advise/legacy/Makefile ui/Makefile ui/src/Makefile ui/src/libs/Makefile ui/images/Makefile ui/build/Makefile ui/build/dojo/Makefile ui/build/freeipa/Makefile tools/Makefile tools/man/Makefile updates/Makefile po/Makefile restart_scripts/Makefile wsgi/Makefile ]) AC_OUTPUT freeipa-3.3.4/install/missing0000755000175000017500000001533112271707662015562 0ustar mkosekmkosek#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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 2, 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 . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: freeipa-3.3.4/install/config.h.in~0000664000175000017500000000116112271707531016375 0ustar mkosekmkosek/* config.h.in. Generated from configure.ac by autoheader. */ /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Version number of package */ #undef VERSION freeipa-3.3.4/install/Makefile.am0000664000175000017500000000231012271663206016205 0ustar mkosekmkosek# This file will be processed with automake-1.7 to create Makefile.in # AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = \ certmonger \ conf \ ffextension \ html \ migration \ share \ ui \ tools \ updates \ po \ restart_scripts \ wsgi \ $(NULL) install-exec-local: mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/pki-ca chmod 755 $(DESTDIR)$(localstatedir)/lib/ipa/pki-ca uninstall-local: -rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore -rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysupgrade -rmdir $(DESTDIR)$(localstatedir)/lib/ipa DISTCLEANFILES = \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ intltool-*.in \ compile \ configure \ COPYING \ INSTALL \ install-sh \ missing \ mkinstalldirs \ config.guess \ ltmain.sh \ config.sub \ depcomp \ Makefile.in \ config.h.* \ aclocal.m4 \ version.m4 \ ipa-client.spec \ py-compile \ $(NULL) freeipa-3.3.4/install/updates/0000775000175000017500000000000012271707664015631 5ustar mkosekmkosekfreeipa-3.3.4/install/updates/20-dna.update0000664000175000017500000000070412271663206020010 0ustar mkosekmkosek# Enable the DNA plugin dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config only:nsslapd-pluginEnabled: on # Change the magic value to -1 dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config only:dnaMagicRegen: -1 dn: cn=ipa-winsync,cn=plugins,cn=config remove:ipaWinSyncUserAttr: uidNumber 999 remove:ipaWinSyncUserAttr: gidNumber 999 add:ipaWinSyncUserAttr: uidNumber -1 add:ipaWinSyncUserAttr: gidNumber -1 freeipa-3.3.4/install/updates/40-otp.update0000664000175000017500000000205312271663206020051 0ustar mkosekmkosekdn: cn=otp,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: otp dn: $SUFFIX add: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "objectclass || ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can read basic token info"; allow (read, search, compare) userattr = "ipatokenOwner#USERDN";)' add: aci:'(targetfilter = "(objectClass=ipaToken)")(targetattrs = "ipatokenUniqueID || description || ipatokenOwner || ipatokenNotBefore || ipatokenNotAfter || ipatokenVendor || ipatokenModel || ipatokenSerial")(version 3.0; acl "Users can write basic token info"; allow (write) userattr = "ipatokenOwner#USERDN";)' add: aci:'(targetfilter = "(objectClass=ipatokenTOTP)")(targetattrs = "ipatokenOTPkey || ipatokenOTPalgorithm || ipatokenOTPdigits || ipatokenTOTPclockOffset || ipatokenTOTPtimeStep")(version 3.0; acl "Users can add TOTP token secrets"; allow (write, search) userattr = "ipatokenOwner#USERDN";)' freeipa-3.3.4/install/updates/21-replicas_container.update0000664000175000017500000000023112202434255023100 0ustar mkosekmkosek# # Add replicas container if not available # dn: cn=replicas,cn=ipa,cn=etc,$SUFFIX add:objectClass: top add:objectClass: nsContainer add:cn: replicas freeipa-3.3.4/install/updates/40-automember.update0000664000175000017500000000143512202434255021404 0ustar mkosekmkosek# Add all supported automember LDAP objects dn: cn=Auto Membership Plugin,cn=plugins,cn=config addifnew: nsslapd-pluginConfigArea: 'cn=automember,cn=etc,$SUFFIX' dn: cn=automember,cn=etc,$SUFFIX default: objectClass: top default: objectClass: nsContainer default: cn: automember dn: cn=Hostgroup,cn=automember,cn=etc,$SUFFIX default: objectclass: autoMemberDefinition default: cn: Hostgroup default: autoMemberScope: cn=computers,cn=accounts,$SUFFIX default: autoMemberFilter: objectclass=ipaHost default: autoMemberGroupingAttr: member:dn dn: cn=Group,cn=automember,cn=etc,$SUFFIX default: objectclass: autoMemberDefinition default: cn: Group default: autoMemberScope: cn=users,cn=accounts,$SUFFIX default: autoMemberFilter: objectclass=posixAccount default: autoMemberGroupingAttr: member:dn freeipa-3.3.4/install/updates/10-RFC4876.update0000664000175000017500000001250712270466515020217 0ustar mkosekmkosek# # Schema more or less verbatim from RFC 4876: # "A Configuration Profile Schema for Lightweight Directory Access # Protocol (LDAP)-Based Agents" # dn: cn=schema add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.0 NAME 'defaultServerList' DESC 'List of default servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.1 NAME 'defaultSearchBase' DESC 'Default base for searches' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.2 NAME 'preferredServerList' DESC 'List of preferred servers' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.3 NAME 'searchTimeLimit' DESC 'Maximum time an agent or service allows for a search to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.4 NAME 'bindTimeLimit' DESC 'Maximum time an agent or service allows for a bind operation to complete' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.5 NAME 'followReferrals' DESC 'An agent or service does or should follow referrals' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.6 NAME 'authenticationMethod' DESC 'Identifies the types of authentication methods either used, required, or provided by a service or peer' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.7 NAME 'profileTTL' DESC 'Time to live, in seconds, before a profile is considered stale' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.9 NAME 'attributeMap' DESC 'Attribute mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.10 NAME 'credentialLevel' DESC 'Identifies type of credentials either used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.11 NAME 'objectclassMap' DESC 'Object class mappings used, required, or supported by an agent or service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC4876' )" add:attributeTypes: ( 1.3.6.1.4.1.11.1.3.1.1.12 NAME 'defaultSearchScope' DESC 'Default scope used when performing a search' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC4876' ) add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.13 NAME 'serviceCredentialLevel' DESC 'Specifies the type of credentials either used, required, or supported by a specific service' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.14 NAME 'serviceSearchDescriptor' DESC 'Specifies search descriptors required, used, or supported by a particular service or agent' EQUALITY caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.15 NAME 'serviceAuthenticationMethod' DESC 'Specifies types authentication methods either used, required, or supported by a particular service' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC4876' )" add:attributeTypes:" ( 1.3.6.1.4.1.11.1.3.1.1.16 NAME 'dereferenceAliases' DESC 'Specifies if a service or agent either requires, supports, or uses dereferencing of aliases.' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'RFC4876' )" add:objectClasses: ( 1.3.6.1.4.1.11.1.3.1.2.5 NAME 'DUAConfigProfile' SUP top STRUCTURAL DESC 'Abstraction of a base configuration for a DUA' MUST ( cn ) MAY ( defaultServerList $$ preferredServerList $$ defaultSearchBase $$ defaultSearchScope $$ searchTimeLimit $$ bindTimeLimit $$ credentialLevel $$ authenticationMethod $$ followReferrals $$ dereferenceAliases $$ serviceSearchDescriptor $$ serviceCredentialLevel $$ serviceAuthenticationMethod $$ objectclassMap $$ attributeMap $$ profileTTL ) X-ORIGIN 'RFC4876' ) freeipa-3.3.4/install/updates/45-roles.update0000664000175000017500000000676112202434255020404 0ustar mkosekmkosek# Helpdesk roles dn: cn=Modify Users and Reset passwords,cn=privileges,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: nestedgroup default:cn: Modify Users and Reset passwords default:description: Modify Users and Reset passwords default:member: cn=helpdesk,cn=roles,cn=accounts,$SUFFIX dn: cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX add:member: 'cn=Modify Users and Reset passwords,cn=privileges,cn=pbac,$SUFFIX' dn: cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX add:member: 'cn=Modify Users and Reset passwords,cn=privileges,cn=pbac,$SUFFIX' dn: cn=Modify Group membership,cn=privileges,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: nestedgroup default:cn: Modify Group membership default:description: Modify Group membership default:member: cn=helpdesk,cn=roles,cn=accounts,$SUFFIX dn: cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX add:member: 'cn=Modify Group membership,cn=privileges,cn=pbac,$SUFFIX' dn: cn=User Administrator,cn=roles,cn=accounts,$SUFFIX default:objectClass: groupofnames default:objectClass: nestedgroup default:objectClass: top default:cn: User Administrator default:description: Responsible for creating Users and Groups dn: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX add: member: 'cn=User Administrator,cn=roles,cn=accounts,$SUFFIX' dn: cn=Group Administrators,cn=privileges,cn=pbac,$SUFFIX add: member: 'cn=User Administrator,cn=roles,cn=accounts,$SUFFIX' dn: cn=IT Specialist,cn=roles,cn=accounts,$SUFFIX default:objectClass: groupofnames default:objectClass: nestedgroup default:objectClass: top default:cn: IT Specialist default:description: IT Specialist dn: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=Host Group Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=Service Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=Automount Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=IT Security Specialist,cn=roles,cn=accounts,$SUFFIX default:objectClass: groupofnames default:objectClass: nestedgroup default:objectClass: top default:cn: IT Security Specialist default:description: IT Security Specialist dn: cn=Netgroups Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Security Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Security Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=Sudo administrator,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=IT Security Specialist,cn=roles,cn=accounts,$SUFFIX' dn: cn=Security Architect,cn=roles,cn=accounts,$SUFFIX default:objectClass: groupofnames default:objectClass: nestedgroup default:objectClass: top default:cn: Security Architect default:description: Security Architect dn: cn=Delegation Administrator,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=Security Architect,cn=roles,cn=accounts,$SUFFIX' dn: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=Security Architect,cn=roles,cn=accounts,$SUFFIX' dn: cn=Write IPA Configuration,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=Security Architect,cn=roles,cn=accounts,$SUFFIX' dn: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=Security Architect,cn=roles,cn=accounts,$SUFFIX' freeipa-3.3.4/install/updates/25-referint.update0000664000175000017500000000106412270466515021074 0ustar mkosekmkosek# Expand attributes checked by Referential Integrity plugin # pres and eq indexes defined in 20-indices.update must be set for all these # attributes dn: cn=referential integrity postoperation,cn=plugins,cn=config add: nsslapd-pluginArg9: memberuser add: nsslapd-pluginArg10: memberhost add: nsslapd-pluginArg11: sourcehost add: nsslapd-pluginArg12: memberservice add: nsslapd-pluginArg13: managedby add: nsslapd-pluginArg14: memberallowcmd add: nsslapd-pluginArg15: memberdenycmd add: nsslapd-pluginArg16: ipasudorunas add: nsslapd-pluginArg17: ipasudorunasgroup freeipa-3.3.4/install/updates/20-aci.update0000664000175000017500000000215112202434255017772 0ustar mkosekmkosek# Don't allow managed netgroups to be modified dn: cn=ng,cn=alt,$SUFFIX add:aci: '(targetfilter = "(objectClass=mepManagedEntry)")(targetattr = "*")(version 3.0; acl "Managed netgroups cannot be modified"; deny (write) userdn = "ldap:///all";)' # This is used for the host/service one-time passwordn and keytab indirectors. # We can do a query on a DN to see if an attribute exists. dn: cn=accounts,$SUFFIX add:aci: (targetattr="userPassword || krbPrincipalKey")(version 3.0; acl "Search existence of password and kerberos keys"; allow(search) userdn = "ldap:///all";) # SSH public keys dn: $SUFFIX add:aci:'(targetattr = "ipasshpubkey")(version 3.0;acl "selfservice:Users can manage their own SSH public keys";allow (write) userdn = "ldap:///self";)' dn: cn=computers,cn=accounts,$SUFFIX add:aci:'(targetattr="ipasshpubkey")(version 3.0; acl "Hosts can modify their own SSH public keys"; allow(write) userdn = "ldap:///self";)' dn: cn=computers,cn=accounts,$SUFFIX add:aci:'(targetattr="ipasshpubkey")(version 3.0; acl "Hosts can manage other host SSH public keys"; allow(write) userattr = "parent[0,1].managedby#USERDN";)' freeipa-3.3.4/install/updates/10-bind-schema.update0000664000175000017500000001115212271663206021416 0ustar mkosekmkosek# # New schema enhancements from: # https://fedorahosted.org/bind-dyndb-ldap/browser/doc/schema # dn: cn=schema add:attributeTypes: ( 2.16.840.1.113730.3.8.5.11 NAME 'idnsAllowQuery' DESC 'BIND9 allow-query ACL element' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2') add:attributeTypes: ( 2.16.840.1.113730.3.8.5.12 NAME 'idnsAllowTransfer' DESC 'BIND9 allow-transfer ACL element' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2') add:attributeTypes: ( 2.16.840.1.113730.3.8.5.13 NAME 'idnsAllowSyncPTR' DESC 'permit synchronization of PTR records' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.5.14 NAME 'idnsForwardPolicy' DESC 'forward policy: only or first' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v2' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.5.15 NAME 'idnsForwarders' DESC 'list of forwarders' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v2' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.5.16 NAME 'idnsZoneRefresh' DESC 'zone refresh interval' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA v2' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.5.17 NAME 'idnsPersistentSearch' DESC 'allow persistent searches' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) add:objectClasses: ( 2.16.840.1.113730.3.8.6.2 NAME 'idnsConfigObject' DESC 'DNS global config options' STRUCTURAL MAY ( idnsForwardPolicy $$ idnsForwarders $$ idnsAllowSyncPTR $$ idnsZoneRefresh $$ idnsPersistentSearch ) ) add:objectClasses: ( 2.16.840.1.113730.3.8.12.18 NAME 'ipaDNSZone' SUP top AUXILIARY MUST idnsName MAY managedBy X-ORIGIN 'IPA v3' ) dn: cn=schema replace:objectClasses:( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsZoneActive $$ idnsSOAmName $$ idnsSOArName $$ idnsSOAserial $$ idnsSOArefresh $$ idnsSOAretry $$ idnsSOAexpire $$ idnsSOAminimum ) MAY idnsUpdatePolicy )::( 2.16.840.1.113730.3.8.6.1 NAME 'idnsZone' DESC 'Zone class' SUP idnsRecord STRUCTURAL MUST ( idnsName $$ idnsZoneActive $$ idnsSOAmName $$ idnsSOArName $$ idnsSOAserial $$ idnsSOArefresh $$ idnsSOAretry $$ idnsSOAexpire $$ idnsSOAminimum ) MAY ( idnsUpdatePolicy $$ idnsAllowQuery $$ idnsAllowTransfer $$ idnsAllowSyncPTR $$ idnsForwardPolicy $$ idnsForwarders ) ) replace:attributeTypes:"(1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord' DESC 'Non-Terminal DNS Name Redirection, RFC 2672' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)::( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord' DESC 'Non-Terminal DNS Name Redirection, RFC 2672' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )" replace:attributeTypes: (0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)::( 0.9.2342.19200300.100.1.31 NAME 'cNAMERecord' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE ) replace:objectClasses:"( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( cn $$ idnsAllowDynUpdate $$ DNSTTL $$ DNSClass $$ ARecord $$ AAAARecord $$ A6Record $$ NSRecord $$ CNAMERecord $$ PTRRecord $$ SRVRecord $$ TXTRecord $$ MXRecord $$ MDRecord $$ HINFORecord $$ MINFORecord $$ AFSDBRecord $$ SIGRecord $$ KEYRecord $$ LOCRecord $$ NXTRecord $$ NAPTRRecord $$ KXRecord $$ CERTRecord $$ DNAMERecord $$ DSRecord $$ SSHFPRecord $$ RRSIGRecord $$ NSECRecord ) )::( 2.16.840.1.113730.3.8.6.0 NAME 'idnsRecord' DESC 'dns Record, usually a host' SUP top STRUCTURAL MUST idnsName MAY ( idnsAllowDynUpdate $$ DNSTTL $$ DNSClass $$ ARecord $$ AAAARecord $$ A6Record $$ NSRecord $$ CNAMERecord $$ PTRRecord $$ SRVRecord $$ TXTRecord $$ MXRecord $$ MDRecord $$ HINFORecord $$ MINFORecord $$ AFSDBRecord $$ SIGRecord $$ KEYRecord $$ LOCRecord $$ NXTRecord $$ NAPTRRecord $$ KXRecord $$ CERTRecord $$ DNAMERecord $$ DSRecord $$ SSHFPRecord $$ RRSIGRecord $$ NSECRecord ) )" freeipa-3.3.4/install/updates/50-7_bit_check.update0000664000175000017500000000056612271663206021420 0ustar mkosekmkosek# Remove userPassword from the list of attributes checked by 7-bit plugin # Replace argument value 'userPassword' with 'mail' to avoid the need to # shift the whole argument array. Attribute 'mail' is already listed # in pluginarg1, so it is conveniently used as valid value placeholder. dn: cn=7-bit check,cn=plugins,cn=config replace:nsslapd-pluginarg2:userpassword::mail freeipa-3.3.4/install/updates/20-replication.update0000664000175000017500000000046112271663206021557 0ustar mkosekmkosek# # Counter used to store the next replica id # # Start at 3 to avoid conflicts with v1.0 replica ids. The value itself # isn't important but each replica needs a unique id. dn: cn=replication,cn=etc,$SUFFIX default: objectclass: nsDS5Replica default: nsDS5ReplicaId: 3 default: nsDS5ReplicaRoot: $SUFFIX freeipa-3.3.4/install/updates/50-groupuuid.update0000664000175000017500000000061412202434255021266 0ustar mkosekmkosek# The groups added in bootstrap-template.ldif didn't include ipaUniqueId dn: cn=admins,cn=groups,cn=accounts,$SUFFIX add:objectclass: ipaobject addifnew:ipaUniqueID: autogenerate dn: cn=ipausers,cn=groups,cn=accounts,$SUFFIX add:objectclass: ipaobject addifnew:ipaUniqueID: autogenerate dn: cn=editors,cn=groups,cn=accounts,$SUFFIX add:objectclass: ipaobject addifnew:ipaUniqueID: autogenerate freeipa-3.3.4/install/updates/10-config.update0000664000175000017500000000405112271663206020511 0ustar mkosekmkosek# Enforce matching SSL certificate host names when 389-ds acts as an SSL # client. A restart is necessary for this to take effect, we do one when # upgrading. dn: cn=config only:nsslapd-ssl-check-hostname: on # Remove incorrect placement dn: cn=Kerberos Principal Name,cn=IPA MODRDN,cn=plugins,cn=config remove: nsslapd-pluginPrecedence: 60 # Set the precedence of the ipa-modrdn plugin so it runs after other # plugins (the default is 50). dn: cn=IPA MODRDN,cn=plugins,cn=config only: nsslapd-pluginPrecedence: 60 # Set limits to suite better IPA deployment sizes, defaults are too # conservative dn: cn=config default: nsslapd-sizelimit:100000 dn: cn=config,cn=ldbm database,cn=plugins,cn=config replace: nsslapd-lookthroughlimit:5000::100000 replace: nsslapd-idlistscanlimit:4000::100000 #Set much lower limits for anonymous searhes dn: cn=anonymous-limits,cn=etc,$SUFFIX default:objectclass:nsContainer default:objectclass:top default:cn: anonymous-limits default:nsSizeLimit: 5000 default:nsLookThroughLimit: 5000 dn: cn=config only:nsslapd-anonlimitsdn:'cn=anonymous-limits,cn=etc,$SUFFIX' # Add a defaultNamingContext if one hasn't already been set. This was # introduced in 389-ds-base-1.2.10-0.9.a8. Adding this to a server that # doesn't support it generates a non-fatal error. dn: cn=config add:nsslapd-defaultNamingContext:'$SUFFIX' # Allow the root DSE to be searched even with minssf set dn: cn=config only:nsslapd-minssf-exclude-rootdse:on # Set the IPA winsync precedence so it will run after the DS # POSIX winsync plugin dn: cn=ipa-winsync,cn=plugins,cn=config only: nsslapd-pluginPrecedence: 60 # Enable SASL mapping fallback dn: cn=config only:nsslapd-sasl-mapping-fallback: on dn: cn=Full Principal,cn=mapping,cn=sasl,cn=config addifnew:nsSaslMapPriority: 10 dn: cn=Name Only,cn=mapping,cn=sasl,cn=config addifnew:nsSaslMapPriority: 10 # Default SASL buffer size was too small and could lead for example to # migration errors # Can be removed when https://fedorahosted.org/389/ticket/47457 is fixed dn: cn=config only:nsslapd-sasl-max-buffer-size:2097152 freeipa-3.3.4/install/updates/20-user_private_groups.update0000664000175000017500000000222412202434255023346 0ustar mkosekmkosek# This is a copy of the definition from user_private_groups.ldif # This is required for replication. The template entry will get # replicated but the plugin configuration will not. dn: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX default:objectclass: mepTemplateEntry default:cn: UPG Template default:mepRDNAttr: cn default:mepStaticAttr: objectclass: posixgroup default:mepStaticAttr: objectclass: ipaobject default:mepStaticAttr: ipaUniqueId: autogenerate default:mepMappedAttr: cn: $$uid default:mepMappedAttr: gidNumber: $$uidNumber default:mepMappedAttr: description: User private group for $$uid dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX default:objectclass: extensibleObject default:cn: UPG Definition default:originScope: cn=users,cn=accounts,$SUFFIX default:originFilter: objectclass=posixAccount default:managedBase: cn=groups,cn=accounts,$SUFFIX default:managedTemplate: cn=UPG Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX dn: cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX replace:originFilter: objectclass=posixAccount::(&(objectclass=posixAccount)(!(description=__no_upg__))) freeipa-3.3.4/install/updates/30-policy.update0000664000175000017500000000270212202434255020540 0ustar mkosekmkosek# bootstrap the policy DIT structure. Currently not used. dn: cn=policies,$SUFFIX add: objectclass: nsContainer add: objectclass: ipaContainer add: cn: policies add: description: Root of the policy related sub tree dn: cn=configs,cn=policies,$SUFFIX add: objectclass: nsContainer add: objectclass: ipaContainer add: cn: configs add: description: Root of the sub tree that holds configuration policies for different applications dn: cn=applications,cn=configs,cn=policies,$SUFFIX add: objectclass: nsContainer add: objectclass: ipaContainer add: cn: applications add: description: Root of the tree that hold all definitions of the supported applications dn: cn=Shell Applications,cn=applications,cn=configs,cn=policies,$SUFFIX add: objectclass: nsContainer add: objectclass: ipaContainer add: cn: Shell Applications add: description: Shell Applications - special application that holds templates for actions dn: cn=roles,cn=policies,$SUFFIX add: objectclass: nsContainer add: objectclass: ipaContainer add: cn: roles add: description: Root of the sub tree that holds role management data dn: cn=policygroups,cn=configs,cn=policies,$SUFFIX add: objectclass: ipaContainer add: objectclass: ipaOrderedContainer add: cn: policygroups add: description: Sub tree to hold policy groups dn: cn=policylinks,cn=configs,cn=policies,$SUFFIX add: objectclass: ipaContainer add: objectclass: ipaOrderedContainer add: cn: policylinks add: description: Sub tree to hold policy links freeipa-3.3.4/install/updates/Makefile.am0000664000175000017500000000234612271663206017663 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/updates app_DATA = \ 10-60basev2.update \ 10-60basev3.update \ 10-70ipaotp.update \ 10-RFC2307bis.update \ 10-RFC4876.update \ 10-config.update \ 10-enable-betxn.update \ 10-selinuxusermap.update \ 10-sudo.update \ 10-ssh.update \ 10-bind-schema.update \ 10-uniqueness.update \ 10-schema_compat.update \ 19-managed-entries.update \ 20-aci.update \ 20-dna.update \ 20-host_nis_groups.update \ 20-indices.update \ 20-nss_ldap.update \ 20-replication.update \ 20-user_private_groups.update \ 20-winsync_index.update \ 21-replicas_container.update \ 21-ca_renewal_container.update \ 25-referint.update \ 30-s4u2proxy.update \ 40-delegation.update \ 40-realm_domains.update \ 40-replication.update \ 40-dns.update \ 40-automember.update \ 40-otp.update \ 45-roles.update \ 50-7_bit_check.update \ 50-lockout-policy.update \ 50-groupuuid.update \ 50-hbacservice.update \ 50-krbenctypes.update \ 50-nis.update \ 50-ipaconfig.update \ 55-pbacmemberof.update \ 60-trusts.update \ 61-trusts-s4u2proxy.update \ 62-ranges.update \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/updates/40-delegation.update0000664000175000017500000006321012271663206021364 0ustar mkosekmkosek# IPA configuration dn: cn=Write IPA Configuration,cn=privileges,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: nestedgroup default:cn: Write IPA Configuration default:description: Write IPA Configuration dn: cn=Write IPA Configuration,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Write IPA Configuration default:member: cn=Write IPA Configuration,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci: '(targetattr = "ipausersearchfields || ipagroupsearchfields || ipasearchtimelimit || ipasearchrecordslimit || ipacustomfields || ipahomesrootdir || ipadefaultloginshell || ipadefaultprimarygroup || ipamaxusernamelength || ipapwdexpadvnotify || ipauserobjectclasses || ipagroupobjectclasses || ipadefaultemaildomain || ipamigrationenabled || ipacertificatesubjectbase || ipaconfigstring")(target = "ldap:///cn=ipaconfig,cn=etc,$SUFFIX" )(version 3.0 ; acl "permission:Write IPA Configuration"; allow (write) groupdn = "ldap:///cn=Write IPA Configuration,cn=permissions,cn=pbac,$SUFFIX";)' # Host-Based Access Control dn: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX default:objectClass: nestedgroup default:objectClass: groupofnames default:objectClass: top default:cn: HBAC Administrator default:description: HBAC Administrator dn: cn=Add HBAC rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add HBAC rule default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete HBAC rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete HBAC rule default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify HBAC rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Modify HBAC rule default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage HBAC rule membership,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Manage HBAC rule membership default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add HBAC services,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add HBAC services default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete HBAC services,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete HBAC services default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add HBAC service groups,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add HBAC service groups default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete HBAC service groups,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete HBAC service groups default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage HBAC service group membership,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Manage HBAC service group membership default:member: cn=HBAC Administrator,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci: '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Add HBAC rule";allow (add) groupdn = "ldap:///cn=Add HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Delete HBAC rule";allow (delete) groupdn = "ldap:///cn=Delete HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "servicecategory || sourcehostcategory || cn || description || ipaenabledflag || accesstime || usercategory || hostcategory || accessruletype || sourcehost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Modify HBAC rule";allow (write) groupdn = "ldap:///cn=Modify HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "memberuser || externalhost || memberservice || memberhost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Manage HBAC rule membership";allow (write) groupdn = "ldap:///cn=Manage HBAC rule membership,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=hbacservices,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Add HBAC services";allow (add) groupdn = "ldap:///cn=Add HBAC services,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=hbacservices,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Delete HBAC services";allow (delete) groupdn = "ldap:///cn=Delete HBAC services,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=hbacservicegroups,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Add HBAC service groups";allow (add) groupdn = "ldap:///cn=Add HBAC service groups,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=hbacservicegroups,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Delete HBAC service groups";allow (delete) groupdn = "ldap:///cn=Delete HBAC service groups,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "member")(target = "ldap:///cn=*,cn=hbacservicegroups,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Manage HBAC service group membership";allow (write) groupdn = "ldap:///cn=Manage HBAC service group membership,cn=permissions,cn=pbac,$SUFFIX";)' # SUDO dn: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX default:objectClass: nestedgroup default:objectClass: groupofnames default:objectClass: top default:cn: Sudo Administrator default:description: Sudo Administrator dn: cn=Add Sudo rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add Sudo rule default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete Sudo rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete Sudo rule default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Sudo rule,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Modify Sudo rule default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add Sudo command,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add Sudo command default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete Sudo command,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete Sudo command default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Sudo command,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Modify Sudo command default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add Sudo command group,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add Sudo command group default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete Sudo command group,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete Sudo command group default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage Sudo command group membership,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Manage Sudo command group membership default:member: cn=Sudo Administrator,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci: '(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Add Sudo rule";allow (add) groupdn = "ldap:///cn=Add Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Delete Sudo rule";allow (delete) groupdn = "ldap:///cn=Delete Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "description || ipaenabledflag || usercategory || hostcategory || cmdcategory || ipasudorunasusercategory || ipasudorunasgroupcategory || externaluser || ipasudorunasextuser || ipasudorunasextgroup || memberdenycmd || memberallowcmd || memberuser")(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Modify Sudo rule";allow (write) groupdn = "ldap:///cn=Modify Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)' remove:aci: '(targetattr = "description")(target = "ldap:///sudocmd=*,cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Modify Sudo command";allow (write) groupdn = "ldap:///cn=Modify Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' remove:aci: '(target = "ldap:///sudocmd=*,cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Delete Sudo command";allow (delete) groupdn = "ldap:///cn=Delete Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' remove:aci: '(target = "ldap:///sudocmd=*,cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Add Sudo command";allow (add) groupdn = "ldap:///cn=Add Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetfilter = "(objectclass=ipasudocmd)")(targetattr = "description")(target = "ldap:///cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Modify Sudo command";allow (write) groupdn = "ldap:///cn=Modify Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetfilter = "(objectclass=ipasudocmd)")(target = "ldap:///cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Delete Sudo command";allow (delete) groupdn = "ldap:///cn=Delete Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetfilter = "(objectclass=ipasudocmd)")(target = "ldap:///cn=sudocmds,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Add Sudo command";allow (add) groupdn = "ldap:///cn=Add Sudo command,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=sudocmdgroups,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Add Sudo command group";allow (add) groupdn = "ldap:///cn=Add Sudo command group,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=sudocmdgroups,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Delete Sudo command group";allow (delete) groupdn = "ldap:///cn=Delete Sudo command group,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "member")(target = "ldap:///cn=*,cn=sudocmdgroups,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Manage Sudo command group membership";allow (write) groupdn = "ldap:///cn=Manage Sudo command group membership,cn=permissions,cn=pbac,$SUFFIX";)' # Password Policy dn: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX default:objectClass: nestedgroup default:objectClass: groupofnames default:objectClass: top default:cn: Password Policy Administrator default:description: Password Policy Administrator dn: cn=Add Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add Group Password Policy costemplate default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete Group Password Policy costemplate default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Modify Group Password Policy costemplate default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Add Group Password Policy,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Add Group Password Policy default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Delete Group Password Policy,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Delete Group Password Policy default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX default:objectClass: groupofnames default:objectClass: ipapermission default:objectClass: top default:cn: Modify Group Password Policy default:member: cn=Password Policy Administrator,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci: '(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy costemplate";allow (add) groupdn = "ldap:///cn=Add Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy costemplate";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "cospriority")(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy costemplate";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy";allow (add) groupdn = "ldap:///cn=Add Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)' add:aci: '(targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdhistorylength || krbpwdmindiffchars || krbpwdminlength || krbpwdmaxfailure || krbpwdfailurecountinterval || krbpwdlockoutduration")(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)' # Allow an admin to enroll a host that has a one-time password. # When a host is created with a password no krbPrincipalName is set. # This will let it be added if the client ends up enrolling with # an administrator instead. dn: cn=Add krbPrincipalName to a host,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Add krbPrincipalName to a host default:member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX default:member: cn=Host Enrollment,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci: '(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(targetfilter = "(!(krbprincipalname=*))")(targetattr = "krbprincipalname")(version 3.0;acl "permission:Add krbPrincipalName to a host"; allow (write) groupdn = "ldap:///cn=Add krbPrincipalName to a host,cn=permissions,cn=pbac,$SUFFIX";)' dn: cn=Host Enrollment,cn=privileges,cn=pbac,$SUFFIX add:member: 'cn=admins,cn=groups,cn=accounts,$SUFFIX' # Don't allow admins to update enrolledBy dn: $SUFFIX replace:aci:'(targetattr = "enrolledby || objectclass")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Enroll a host";allow (write) groupdn = "ldap:///cn=Enroll a host,cn=permissions,cn=pbac,$SUFFIX";)::(targetattr = "objectclass")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Enroll a host";allow (write) groupdn = "ldap:///cn=Enroll a host,cn=permissions,cn=pbac,$SUFFIX";)' # The original DNS permissions lacked the tag. dn: $SUFFIX replace:aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries";allow (add) groupdn = "ldap:///cn=add dns entries,cn=permissions,cn=pbac,$SUFFIX";)::(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:add dns entries";allow (add) groupdn = "ldap:///cn=add dns entries,cn=permissions,cn=pbac,$SUFFIX";)' replace:aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries";allow (delete) groupdn = "ldap:///cn=remove dns entries,cn=permissions,cn=pbac,$SUFFIX";)::(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:remove dns entries";allow (delete) groupdn = "ldap:///cn=remove dns entries,cn=permissions,cn=pbac,$SUFFIX";)' replace:aci:'(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)::(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)' # SELinux User Mapping dn: cn=SELinux User Map Administrators,cn=privileges,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: nestedgroup default:cn: SELinux User Map Administrators default:description: SELinux User Map Administrators dn: cn=Add SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Add SELinux User Maps default:member: cn=SELinux User Map Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Remove SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Remove SELinux User Maps default:member: cn=SELinux User Map Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Modify SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Modify SELinux User Maps default:member: cn=SELinux User Map Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci:'(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Add SELinux User Maps";allow (add) groupdn = "ldap:///cn=Add SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)' dn: $SUFFIX add:aci:'(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Remove SELinux User Maps";allow (delete) groupdn = "ldap:///cn=Remove SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)' 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 default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Manage User SSH Public Keys default:member: cn=User Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Manage Host SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Manage Host SSH Public Keys default:member: cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX dn: $SUFFIX add:aci:'(targetattr = "ipasshpubkey")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage User SSH Public Keys";allow (write) groupdn = "ldap:///cn=Manage User SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX";)' dn: $SUFFIX add:aci:'(targetattr = "ipasshpubkey")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage Host SSH Public Keys";allow (write) groupdn = "ldap:///cn=Manage Host SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX";)' # Limit the change password permission so it can't change the passwords # of administrators dn: $SUFFIX replace:aci:'(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)::(targetfilter = "(!(memberOf=cn=admins,cn=groups,cn=accounts,$SUFFIX))")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)' # Don't allow the default 'manage group membership' to be able to manage the # admins group replace:aci:'(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)::(targetfilter = "(!(cn=admins))")(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)' dn: cn=ipa,cn=etc,$SUFFIX add:aci:'(target = "ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(version 3.0; acl "Add CA Certificates for renewals"; allow(add) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)' add:aci:'(target = "ldap:///cn=*,cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX")(targetattr = "userCertificate")(version 3.0; acl "Modify CA Certificates for renewals"; allow(write) userdn = "ldap:///fqdn=$FQDN,cn=computers,cn=accounts,$SUFFIX";)' # Add permissions "Retrieve Certificates from the CA" and "Revoke Certificate" # to privilege "Host Administrators" dn: cn=Retrieve Certificates from the CA,cn=permissions,cn=pbac,$SUFFIX add: member: 'cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX' dn: cn=Revoke Certificate,cn=permissions,cn=pbac,$SUFFIX add: member: 'cn=Host Administrators,cn=privileges,cn=pbac,$SUFFIX' freeipa-3.3.4/install/updates/10-enable-betxn.update0000664000175000017500000000263012271663206021611 0ustar mkosekmkosek# Enable transactions in 389-ds-base dn: cn=7-bit check,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=attribute uniqueness,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=Auto Membership Plugin,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=Linked Attributes,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=Managed Entries,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=MemberOf Plugin,cn=plugins,cn=config only: nsslapd-pluginType: betxnpostoperation dn: cn=Multimaster Replication Plugin,cn=plugins,cn=config only: nsslapd-pluginbetxn: on dn: cn=PAM Pass Through Auth,cn=plugins,cn=config only: nsslapd-pluginType: betxnpreoperation dn: cn=referential integrity postoperation,cn=plugins,cn=config only: nsslapd-pluginType: betxnpostoperation dn: cn=Roles Plugin,cn=plugins,cn=config only: nsslapd-pluginbetxn: on dn: cn=State Change Plugin,cn=plugins,cn=config only: nsslapd-pluginType: betxnpostoperation dn: cn=USN,cn=plugins,cn=config only: nsslapd-pluginbetxn: on dn: cn=IPA MODRDN,cn=plugins,cn=config only: nsslapd-plugintype: betxnpostoperation dn: cn=ipa_pwd_extop,cn=plugins,cn=config only: nsslapd-pluginbetxn: on dn: cn=Schema Compatibility, cn=plugins, cn=config onlyifexist: nsslapd-pluginbetxn: on dn: cn=NIS Server, cn=plugins, cn=config onlyifexist: nsslapd-pluginbetxn: on freeipa-3.3.4/install/updates/30-s4u2proxy.update0000664000175000017500000000153212202434255021140 0ustar mkosekmkosekdn: cn=s4u2proxy,cn=etc,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: s4u2proxy dn: cn=ipa-http-delegation,cn=s4u2proxy,cn=etc,$SUFFIX default: objectClass: ipaKrb5DelegationACL default: objectClass: groupOfPrincipals default: objectClass: top default: cn: ipa-http-delegation default: memberPrincipal: HTTP/$FQDN@$REALM default: ipaAllowedTarget: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX dn: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX default: objectClass: groupOfPrincipals default: objectClass: top default: cn: ipa-ldap-delegation-targets default: memberPrincipal: ldap/$FQDN@$REALM dn: cn=ipa-http-delegation,cn=s4u2proxy,cn=etc,$SUFFIX add: memberPrincipal: HTTP/$FQDN@$REALM dn: cn=ipa-ldap-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX add: memberPrincipal: ldap/$FQDN@$REALM freeipa-3.3.4/install/updates/21-ca_renewal_container.update0000664000175000017500000000023612202434255023403 0ustar mkosekmkosek# # Add CA renewal container if not available # dn: cn=ca_renewal,cn=ipa,cn=etc,$SUFFIX add:objectClass: top add:objectClass: nsContainer add:cn: ca_renewal freeipa-3.3.4/install/updates/50-nis.update0000664000175000017500000001715112202434255020040 0ustar mkosekmkosek# Correct syntax error that caused users to not appear dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config replace:nis-value-format: '%merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")' # Correct syntax error that caused nested netgroups to not work # https://bugzilla.redhat.com/show_bug.cgi?id=788625 dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config replace:nis-value-format: '%merge(" ","%{memberNisNetgroup}","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")' # Make the padding an expression so usercat and hostcat always gets # evaluated when displaying entries. # https://bugzilla.redhat.com/show_bug.cgi?id=767372 dn: nis-domain=$DOMAIN+nis-map=netgroup, cn=NIS Server, cn=plugins, cn=config replace:nis-value-format: '%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"-\"),%{nisDomainName:-})")::%merge(" ","%deref_f(\"member\",\"(objectclass=ipanisNetgroup)\",\"cn\")","(%link(\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%{externalHost}\\\\\\\",\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberHost\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"fqdn\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"hostCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\",\",\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"%collect(\\\\\\\"%deref(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\",\\\\\\\"%deref_r(\\\\\\\\\\\\\\\"memberUser\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"member\\\\\\\\\\\\\\\",\\\\\\\\\\\\\\\"uid\\\\\\\\\\\\\\\")\\\\\\\")\\\")\",\"%ifeq(\\\"userCategory\\\",\\\"all\\\",\\\"\\\",\\\"-\\\")\"),%{nisDomainName:-})")' dn: nis-domain=$DOMAIN+nis-map=ethers.byaddr, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: ethers.byaddr default:nis-base: cn=computers, cn=accounts, $SUFFIX default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6") default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7") default:nis-secure: no dn: nis-domain=$DOMAIN+nis-map=ethers.byname, cn=NIS Server, cn=plugins, cn=config default:objectclass: top default:objectclass: extensibleObject default:nis-domain: $DOMAIN default:nis-map: ethers.byname default:nis-base: cn=computers, cn=accounts, $SUFFIX default:nis-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:nis-keys-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%7") default:nis-values-format: %mregsub("%{macAddress} %{fqdn}","(..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..)[:\\\|-](..) (.*)","%1:%2:%3:%4:%5:%6 %7") default:nis-secure: no freeipa-3.3.4/install/updates/50-lockout-policy.update0000664000175000017500000000017112202434255022216 0ustar mkosekmkosekdn: cn=global_policy,cn=$REALM,cn=kerberos,$SUFFIX replace:krbPwdLockoutDuration:10::600 replace: krbPwdMaxFailure:3::6 freeipa-3.3.4/install/updates/20-host_nis_groups.update0000664000175000017500000000200212202434255022456 0ustar mkosekmkosek# This is a copy of the definition from host_nis_groups.ldif # This is required for replication. The template entry will get # replicated but the plugin configuration will not. dn: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX default:objectclass: mepTemplateEntry default:cn: NGP HGP Template default:mepRDNAttr: cn default:mepStaticAttr: ipaUniqueId: autogenerate default:mepStaticAttr: objectclass: ipanisnetgroup default:mepStaticAttr: objectclass: ipaobject default:mepStaticAttr: nisDomainName: $DOMAIN default:mepMappedAttr: cn: $$cn default:mepMappedAttr: memberHost: $$dn default:mepMappedAttr: description: ipaNetgroup $$cn dn: cn=NGP Definition,cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX default:objectclass: extensibleObject only:cn: NGP Definition default:originScope: cn=hostgroups,cn=accounts,$SUFFIX default:originFilter: objectclass=ipahostgroup default:managedBase: cn=ng,cn=alt,$SUFFIX default:managedTemplate: cn=NGP HGP Template,cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX freeipa-3.3.4/install/updates/50-ipaconfig.update0000664000175000017500000000042612271663206021211 0ustar mkosekmkosekdn: cn=ipaConfig,cn=etc,$SUFFIX add:ipaSELinuxUserMapOrder: guest_u:s0$$xguest_u:s0$$user_u:s0$$staff_u:s0-s0:c0.c1023$$unconfined_u:s0-s0:c0.c1023 add:ipaSELinuxUserMapDefault: unconfined_u:s0-s0:c0.c1023 add:ipaUserObjectClasses: ipasshuser remove:ipaConfigString:AllowLMhash freeipa-3.3.4/install/updates/60-trusts.update0000664000175000017500000004434712271663206020631 0ustar mkosekmkosekdn: cn=schema add:attributeTypes: (2.16.840.1.113730.3.8.11.2 NAME 'ipaNTSecurityIdentifier' DESC 'NT Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.23 NAME 'ipaNTTrustedDomainSID' DESC 'NT Trusted Domain Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.3 NAME 'ipaNTFlatName' DESC 'Flat/Netbios Name' 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.4 NAME 'ipaNTFallbackPrimaryGroup' DESC 'Fallback Group to set the Primary group Security Identifier for users with UPGs' SUP distinguishedName X-ORIGIN 'IPA v3' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.5 NAME 'ipaNTHash' DESC 'NT Hash of user password' EQUALITY octetStringMatch ORDERING octetStringOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA v3' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.6 NAME 'ipaNTLogonScript' DESC 'User Logon Script Name' 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.7 NAME 'ipaNTProfilePath' DESC 'User Profile Path' 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.8 NAME 'ipaNTHomeDirectory' DESC 'User Home Directory Path' 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.9 NAME 'ipaNTHomeDirectoryDrive' DESC 'User Home Drive Letter' 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.10 NAME 'ipaNTDomainGUID' DESC 'NT Domain GUID' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'IPA v3' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.11 NAME 'ipaNTTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.12 NAME 'ipaNTTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.13 NAME 'ipaNTTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.14 NAME 'ipaNTTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.15 NAME 'ipaNTTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.16 NAME 'ipaNTTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.17 NAME 'ipaNTTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.18 NAME 'ipaNTTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.19 NAME 'ipaNTSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE ) add: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' ) add:objectClasses: (2.16.840.1.113730.3.8.12.3 NAME 'ipaNTGroupAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.4 NAME 'ipaNTDomainAttrs' SUP top AUXILIARY MUST ( ipaNTSecurityIdentifier $$ ipaNTFlatName $$ ipaNTDomainGUID ) MAY ( ipaNTFallbackPrimaryGroup ) X-ORIGIN 'IPA v3' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.38 NAME 'ipaNTSIDBlacklistIncoming' DESC 'Extra SIDs filtered out from incoming MS-PAC' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3' ) add:attributeTypes: ( 2.16.840.1.113730.3.8.11.39 NAME 'ipaNTSIDBlacklistOutgoing' DESC 'Extra SIDs filtered out from outgoing MS-PAC' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3' ) replace:objectClasses: (2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $$ ipaNTTrustAttributes $$ ipaNTTrustDirection $$ ipaNTTrustPartner $$ ipaNTFlatName $$ ipaNTTrustAuthOutgoing $$ ipaNTTrustAuthIncoming $$ ipaNTSecurityIdentifier $$ ipaNTTrustForestTrustInfo $$ ipaNTTrustPosixOffset $$ ipaNTSupportedEncryptionTypes) )::(2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $$ ipaNTTrustAttributes $$ ipaNTTrustDirection $$ ipaNTTrustPartner $$ ipaNTFlatName $$ ipaNTTrustAuthOutgoing $$ ipaNTTrustAuthIncoming $$ ipaNTTrustedDomainSID $$ ipaNTTrustForestTrustInfo $$ ipaNTTrustPosixOffset $$ ipaNTSupportedEncryptionTypes $$ ipaNTSIDBlacklistIncoming $$ ipaNTSIDBlacklistOutgoing) ) replace:objectClasses: (2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $$ ipaNTTrustAttributes $$ ipaNTTrustDirection $$ ipaNTTrustPartner $$ ipaNTFlatName $$ ipaNTTrustAuthOutgoing $$ ipaNTTrustAuthIncoming $$ ipaNTTrustedDomainSID $$ ipaNTTrustForestTrustInfo $$ ipaNTTrustPosixOffset $$ ipaNTSupportedEncryptionTypes) )::(2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $$ ipaNTTrustAttributes $$ ipaNTTrustDirection $$ ipaNTTrustPartner $$ ipaNTFlatName $$ ipaNTTrustAuthOutgoing $$ ipaNTTrustAuthIncoming $$ ipaNTTrustedDomainSID $$ ipaNTTrustForestTrustInfo $$ ipaNTTrustPosixOffset $$ ipaNTSupportedEncryptionTypes $$ ipaNTSIDBlacklistIncoming $$ ipaNTSIDBlacklistOutgoing) ) add:objectClasses: (2.16.840.1.113730.3.8.12.5 NAME 'ipaNTTrustedDomain' SUP top STRUCTURAL DESC 'Trusted Domain Object' MUST ( cn ) MAY ( ipaNTTrustType $$ ipaNTTrustAttributes $$ ipaNTTrustDirection $$ ipaNTTrustPartner $$ ipaNTFlatName $$ ipaNTTrustAuthOutgoing $$ ipaNTTrustAuthIncoming $$ ipaNTTrustedDomainSID $$ ipaNTTrustForestTrustInfo $$ ipaNTTrustPosixOffset $$ ipaNTSupportedEncryptionTypes $$ ipaNTSIDBlacklistIncoming $$ ipaNTSIDBlacklistOutgoing) ) dn: cn=trust admins,cn=groups,cn=accounts,$SUFFIX default: objectClass: top default: objectClass: groupofnames default: objectClass: ipausergroup default: objectClass: nestedgroup default: objectClass: ipaobject default: cn: trust admins default: description: Trusts administrators group default: member: uid=admin,cn=users,cn=accounts,$SUFFIX default: nsAccountLock: FALSE default: ipaUniqueID: autogenerate dn: cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX default: objectClass: GroupOfNames default: objectClass: top default: cn: adtrust agents dn: cn=trusts,$SUFFIX default: objectClass: top default: objectClass: nsContainer default: cn: trusts # Trust management # 1. cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX can manage trusts, to allow modification via CIFS # 2. cn=trust admins,cn=groups,cn=accounts,$SUFFIX can manage trusts (via ipa tools) dn: cn=trusts,$SUFFIX add:aci: '(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)' replace:aci:'(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing || krbPrincipalName || krbLastPwdChange || krbTicketFlags || krbLoginFailedCount || krbExtraData || krbPrincipalKey")(version 3.0;acl "Allow trust system user to create and delete trust accounts and cross realm principals"; allow (read,write,add,delete) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)' replace:aci:'(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)::(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)' add:aci: '(target = "ldap:///cn=trusts,$SUFFIX")(targetattr = "ipaNTTrustType || ipaNTTrustAttributes || ipaNTTrustDirection || ipaNTTrustPartner || ipaNTFlatName || ipaNTTrustAuthOutgoing || ipaNTTrustAuthIncoming || ipaNTSecurityIdentifier || ipaNTTrustForestTrustInfo || ipaNTTrustPosixOffset || ipaNTSupportedEncryptionTypes || ipaNTSIDBlacklistIncoming || ipaNTSIDBlacklistOutgoing")(version 3.0;acl "Allow trust admins manage trust accounts"; allow (read,write,add,delete) groupdn="ldap:///cn=trust admins,cn=groups,cn=accounts,$SUFFIX";)' # Samba user should be able to read NT passwords to authenticate # Add ipaNTHash to global ACIs, leave DNS tree out of global allow access rule dn: $SUFFIX add:aci: '(targetattr = "ipaNTHash")(version 3.0; acl "Samba system principals can read and write NT passwords"; allow (read,write) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)' remove:aci: '(targetattr = "ipaNTHash")(version 3.0; acl "Samba system principals can read NT passwords"; allow (read) groupdn="ldap:///cn=adtrust agents,cn=sysaccounts,cn=etc,$SUFFIX";)' replace:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || userPKCS12")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)::(target != "ldap:///idnsname=*,cn=dns,$SUFFIX")(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || userPKCS12 || ipaNTHash")(version 3.0; acl "Enable Anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)' remove: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";)' remove: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 || ipaNTHash")(version 3.0; acl "Admin can manage any entry"; allow (all) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)' add:aci:'(targetattr != "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory || krbMKey || krbPrincipalName || krbCanonicalName || krbUPEnabled || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData || krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount || 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";)' # Add the default PAC type to configuration dn: cn=ipaConfig,cn=etc,$SUFFIX addifnew: ipaKrbAuthzData: MS-PAC # Fix typo in some installs in the spelling of ORDERING. They were added # with a typo which was silently dropped by 389-ds-base, so add in the # proper ordering syntax now. replace:attributeTypes: (2.16.840.1.113730.3.8.11.3 NAME 'ipaNTFlatName' DESC 'Flat/Netbios Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.3 NAME 'ipaNTFlatName' DESC 'Flat/Netbios Name' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) replace:attributeTypes: (2.16.840.1.113730.3.8.11.5 NAME 'ipaNTHash' DESC 'NT Hash of user password' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.5 NAME 'ipaNTHash' DESC 'NT Hash of user password' EQUALITY octetStringMatch ORDERING octetStringOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA v3' ) replace:attributeTypes: (2.16.840.1.113730.3.8.11.6 NAME 'ipaNTLogonScript' DESC 'User Logon Script Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.6 NAME 'ipaNTLogonScript' DESC 'User Logon Script Name' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) replace:attributeTypes: (2.16.840.1.113730.3.8.11.7 NAME 'ipaNTProfilePath' DESC 'User Profile Path' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.7 NAME 'ipaNTProfilePath' DESC 'User Profile Path' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) replace:attributeTypes: (2.16.840.1.113730.3.8.11.8 NAME 'ipaNTHomeDirectory' DESC 'User Home Directory Path' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.8 NAME 'ipaNTHomeDirectory' DESC 'User Home Directory Path' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) replace:attributeTypes: (2.16.840.1.113730.3.8.11.9 NAME 'ipaNTHomeDirectoryDrive' DESC 'User Home Drive Letter' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) :: (2.16.840.1.113730.3.8.11.9 NAME 'ipaNTHomeDirectoryDrive' DESC 'User Home Drive Letter' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v3' ) freeipa-3.3.4/install/updates/55-pbacmemberof.update0000664000175000017500000000120312271663206021673 0ustar mkosekmkosek# # This needs to come later in the cycle otherwise the DN sorting is going # to cause it to execute before the member attributes are added dn: cn=Update PBAC memberOf $TIME, cn=memberof task, cn=tasks, cn=config add: objectClass: top add: objectClass: extensibleObject add: cn: IPA PBAC memberOf $TIME add: basedn: 'cn=privileges,cn=pbac,$SUFFIX' add: filter: (objectclass=*) add: ttl: 10 dn: cn=Update Role memberOf $TIME, cn=memberof task, cn=tasks, cn=config add: objectClass: top add: objectClass: extensibleObject add: cn: Update Role memberOf $TIME add: basedn: 'cn=roles,cn=accounts,$SUFFIX' add: filter: (objectclass=*) add: ttl: 10 freeipa-3.3.4/install/updates/10-ssh.update0000664000175000017500000000120412270466515020041 0ustar mkosekmkosek# Add the SSH schema dn: cn=schema add:attributeTypes: ( 2.16.840.1.113730.3.8.11.31 NAME 'ipaSshPubKey' DESC 'SSH public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'IPA v3' ) add:objectClasses: ( 2.16.840.1.113730.3.8.12.11 NAME 'ipaSshGroupOfPubKeys' ABSTRACT MAY ipaSshPubKey X-ORIGIN 'IPA v3' ) add:objectClasses: ( 2.16.840.1.113730.3.8.12.12 NAME 'ipaSshUser' SUP ipaSshGroupOfPubKeys AUXILIARY X-ORIGIN 'IPA v3' ) add:objectClasses: ( 2.16.840.1.113730.3.8.12.13 NAME 'ipaSshHost' SUP ipaSshGroupOfPubKeys AUXILIARY X-ORIGIN 'IPA v3' ) freeipa-3.3.4/install/updates/50-hbacservice.update0000664000175000017500000000306712271663206021534 0ustar mkosekmkosekdn: cn=crond,cn=hbacservices,cn=hbac,$SUFFIX default:objectclass: ipahbacservice default:objectclass: ipaobject default:cn: crond default:description: crond default:ipauniqueid:autogenerate dn: cn=vsftpd,cn=hbacservices,cn=hbac,$SUFFIX default:objectclass: ipahbacservice default:objectclass: ipaobject default:cn: vsftpd default:description: vsftpd default:ipauniqueid:autogenerate dn: cn=proftpd,cn=hbacservices,cn=hbac,$SUFFIX default:objectclass: ipahbacservice default:objectclass: ipaobject default:cn: proftpd default:description: proftpd default:ipauniqueid:autogenerate dn: cn=pure-ftpd,cn=hbacservices,cn=hbac,$SUFFIX default:objectclass: ipahbacservice default:objectclass: ipaobject default:cn: pure-ftpd default:description: pure-ftpd default:ipauniqueid:autogenerate dn: cn=gssftp,cn=hbacservices,cn=hbac,$SUFFIX default:objectclass: ipahbacservice default:objectclass: ipaobject default:cn: gssftp default:description: gssftp default:ipauniqueid:autogenerate dn: cn=ftp,cn=hbacservicegroups,cn=hbac,$SUFFIX default:objectClass: ipaobject default:objectClass: ipahbacservicegroup default:objectClass: nestedGroup default:objectClass: groupOfNames default:objectClass: top default:cn: ftp default:ipauniqueid:autogenerate default:description: Default group of ftp related services default:member: cn=ftp,cn=hbacservices,cn=hbac,$SUFFIX default:member: cn=proftpd,cn=hbacservices,cn=hbac,$SUFFIX default:member: cn=pure-ftpd,cn=hbacservices,cn=hbac,$SUFFIX default:member: cn=vsftpd,cn=hbacservices,cn=hbac,$SUFFIX default:member: cn=gssftp,cn=hbacservices,cn=hbac,$SUFFIX freeipa-3.3.4/install/updates/20-nss_ldap.update0000664000175000017500000000172012202434255021042 0ustar mkosekmkosek# # Add profile for RFC 4876 agents (Solaris and HP/ux) # # Update the top-level entry dn: $SUFFIX add:objectClass: domain add:objectClass: domainRelatedObject add:objectClass: nisDomainObject add:associatedDomain: $DOMAIN add:nisDomain: $DOMAIN # Add a place to store the nss_ldap default profile dn: ou=profile,$SUFFIX add: objectClass: top add: objectClass: organizationalUnit add: ou: profiles # The DUA profile. On Solaris one can run: # ldap_client init ipa.example.com dn: cn=default,ou=profile,$SUFFIX default:ObjectClass: top default:ObjectClass: DUAConfigProfile default:defaultServerList: $FQDN default:defaultSearchBase: $SUFFIX default:authenticationMethod: none default:searchTimeLimit: 15 default:cn: default default:serviceSearchDescriptor: passwd:cn=users,cn=accounts,$SUFFIX default:serviceSearchDescriptor: group:cn=groups,cn=compat,$SUFFIX default:bindTimeLimit: 5 default:objectClassMap: shadow:shadowAccount=posixAccount default:followReferrals:TRUE freeipa-3.3.4/install/updates/10-schema_compat.update0000664000175000017500000000513012271663206022046 0ustar mkosekmkosekdn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config only:schema-compat-entry-rdn:'%ifeq("ipaEnabledFlag", "FALSE", "DISABLED", "cn=%{cn}")' replace: schema-compat-entry-attribute:'sudoRunAsGroup=%deref("ipaSudoRunAs","cn")::sudoRunAsGroup=%deref_f("ipaSudoRunAsGroup","(objectclass=posixGroup)","cn")' # Change padding for host and userCategory so the pad returns the same value # as the original, '' or -. dn: cn=ng,cn=Schema Compatibility,cn=plugins,cn=config replace: schema-compat-entry-attribute:'nisNetgroupTriple=(%link("%ifeq(\"hostCategory\",\"all\",\"\",\"%collect(\\\"%{externalHost}\\\",\\\"%deref(\\\\\\\"memberHost\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberHost\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\")\")","-",",","%ifeq(\"userCategory\",\"all\",\"\",\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\")","-"),%{nisDomainName:-})::nisNetgroupTriple=(%link("%ifeq(\"hostCategory\",\"all\",\"\",\"%collect(\\\"%{externalHost}\\\",\\\"%deref(\\\\\\\"memberHost\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberHost\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"fqdn\\\\\\\")\\\")\")","%ifeq(\"hostCategory\",\"all\",\"\",\"-\")",",","%ifeq(\"userCategory\",\"all\",\"\",\"%collect(\\\"%deref(\\\\\\\"memberUser\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\",\\\"%deref_r(\\\\\\\"memberUser\\\\\\\",\\\\\\\"member\\\\\\\",\\\\\\\"uid\\\\\\\")\\\")\")","%ifeq(\"userCategory\",\"all\",\"\",\"-\")"),%{nisDomainName:-})' dn: cn=computers, cn=Schema Compatibility, cn=plugins, cn=config default:objectClass: top default:objectClass: extensibleObject default:cn: computers default:schema-compat-container-group: cn=compat, $SUFFIX default:schema-compat-container-rdn: cn=computers default:schema-compat-search-base: cn=computers, cn=accounts, $SUFFIX default:schema-compat-search-filter: (&(macAddress=*)(fqdn=*)(objectClass=ipaHost)) default:schema-compat-entry-rdn: cn=%first("%{fqdn}") default:schema-compat-entry-attribute: objectclass=device default:schema-compat-entry-attribute: objectclass=ieee802Device default:schema-compat-entry-attribute: cn=%{fqdn} default:schema-compat-entry-attribute: macAddress=%{macAddress} dn: cn=sudoers,cn=Schema Compatibility,cn=plugins,cn=config add:schema-compat-entry-attribute: sudoOrder=%{sudoOrder} freeipa-3.3.4/install/updates/10-70ipaotp.update0000664000175000017500000001210112271663206020702 0ustar mkosekmkosekdn: cn=schema add:attributeTypes: (2.16.840.1.113730.3.8.16.1.1 NAME 'ipatokenUniqueID' DESC 'Token Unique Identifier' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.2 NAME 'ipatokenDisabled' DESC 'Optionally marks token as Disabled' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.3 NAME 'ipatokenNotBefore' DESC 'Token validity date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.4 NAME 'ipatokenNotAfter' DESC 'Token expiration date' EQUALITY generalizedTimeMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.5 NAME 'ipatokenVendor' DESC 'Optional Vendor identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.6 NAME 'ipatokenModel' DESC 'Optional Model identifier' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.7 NAME 'ipatokenSerial' DESC 'OTP Token Serial number' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.8 NAME 'ipatokenOTPkey' DESC 'OTP Token Key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.9 NAME 'ipatokenOTPalgorithm' DESC 'OTP Token Algorithm' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.10 NAME 'ipatokenOTPdigits' DESC 'OTP Token Number of digits' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.11 NAME 'ipatokenTOTPclockOffset' DESC 'TOTP clock offset' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.12 NAME 'ipatokenTOTPtimeStep' DESC 'TOTP time-step' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.13 NAME 'ipatokenOwner' DESC 'User entry that owns this token' SUP distinguishedName SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.14 NAME 'ipatokenRadiusUserName' DESC 'Corresponding Radius username' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.15 NAME 'ipatokenRadiusConfigLink' DESC 'Corresponding Radius Configuration link' SUP distinguishedName SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.16 NAME 'ipatokenRadiusServer' DESC 'Server String Configuration' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.17 NAME 'ipatokenRadiusSecret' DESC 'Server Secret' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.18 NAME 'ipatokenRadiusTimeout' DESC 'Server Timeout' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.19 NAME 'ipatokenRadiusRetries' DESC 'Number of allowed Retries' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:attributeTypes: (2.16.840.1.113730.3.8.16.1.20 NAME 'ipatokenUserMapAttribute' DESC 'Attribute to map from the user entry for RADIUS server authentication' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA OTP') add:objectClasses: (2.16.840.1.113730.3.8.16.2.1 NAME 'ipaToken' SUP top ABSTRACT DESC 'Abstract token class for tokens' MUST (ipatokenUniqueID) MAY (description $$ ipatokenOwner $$ ipatokenDisabled $$ ipatokenNotBefore $$ ipatokenNotAfter $$ ipatokenVendor $$ ipatokenModel $$ ipatokenSerial) X-ORIGIN 'IPA OTP') add:objectClasses: (2.16.840.1.113730.3.8.16.2.2 NAME 'ipatokenTOTP' SUP ipaToken STRUCTURAL DESC 'TOTP Token Type' MAY (ipatokenOTPkey $$ ipatokenOTPalgorithm $$ ipatokenOTPdigits $$ ipatokenTOTPclockOffset $$ ipatokenTOTPtimeStep) X-ORIGIN 'IPA OTP') add:objectClasses: (2.16.840.1.113730.3.8.16.2.3 NAME 'ipatokenRadiusProxyUser' SUP top AUXILIARY DESC 'Radius Proxy User' MUST (ipatokenRadiusConfigLink) MAY (ipatokenRadiusUserName) X-ORIGIN 'IPA OTP') add:objectClasses: (2.16.840.1.113730.3.8.16.2.4 NAME 'ipatokenRadiusConfiguration' SUP top STRUCTURAL DESC 'Proxy Radius Configuration' MUST (cn $$ ipatokenRadiusServer $$ ipatokenRadiusSecret) MAY (description $$ ipatokenRadiusTimeout $$ ipatokenRadiusRetries $$ ipatokenUserMapAttribute) X-ORIGIN 'IPA OTP') freeipa-3.3.4/install/updates/62-ranges.update0000664000175000017500000000573112271663206020540 0ustar mkosekmkosekdn: cn=schema add:attributeTypes: (2.16.840.1.113730.3.8.11.33 NAME 'ipaBaseID' DESC 'First value 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' ) add: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' ) add: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' ) add: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' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.41 NAME 'ipaRangeType' DESC 'Range type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.14 NAME 'ipaIDobject' SUP top AUXILIARY MAY ( uidNumber $$ gidNumber $$ ipaNTSecurityIdentifier ) X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.15 NAME 'ipaIDrange' ABSTRACT MUST ( cn $$ ipaBaseID $$ ipaIDRangeSize ) X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.16 NAME 'ipaDomainIDRange' SUP ipaIDrange STRUCTURAL MAY ( ipaBaseRID $$ ipaSecondaryBaseRID ) X-ORIGIN 'IPA v3' ) add:objectClasses: (2.16.840.1.113730.3.8.12.17 NAME 'ipaTrustedADDomainRange' SUP ipaIDrange STRUCTURAL MUST ( ipaBaseRID $$ ipaNTTrustedDomainSID ) X-ORIGIN 'IPA v3' ) replace:objectClasses: (2.16.840.1.113730.3.8.12.15 NAME 'ipaIDrange' ABSTRACT MUST ( cn $$ ipaBaseID $$ ipaIDRangeSize ) X-ORIGIN 'IPA v3' )::(2.16.840.1.113730.3.8.12.15 NAME 'ipaIDrange' ABSTRACT MUST ( cn $$ ipaBaseID $$ ipaIDRangeSize $$ ipaRangeType ) X-ORIGIN 'IPA v3' ) dn: cn=ranges,cn=etc,$SUFFIX default: objectClass: top default: objectClass: nsContainer default: cn: ranges dn: cn=IPA Range-Check,cn=plugins,cn=config default: changetype: add default: objectclass: top default: objectclass: nsSlapdPlugin default: objectclass: extensibleObject default: cn: IPA Range-Check default: nsslapd-pluginpath: libipa_range_check default: nsslapd-plugininitfunc: ipa_range_check_init default: nsslapd-plugintype: preoperation default: nsslapd-pluginenabled: on default: nsslapd-pluginid: ipa_range_check_version default: nsslapd-pluginversion: 1.0 default: nsslapd-pluginvendor: Red Hat, Inc. default: nsslapd-plugindescription: IPA Range-Check plugin default: nsslapd-plugin-depends-on-type: database default: nsslapd-basedn: $SUFFIX # Add new ipaIDobject to DNA plugin configuraton dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config replace:dnaFilter:(|(objectclass=posixAccount)(objectClass=posixGroup))::(|(objectClass=posixAccount)(objectClass=posixGroup)(objectClass=ipaIDobject)) freeipa-3.3.4/install/updates/19-managed-entries.update0000664000175000017500000000102112202434255022304 0ustar mkosekmkosekdn: cn=Managed Entries,cn=plugins,cn=config only: nsslapd-pluginConfigArea: 'cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX' dn: cn=Managed Entries,cn=etc,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: Managed Entries dn: cn=Templates,cn=Managed Entries,cn=etc,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: Templates dn: cn=Definitions,cn=Managed Entries,cn=etc,$SUFFIX default: objectClass: nsContainer default: objectClass: top default: cn: Definitions freeipa-3.3.4/install/updates/20-winsync_index.update0000664000175000017500000000042412202434255022120 0ustar mkosekmkosek# # Make sure winsync attributes have the correct indexing # dn: cn=ntUniqueId,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only: nsIndexType: eq,pres dn: cn=ntUserDomainId,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only: nsIndexType: eq,pres freeipa-3.3.4/install/updates/10-sudo.update0000664000175000017500000000514712270466515020230 0ustar mkosekmkosek# Update the SUDO schema # These are the deltas from the new Sudo Schema # This is required for updating older installs which are # missing the new attributes. dn: cn=schema add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'SUDO' ) add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.8 NAME 'sudoNotBefore' DESC 'Start of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 X-ORIGIN 'SUDO' ) add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.9 NAME 'sudoNotAfter' DESC 'End of time interval for which the entry is valid' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 X-ORIGIN 'SUDO' ) add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10 NAME 'sudoOrder' DESC 'an integer to order the sudoRole entries' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'SUDO' ) replace:objectClasses:( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer Entries' STRUCTURAL MUST cn MAY ( sudoUser $$ sudoHost $$ sudoCommand $$ sudoRunAs $$ sudoOption $$ description ) X-ORIGIN 'SUDO' )::( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $$ sudoHost $$ sudoCommand $$ sudoRunAs $$ sudoRunAsUser $$ sudoRunAsGroup $$ sudoOption $$ sudoNotBefore $$ sudoNotAfter $$ sudoOrder $$ description ) X-ORIGIN 'SUDO') replace:objectClasses: ( 2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $$ externalHost $$ hostMask $$ memberAllowCmd $$ memberDenyCmd $$ cmdCategory $$ ipaSudoOpt $$ ipaSudoRunAs $$ ipaSudoRunAsExtUser $$ ipaSudoRunAsUserCategory $$ ipaSudoRunAsGroup $$ ipaSudoRunAsExtGroup $$ ipaSudoRunAsGroupCategory ) X-ORIGIN 'IPA v2' )::(2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $$ externalHost $$ hostMask $$ memberAllowCmd $$ memberDenyCmd $$ cmdCategory $$ ipaSudoOpt $$ ipaSudoRunAs $$ ipaSudoRunAsExtUser $$ ipaSudoRunAsUserCategory $$ ipaSudoRunAsGroup $$ ipaSudoRunAsExtGroup $$ ipaSudoRunAsGroupCategory $$ sudoNotBefore $$ sudoNotAfter $$ sudoOrder) X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/updates/10-60basev2.update0000664000175000017500000002256712270466515020613 0ustar mkosekmkosek# Fix some problems with the original 60basev2 schema file. dn: cn=schema replace:attributeTypes:( 2.16.840.1.113730.3.8.3.1 NAME 'ipaUniqueID' DESC 'Unique identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.1 NAME 'ipaUniqueID' DESC 'Unique identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes: ( 2.16.840.1.113730.3.8.3.2 NAME 'ipaClientVersion' DESC 'Text string describing client version of the IPA software installed' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.2 NAME 'ipaClientVersion' DESC 'Text string describing client version of the IPA software installed' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.3 NAME 'enrolledBy' DESC 'DN of administrator who performed manual enrollment of the host' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.3 NAME 'enrolledBy' DESC 'DN of administrator who performed manual enrollment of the host' SUP distinguishedName X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.4 NAME 'fqdn' DESC 'FQDN' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 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' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.18 NAME 'managedBy' DESC 'DNs of entries allowed to manage' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2')::( 2.16.840.1.113730.3.8.3.18 NAME 'managedBy' DESC 'DNs of entries allowed to manage' SUP distinguishedName X-ORIGIN 'IPA v2') replace:attributeTypes:( 2.16.840.1.113730.3.8.3.24 NAME 'ipaEntitlementId' DESC 'Entitlement Unique identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 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' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.5 NAME 'memberUser' DESC 'Reference to a principal that performs an action (usually user).' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.5 NAME 'memberUser' DESC 'Reference to a principal that performs an action (usually user).' SUP distinguishedName X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.6 NAME 'userCategory' DESC 'Additional classification for users' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.6 NAME 'userCategory' DESC 'Additional classification for users' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.7 NAME 'memberHost' DESC 'Reference to a device where the operation takes place (usually host).' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.7 NAME 'memberHost' DESC 'Reference to a device where the operation takes place (usually host).' SUP distinguishedName X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.8 NAME 'hostCategory' DESC 'Additional classification for hosts' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.8 NAME 'hostCategory' DESC 'Additional classification for hosts' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.19 NAME 'serviceCategory' DESC 'Additional classification for services' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.19 NAME 'serviceCategory' DESC 'Additional classification for services' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.20 NAME 'memberService' DESC 'Reference to the pam service of this operation.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.20 NAME 'memberService' DESC 'Reference to the pam service of this operation.' SUP distinguishedName X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.25 NAME 'ipaPermissionType' DESC 'IPA permission flags' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.25 NAME 'ipaPermissionType' DESC 'IPA permission flags' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes: (2.16.840.1.113730.3.8.3.9 NAME 'ipaEnabledFlag' DESC 'The flag to show if the association is active or should be ignored' EQUALITY booleanMatch ORDERING booleanMatch SUBSTR booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.9 NAME 'ipaEnabledFlag' DESC 'The flag to show if the association is active or should be ignored' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.11 NAME 'externalHost' DESC 'Multivalue string attribute that allows storing host names.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.11 NAME 'externalHost' DESC 'Multivalue string attribute that allows storing host names.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.12 NAME 'sourceHostCategory' DESC 'Additional classification for hosts' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.12 NAME 'sourceHostCategory' DESC 'Additional classification for hosts' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.13 NAME 'accessRuleType' DESC 'The flag to represent if it is allow or deny rule.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.13 NAME 'accessRuleType' DESC 'The flag to represent if it is allow or deny rule.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.14 NAME 'accessTime' DESC 'Access time' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.14 NAME 'accessTime' DESC 'Access time' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes: (2.16.840.1.113730.3.8.3.15 NAME 'nisDomainName' DESC 'NIS domain name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.15 NAME 'nisDomainName' DESC 'NIS domain name.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.3.17 NAME 'hostCApolicy' DESC 'Policy on how to treat host requests for cert operations.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.3.17 NAME 'hostCApolicy' DESC 'Policy on how to treat host requests for cert operations.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'IPA v2' ) freeipa-3.3.4/install/updates/10-uniqueness.update0000664000175000017500000000126012202434255021434 0ustar mkosekmkosekdn: cn=sudorule name uniqueness,cn=plugins,cn=config default:objectClass: top default:objectClass: nsSlapdPlugin default:objectClass: extensibleObject default:cn: sudorule name uniqueness default:nsslapd-pluginDescription: Enforce unique attribute values default:nsslapd-pluginPath: libattr-unique-plugin default:nsslapd-pluginInitfunc: NSUniqueAttr_Init default:nsslapd-pluginType: preoperation default:nsslapd-pluginEnabled: on default:nsslapd-pluginarg0: cn default:nsslapd-pluginarg1: cn=sudorules,cn=sudo,$SUFFIX default:nsslapd-plugin-depends-on-type: database default:nsslapd-pluginId: NSUniqueAttr default:nsslapd-pluginVersion: 1.1.0 default:nsslapd-pluginVendor: Fedora Project freeipa-3.3.4/install/updates/40-replication.update0000664000175000017500000000166012271663206021563 0ustar mkosekmkosek# Let a delegated user put the database into read-only mode when deleting # an agreement. dn: cn=userRoot,cn=ldbm database,cn=plugins,cn=config add:aci: '(targetattr=nsslapd-readonly)(version 3.0; acl "Allow marking the database readonly"; allow (write) groupdn = "ldap:///cn=Remove Replication Agreements,cn=permissions,cn=pbac,$SUFFIX";)' # Add rules to manage DNA ranges dn: cn=Modify DNA Range,cn=permissions,cn=pbac,$SUFFIX default:objectClass: top default:objectClass: groupofnames default:objectClass: ipapermission default:cn: Modify DNA Range default:ipapermissiontype: SYSTEM default:member: cn=Replication Administrators,cn=privileges,cn=pbac,$SUFFIX dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config add:aci: '(targetattr=dnaNextRange || dnaNextValue || dnaMaxValue)(version 3.0;acl "permission:Modify DNA Range";allow (write) groupdn = "ldap:///cn=Modify DNA Range,cn=permissions,cn=pbac,$SUFFIX";)' freeipa-3.3.4/install/updates/61-trusts-s4u2proxy.update0000664000175000017500000000046612202434255022513 0ustar mkosekmkosekdn: cn=ipa-cifs-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX default: objectClass: groupOfPrincipals default: objectClass: top default: cn: ipa-cifs-delegation-targets dn: cn=ipa-http-delegation,cn=s4u2proxy,cn=etc,$SUFFIX add: ipaAllowedTarget: 'cn=ipa-cifs-delegation-targets,cn=s4u2proxy,cn=etc,$SUFFIX' freeipa-3.3.4/install/updates/10-60basev3.update0000664000175000017500000001112312271663206020573 0ustar mkosekmkosekdn: cn=schema add:attributeTypes: ( 2.16.840.1.113730.3.8.11.20 NAME 'memberPrincipal' DESC 'Principal names member of a groupOfPrincipals group' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA-v3') add:attributeTypes: ( 2.16.840.1.113730.3.8.11.21 NAME 'ipaAllowToImpersonate' DESC 'Principals that can be impersonated' SUP distinguishedName X-ORIGIN 'IPA-v3') add:attributeTypes: ( 2.16.840.1.113730.3.8.11.22 NAME 'ipaAllowedTarget' DESC 'Target principals alowed to get a ticket for' SUP distinguishedName X-ORIGIN 'IPA-v3') 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' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.7.1 NAME 'memberAllowCmd' DESC 'Reference to a command or group of commands that are allowed by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.7.1 NAME 'memberAllowCmd' DESC 'Reference to a command or group of commands that are allowed by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) replace:attributeTypes:( 2.16.840.1.113730.3.8.7.2 NAME 'memberDenyCmd' DESC 'Reference to a command or group of commands that are denied by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' )::( 2.16.840.1.113730.3.8.7.2 NAME 'memberDenyCmd' DESC 'Reference to a command or group of commands that are denied by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) add:attributeTypes: (2.16.840.1.113730.3.8.11.1 NAME 'ipaExternalMember' DESC 'External Group Member Identifier' EQUALITY caseIgnoreMatch ORDERING caseIgnoreOrderingMatch 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.1 NAME 'ipaExternalGroup' SUP top STRUCTURAL MUST ( cn ) MAY ( ipaExternalMember $$ memberOf $$ description $$ owner) X-ORIGIN 'IPA v3' ) replace:objectClasses: (2.16.840.1.113730.3.8.4.1 NAME 'ipaHost' AUXILIARY MUST ( fqdn ) MAY ( userPassword $$ ipaClientVersion $$ enrolledBy $$ memberOf ) X-ORIGIN 'IPA v2' )::(2.16.840.1.113730.3.8.4.1 NAME 'ipaHost' AUXILIARY MUST ( fqdn ) MAY ( userPassword $$ ipaClientVersion $$ enrolledBy $$ memberOf $$ userClass ) X-ORIGIN 'IPA v2' ) # Fix dc syntax (RFC 2247) replace:attributeTypes:"( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domaincomponent' ) DESC 'Standard LDAP attribute type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2247' )::( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domaincomponent' ) DESC 'Standard LDAP attribute type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2247' )" # Add ipaUserAuthType and ipaUserAuthTypeClass add:attributeTypes: (2.16.840.1.113730.3.8.11.40 NAME 'ipaUserAuthType' DESC 'Allowed authentication methods' EQUALITY caseIgnoreMatch 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.19 NAME 'ipaUserAuthTypeClass' SUP top AUXILIARY DESC 'Class for authentication methods definition' MAY ipaUserAuthType X-ORIGIN 'IPA v3') freeipa-3.3.4/install/updates/40-realm_domains.update0000664000175000017500000000035512271663206022064 0ustar mkosekmkosek# Add the Realm Domains container dn: cn=Realm Domains,cn=ipa,cn=etc,$SUFFIX default:objectClass: domainRelatedObject default:objectClass: nsContainer default:objectClass: top default:cn: Realm Domains default:associatedDomain: $DOMAIN freeipa-3.3.4/install/updates/Makefile.in0000664000175000017500000003402212271707662017675 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = updates DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/updates app_DATA = \ 10-60basev2.update \ 10-60basev3.update \ 10-70ipaotp.update \ 10-RFC2307bis.update \ 10-RFC4876.update \ 10-config.update \ 10-enable-betxn.update \ 10-selinuxusermap.update \ 10-sudo.update \ 10-ssh.update \ 10-bind-schema.update \ 10-uniqueness.update \ 10-schema_compat.update \ 19-managed-entries.update \ 20-aci.update \ 20-dna.update \ 20-host_nis_groups.update \ 20-indices.update \ 20-nss_ldap.update \ 20-replication.update \ 20-user_private_groups.update \ 20-winsync_index.update \ 21-replicas_container.update \ 21-ca_renewal_container.update \ 25-referint.update \ 30-s4u2proxy.update \ 40-delegation.update \ 40-realm_domains.update \ 40-replication.update \ 40-dns.update \ 40-automember.update \ 40-otp.update \ 45-roles.update \ 50-7_bit_check.update \ 50-lockout-policy.update \ 50-groupuuid.update \ 50-hbacservice.update \ 50-krbenctypes.update \ 50-nis.update \ 50-ipaconfig.update \ 55-pbacmemberof.update \ 60-trusts.update \ 61-trusts-s4u2proxy.update \ 62-ranges.update \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign updates/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign updates/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/updates/20-indices.update0000664000175000017500000001030412271663206020661 0ustar mkosekmkosek# # Some nss_ldap implementations will always ask for memberuid so we must # have an index for it. # # FreeIPA frequently searches for memberHost and memberUser to determine # group membership. # dn: cn=memberuid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberuid default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq,pres dn: cn=memberHost,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberHost default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=memberUser,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberUser default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=member,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,sub dn: cn=uniquemember,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,sub dn: cn=owner,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,sub dn: cn=manager,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,pres,sub dn: cn=secretary,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,pres,sub dn: cn=seealso,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config only:nsIndexType: eq,sub dn: cn=memberof,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberof default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq dn: cn=fqdn,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: fqdn default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq default:nsIndexType: pres dn: cn=macAddress,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: macAddress default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq default:nsIndexType: pres dn: cn=sourcehost,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: sourcehost default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=memberservice,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberservice default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=managedby,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: managedby default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=memberallowcmd,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberallowcmd default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=memberdenycmd,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: memberdenycmd default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=ipasudorunas,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: ipasudorunas default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=ipasudorunasgroup,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: ipasudorunasgroup default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false only:nsIndexType: eq,pres,sub dn: cn=automountkey,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: automountkey default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq dn: cn=ipakrbprincipalalias,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: ipakrbprincipalalias default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq dn: cn=ipauniqueid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config default:cn: ipauniqueid default:ObjectClass: top default:ObjectClass: nsIndex default:nsSystemIndex: false default:nsIndexType: eq freeipa-3.3.4/install/updates/50-krbenctypes.update0000664000175000017500000000042012271663206021575 0ustar mkosekmkosekdn: cn=$REALM,cn=kerberos,$SUFFIX add: krbSupportedEncSaltTypes: camellia128-cts-cmac:normal add: krbSupportedEncSaltTypes: camellia128-cts-cmac:special add: krbSupportedEncSaltTypes: camellia256-cts-cmac:normal add: krbSupportedEncSaltTypes: camellia256-cts-cmac:special freeipa-3.3.4/install/updates/40-dns.update0000664000175000017500000001522412271663206020037 0ustar mkosekmkosek# Add missing member values to attach permissions to their respective # privileges # Memberof task is already being run in 55-pbacmemberof.update dn: cn=add dns entries,cn=permissions,cn=pbac,$SUFFIX addifexist:objectclass: ipapermission addifexist:member: 'cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX' addifexist:member: 'cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX' dn: cn=remove dns entries,cn=permissions,cn=pbac,$SUFFIX addifexist:objectclass: ipapermission addifexist:member: 'cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX' addifexist:member: 'cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX' dn: cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX addifexist:objectclass: ipapermission addifexist:member: 'cn=DNS Administrators,cn=privileges,cn=pbac,$SUFFIX' addifexist:member: 'cn=DNS Servers,cn=privileges,cn=pbac,$SUFFIX' dn: cn=Write DNS Configuration,cn=permissions,cn=pbac,$SUFFIX addifexist:objectclass: ipapermission # update DNS container dn: cn=dns, $SUFFIX addifexist: objectClass: idnsConfigObject addifexist: aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Add DNS entries in a zone";allow (add) userattr = "parent[1].managedby#GROUPDN";)' addifexist: aci:'(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Remove DNS entries from a zone";allow (delete) userattr = "parent[1].managedby#GROUPDN";)' addifexist: aci:'(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "Update DNS entries in a zone";allow (write) userattr = "parent[0,1].managedby#GROUPDN";)' # update DNS acis with new idnsRecord attributes dn: $SUFFIX replace:aci:'(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)::(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || managedby")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)' replace:aci:'(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)::(targetattr = "idnsname || cn || idnsallowdynupdate || dnsttl || dnsclass || arecord || aaaarecord || a6record || nsrecord || cnamerecord || ptrrecord || srvrecord || txtrecord || mxrecord || mdrecord || hinforecord || minforecord || afsdbrecord || sigrecord || keyrecord || locrecord || nxtrecord || naptrrecord || kxrecord || certrecord || dnamerecord || dsrecord || sshfprecord || rrsigrecord || nsecrecord || idnsname || idnszoneactive || idnssoamname || idnssoarname || idnssoaserial || idnssoarefresh || idnssoaretry || idnssoaexpire || idnssoaminimum || idnsupdatepolicy || idnsallowquery || idnsallowtransfer || idnsallowsyncptr || idnsforwardpolicy || idnsforwarders || managedby")(target = "ldap:///idnsname=*,cn=dns,$SUFFIX")(version 3.0;acl "permission:update dns entries";allow (write) groupdn = "ldap:///cn=update dns entries,cn=permissions,cn=pbac,$SUFFIX";)' # replace DNS tree deny rule with managedBy enhanced allow rule dn: cn=dns, $SUFFIX replace:aci:'(targetattr = "*")(version 3.0; acl "No access to DNS tree without a permission"; deny (read,search,compare) (groupdn != "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX") and (groupdn != "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX");)::(targetattr = "*")(version 3.0; acl "Allow read access"; allow (read,search,compare) groupdn = "ldap:///cn=Read DNS Entries,cn=permissions,cn=pbac,$SUFFIX" or userattr = "parent[0,1].managedby#GROUPDN";)' # add DNS plugin dn: cn=IPA DNS,cn=plugins,cn=config default: objectclass: top default: objectclass: nsslapdPlugin default: objectclass: extensibleObject default: cn: IPA DNS default: nsslapd-plugindescription: IPA DNS support plugin default: nsslapd-pluginenabled: on default: nsslapd-pluginid: ipa_dns default: nsslapd-plugininitfunc: ipadns_init default: nsslapd-pluginpath: libipa_dns.so default: nsslapd-plugintype: preoperation default: nsslapd-pluginvendor: Red Hat, Inc. default: nsslapd-pluginversion: 1.0 default: nsslapd-plugin-depends-on-type: database freeipa-3.3.4/install/updates/10-selinuxusermap.update0000664000175000017500000000662112271663206022335 0ustar mkosekmkosek# Add the SELinux User map config schema dn: cn=schema add:attributeTypes: ( 2.16.840.1.113730.3.8.3.26 NAME 'ipaSELinuxUserMapDefault' DESC 'Default SELinux user' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch 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.3.27 NAME 'ipaSELinuxUserMapOrder' DESC 'Available SELinux user context ordering' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE 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 NAME 'ipaSELinuxUser' DESC 'An SELinux user' 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:objectClasses: ( 2.16.840.1.113730.3.8.12.10 NAME 'ipaSELinuxUserMap' SUP ipaAssociation STRUCTURAL MUST ipaSELinuxUser MAY ( accessTime $$ seeAlso ) X-ORIGIN 'IPA v3') # Create the SELinux User map container dn: cn=selinux,$SUFFIX default:objectClass: top default:objectClass: nsContainer default:cn: selinux dn: cn=usermap,cn=selinux,$SUFFIX default:objectClass: top default:objectClass: nsContainer default:cn: usermap freeipa-3.3.4/install/updates/10-RFC2307bis.update0000664000175000017500000000411612270466515020675 0ustar mkosekmkosek# # Schema derived from RFC 2307bis: # "An Approach for Using LDAP as a Network Information Service" # dn: cn=schema add: attributeTypes: ( 1.3.6.1.1.1.1.28 NAME 'nisPublickey' DESC 'nisPublickey' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 1.3.6.1.1.1.1.29 NAME 'nisSecretkey' DESC 'nisSecretkey' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 1.3.6.1.4.1.1.1.1.12 NAME 'nisDomain' DESC 'NIS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 2.16.840.1.113730.3.1.30 NAME 'mgrpRFC822MailMember' DESC 'mgrpRFC822MailMember' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 1.3.6.1.4.1.42.2.27.1.1.12 NAME 'nisNetIdUser' DESC 'nisNetIdUser' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 1.3.6.1.4.1.42.2.27.1.1.13 NAME 'nisNetIdGroup' DESC 'nisNetIdGroup' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:attributeTypes: ( 1.3.6.1.4.1.42.2.27.1.1.14 NAME 'nisNetIdHost' DESC 'nisNetIdHost' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC2307bis' ) add:objectClasses: ( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' DESC 'nisKeyObject' SUP top MUST ( cn $$ nisPublickey $$ nisSecretkey ) MAY ( uidNumber $$ description ) ) add:objectClasses: ( 1.3.1.6.1.1.1.2.15 NAME 'nisDomainObject' DESC 'nisDomainObject' SUP top AUXILIARY MUST ( nisDomain ) ) add:objectClasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' DESC 'mailGroup' SUP top MUST ( mail ) MAY ( cn $$ mgrpRFC822MailMember ) ) add:objectClasses: ( 1.3.6.1.4.1.42.2.27.1.2.6 NAME 'nisNetId' DESC 'nisNetId' SUP top MUST ( cn ) MAY ( nisNetIdUser $$ nisNetIdGroup $$ nisNetIdHost ) ) freeipa-3.3.4/install/updates/README0000664000175000017500000000152312271663206016503 0ustar mkosekmkosekThe update files are sorted before being processed because there are cases where order matters (such as getting schema added first, creating parent entries, etc). Updates are applied in blocks of ten so that any entries that are dependant on another can be added successfully without having to rely on the length of the DN to get the sorting correct. The file names should use the format #-.update where # conforms to this: 10 - 19: Schema 20 - 29: 389-ds configuration, new indices 30 - 39: Structual elements of the DIT 40 - 49: Pre-loaded data 50 - 59: Cleanup existing data 60 - 69: AD Trust 70 - 79: Reserved 80 - 89: Reserved These numbers aren't absolute, there may be reasons to put an update into one place or another, but by adhereing to the scheme it will be easier to find existing updates and know where to put new ones. freeipa-3.3.4/install/restart_scripts/0000775000175000017500000000000012271707664017417 5ustar mkosekmkosekfreeipa-3.3.4/install/restart_scripts/restart_dirsrv0000664000175000017500000000240412270466515022413 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import sys import syslog from ipapython import services as ipaservices from ipalib import api try: instance = sys.argv[1] except IndexError: instance = "" api.bootstrap(context='restart') api.finalize() syslog.syslog(syslog.LOG_NOTICE, "certmonger restarted dirsrv instance '%s'" % instance) try: ipaservices.knownservices.dirsrv.restart(instance) except Exception, e: syslog.syslog(syslog.LOG_ERR, "Cannot restart dirsrv (instance: '%s'): %s" % (instance, str(e))) freeipa-3.3.4/install/restart_scripts/Makefile.am0000664000175000017500000000063512202434255021442 0ustar mkosekmkosekNULL = appdir = $(libdir)/ipa/certmonger app_DATA = \ restart_dirsrv \ restart_httpd \ restart_pkicad \ renew_ca_cert \ renew_ra_cert \ stop_pkicad \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/restart_scripts/restart_pkicad0000664000175000017500000000477712271663206022351 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import sys import syslog from ipapython import services as ipaservices from ipapython import dogtag from ipaserver.install import certs from ipalib import api nickname = sys.argv[1] api.bootstrap(context='restart') api.finalize() configured_constants = dogtag.configured_constants(api) alias_dir = configured_constants.ALIAS_DIR dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] dogtag_instance = configured_constants.PKI_INSTANCE_NAME # dogtag opens its NSS database in read/write mode so we need it # shut down so certmonger can open it read/write mode. This avoids # database corruption. It should already be stopped by the pre-command # but lets be sure. if dogtag_service.is_running(dogtag_instance): syslog.syslog( syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name) try: dogtag_service.stop(dogtag_instance) except Exception, e: syslog.syslog( syslog.LOG_ERR, "Cannot stop %s: %s" % (dogtag_service.service_name, e)) else: syslog.syslog( syslog.LOG_NOTICE, "Stopped %s" % dogtag_service.service_name) # Fix permissions on the audit cert if we're updating it if nickname == 'auditSigningCert cert-pki-ca': db = certs.CertDB(api.env.realm, nssdir=alias_dir) args = ['-M', '-n', nickname, '-t', 'u,u,Pu', ] db.run_certutil(args) syslog.syslog(syslog.LOG_NOTICE, 'Starting %s' % dogtag_service.service_name) try: dogtag_service.start(dogtag_instance) except Exception, e: syslog.syslog( syslog.LOG_ERR, "Cannot start %s: %s" % (dogtag_service.service_name, e)) else: syslog.syslog( syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name) freeipa-3.3.4/install/restart_scripts/renew_ca_cert0000664000175000017500000001034012271663206022131 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import os import sys import shutil import tempfile import syslog import random import time from ipalib import api from ipapython.dn import DN from ipalib import errors from ipapython import services as ipaservices from ipapython import ipautil from ipapython import dogtag from ipaserver.install import certs from ipaserver.install.cainstance import update_people_entry from ipaserver.plugins.ldap2 import ldap2 from ipaserver.install.cainstance import update_cert_config from ipapython import certmonger # This script a post-cert-install command for certmonger. When certmonger # has renewed a CA subsystem certificate a copy is put into the replicated # tree so it can be shared with the other IPA servers. nickname = sys.argv[1] api.bootstrap(context='restart') api.finalize() configured_constants = dogtag.configured_constants(api) alias_dir = configured_constants.ALIAS_DIR dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] dogtag_instance = configured_constants.PKI_INSTANCE_NAME # Fetch the new certificate db = certs.CertDB(api.env.realm, nssdir=alias_dir) cert = db.get_cert_from_db(nickname, pem=False) if not cert: syslog.syslog(syslog.LOG_ERR, 'No certificate %s found.' % nickname) sys.exit(1) # Update or add it tmpdir = tempfile.mkdtemp(prefix = "tmp-") try: dn = DN(('cn',nickname), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) principal = str('host/%s@%s' % (api.env.host, api.env.realm)) ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal) conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri) conn.connect(ccache=ccache) try: (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate']) entry_attrs['usercertificate'] = cert conn.update_entry(dn, entry_attrs) except errors.NotFound: entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'], usercertificate=cert) conn.add_entry(dn, entry_attrs) except errors.EmptyModlist: pass conn.disconnect() except Exception, e: syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s' % e) finally: shutil.rmtree(tmpdir) # Done withing stopped_service context, CA restarted here update_cert_config(nickname, cert) if nickname == 'subsystemCert cert-pki-ca': update_people_entry('pkidbuser', cert) if nickname == 'auditSigningCert cert-pki-ca': # Fix trust on the audit cert db = certs.CertDB(api.env.realm, nssdir=alias_dir) args = ['-M', '-n', nickname, '-t', 'u,u,Pu', ] try: db.run_certutil(args) syslog.syslog(syslog.LOG_NOTICE, 'Updated trust on certificate %s in %s' % (nickname, db.secdir)) except ipautil.CalledProcessError: syslog.syslog(syslog.LOG_ERR, 'Updating trust on certificate %s failed in %s' % (nickname, db.secdir)) # Now we can start the CA. Using the ipaservices start should fire # off the servlet to verify that the CA is actually up and responding so # when this returns it should be good-to-go. The CA was stopped in the # pre-save state. syslog.syslog(syslog.LOG_NOTICE, 'Starting %s' % dogtag_service.service_name) try: dogtag_service.start(dogtag_instance) except Exception, e: syslog.syslog( syslog.LOG_ERR, "Cannot start %s: %s" % (dogtag_service.service_name, e)) else: syslog.syslog( syslog.LOG_NOTICE, "Started %s" % dogtag_service.service_name) freeipa-3.3.4/install/restart_scripts/stop_pkicad0000664000175000017500000000274012271663206021636 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import sys import syslog from ipapython import services as ipaservices from ipapython import dogtag from ipalib import api api.bootstrap(context='restart') api.finalize() configured_constants = dogtag.configured_constants(api) dogtag_service = ipaservices.knownservices[configured_constants.SERVICE_NAME] dogtag_instance = configured_constants.PKI_INSTANCE_NAME syslog.syslog(syslog.LOG_NOTICE, "Stopping %s" % dogtag_service.service_name) try: dogtag_service.stop(dogtag_instance) except Exception, e: syslog.syslog( syslog.LOG_ERR, "Cannot stop %s: %s" % (dogtag_service.service_name, e)) else: syslog.syslog( syslog.LOG_NOTICE, "Stopped %s" % dogtag_service.service_name) freeipa-3.3.4/install/restart_scripts/renew_ra_cert0000664000175000017500000000602612271663206022156 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import sys import shutil import tempfile import syslog import time from ipapython import services as ipaservices from ipapython import ipautil from ipaserver.install import certs from ipaserver.install.cainstance import update_people_entry from ipalib import api from ipapython.dn import DN from ipalib import errors from ipaserver.plugins.ldap2 import ldap2 api.bootstrap(context='restart') api.finalize() # Fetch the new certificate db = certs.CertDB(api.env.realm) dercert = db.get_cert_from_db('ipaCert', pem=False) # Load it into dogtag update_people_entry('ipara', dercert) attempts = 0 updated = False # Store it in the IPA LDAP server while attempts < 10: conn = None tmpdir = None try: tmpdir = tempfile.mkdtemp(prefix="tmp-") dn = DN(('cn','ipaCert'), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn) principal = str('host/%s@%s' % (api.env.host, api.env.realm)) ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal) conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri) conn.connect(ccache=ccache) try: (entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate']) entry_attrs['usercertificate'] = dercert conn.update_entry(dn, entry_attrs) except errors.NotFound: entry_attrs = dict(objectclass=['top', 'pkiuser', 'nscontainer'], usercertificate=dercert) conn.add_entry(dn, entry_attrs) except errors.EmptyModlist: pass updated = True break except Exception, e: syslog.syslog(syslog.LOG_ERR, 'Updating renewal certificate failed: %s. Sleeping 30s' % e) time.sleep(30) attempts += 1 finally: if conn is not None and conn.isconnected(): conn.disconnect() if tmpdir is not None: shutil.rmtree(tmpdir) if not updated: syslog.syslog(syslog.LOG_ERR, '%s: Giving up. This script may be safely re-executed.' % sys.argv[0]) sys.exit(1) # Now restart Apache so the new certificate is available try: ipaservices.knownservices.httpd.restart() except Exception, e: syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e)) freeipa-3.3.4/install/restart_scripts/Makefile.in0000664000175000017500000003224012271707662021463 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = restart_scripts DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(libdir)/ipa/certmonger app_DATA = \ restart_dirsrv \ restart_httpd \ restart_pkicad \ renew_ca_cert \ renew_ra_cert \ stop_pkicad \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign restart_scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign restart_scripts/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/restart_scripts/restart_httpd0000664000175000017500000000205212270466515022224 0ustar mkosekmkosek#!/usr/bin/python -E # # Authors: # Rob Crittenden # # 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 . import syslog from ipapython import services as ipaservices syslog.syslog(syslog.LOG_NOTICE, 'certmonger restarted httpd') try: ipaservices.knownservices.httpd.restart() except Exception, e: syslog.syslog(syslog.LOG_ERR, "Cannot restart httpd: %s" % str(e)) freeipa-3.3.4/install/restart_scripts/README0000664000175000017500000000021312202434255020256 0ustar mkosekmkosekThis directory contains scripts to be used by the command (-C) option of certmonger to restart services when the certificates are renewed. freeipa-3.3.4/install/html/0000775000175000017500000000000012271707664015130 5ustar mkosekmkosekfreeipa-3.3.4/install/html/ffconfig_page.js0000664000175000017500000001077312202434255020236 0ustar mkosekmkosek/* Authors: * Petr Vobornik * * 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 . */ $(document).ready(function() { var set_enabled = function(steps, enabled) { var method; if (enabled) method = function(el) { el.removeClass('ui-state-disabled'); }; else method = function(el) { el.addClass('ui-state-disabled'); }; for (var i=0; i b_num) return 1; else if (a_num < b_num) return -1; } if (a_parts.length !== b_parts.length) { return a_parts.length > b_parts.length ? 1 : -1; } return 0; }; $('#install-link').click(install); $('#reinstall-link').click(install); $('#configure-link').click(configure); $('#notfirefox-link').button(); $('#ca-link').button(); $('#oldfirefox-link').button(); $('#reinstall-link').button(); $('#install-link').button(); $('#configure-link').button(); $('#return-link').button(); check_version(); show_installed(IPA.browser_config.extension_installed()); });freeipa-3.3.4/install/html/ipa_error.css0000664000175000017500000000101112202434255017600 0ustar mkosekmkosek/* Authors: * Pavel Zuna * Adam Young * Endi Sukma Dewata * Kyle Baker * * Copyright (C) 2010 Red Hat */ /* ssbrowser */ .ssbrowser h2 { font-family: 'Overpass Bold'; font-size: 1em; font-weight: bold; margin-bottom: 3em; margin-left: 5em; margin-top: -3em; } .ssbrowser h3 { font-size: 1.1em; margin-bottom: 1em; } /* Browser configuration */ object.browser-config { width: 100%; } freeipa-3.3.4/install/html/Makefile.am0000664000175000017500000000066012202434255017151 0ustar mkosekmkosekNULL = appdir = $(IPA_SYSCONF_DIR)/html app_DATA = \ ffconfig.js \ ffconfig_page.js \ ssbrowser.html \ browserconfig.html \ unauthorized.html \ ipa_error.css \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/html/ffconfig.js0000664000175000017500000000546712202434255017246 0ustar mkosekmkosek/* Authors: * Petr Vobornik * * 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 . */ var IPA = IPA || {}; IPA.browser_config = { configure_firefox: function(domain) { var self = this; domain = domain || self.get_domain(); self.send_message({ method: 'configure', predefined: 'ipa', trusted_uris: domain }); }, get_configure_result: function() { var self = this; var el = self.get_data_element(); var answer = el.getAttribute('answer'); return answer; }, get_domain: function() { return "."+IPA_DOMAIN; }, send_message: function(options) { options = options || {}; var self = this; self.clear_data_element(); var opt_element = self.get_data_element(); for (var opt in options) { opt_element.setAttribute(opt, options[opt]); } var msg_evt = document.createEvent('HTMLEvents'); msg_evt.initEvent('kerberos-auth-config', true, false); opt_element.dispatchEvent(msg_evt); }, get_data_element: function() { var els = document.getElementsByTagName('kerberosauthdataelement'); var element; if (els.length === 0) { element = document.createElement('kerberosauthdataelement'); document.documentElement.appendChild(element); } else { element = els[0]; } return element; }, clear_data_element: function() { var self = this; var el = self.get_data_element(); var to_remove = []; for (var i=0; i IPA: Identity Policy Audit

Unable to verify your Kerberos credentials

Please make sure that you have valid Kerberos tickets (obtainable via kinit), and that you have configured your browser correctly.

Browser configuration

If this is your first time, please configure your browser. Use Firefox configuration page for Firefox or manual configuration page for other browsers.

freeipa-3.3.4/install/html/ssbrowser.html0000664000175000017500000001012012271663206020032 0ustar mkosekmkosek IPA: Identity Policy Audit

Browser Kerberos Setup

Internet Explorer

Internet Explorer Configuration

Once you are able to log into the workstation with your kerberos key you are now able to use that ticket in Internet Explorer.

Login to the Windows machine using an account of your Kerberos realm (administrative domain)
In Internet Explorer, click Tools, and then click Internet Options.
  • 1. Click the Security tab
  • 2. Click Local intranet
  • 3. Click Sites
  • 4. Click Advanced
  • 5. Add your domain to the list

  • 1. Click the Security tab
  • 2. Click Local intranet
  • 3. Click Custom Level
  • 4. Select Automatic logon only in Intranet zone

  • Visit a kerberized web site using IE (You must use the fully-qualified Domain Name in the URL)
  • You are all set.

Firefox

Firefox Configuration

You can configure Firefox to use Kerberos for Single Sign-on. The following instructions will guide you in configuring your web browser
to send your Kerberos credentials to the appropriate Key Distribution Center which enables Single Sign-on.

  • 1. In the address bar of Firefox, type about:config to display the list of current configuration options.
  • 2. In the Filter field, type negotiate to restrict the list of options.
  • 3. Double-click the network.negotiate-auth.trusted-uris entry to display the Enter string value dialog box.
  • 4. Enter the name of the domain against which you want to authenticate, for example, .example.com.

  • You are all set.

Automatic Configuration of older versions

You can configure older versions of Firefox (up to version 14) using signed code. Use Firefox configuration page for newer versions.

  • 1. Import CA certificate. Make sure you checked all three checkboxes.
  • 2. Click on "Configure Browser" button below.
freeipa-3.3.4/install/html/browserconfig.html0000664000175000017500000000755612271663206020675 0ustar mkosekmkosek IPA: Identity Policy Audit

Firefox configuration

Step 1

Import Certificate Authority certificate

Make sure you select all three checkboxes.

Step 2

Re-install extension

Extension installed. You can proceed to Step 3.

Install Kerberos Configuration Firefox extension

Kerberos Configuration extension is required for Step 3

Step 3

Configure browser

freeipa-3.3.4/install/html/jsl.conf0000664000175000017500000001376112202434255016562 0ustar mkosekmkosek# # Configuration File for JavaScript Lint 0.3.0 # Developed by Matthias Miller (http://www.JavaScriptLint.com) # # This configuration file can be used to lint a collection of scripts, or to enable # or disable warnings for scripts that are linted via the command line. # ### Warnings # Enable or disable warnings based on requirements. # Use "+WarningName" to display or "-WarningName" to suppress. # +no_return_value # function {0} does not always return a value +duplicate_formal # duplicate formal argument {0} +equal_as_assign # test for equality (==) mistyped as assignment (=)?{0} +var_hides_arg # variable {0} hides argument +redeclared_var # redeclaration of {0} {1} +anon_no_return_value # anonymous function does not always return a value +missing_semicolon # missing semicolon +meaningless_block # meaningless block; curly braces have no impact +comma_separated_stmts # multiple statements separated by commas (use semicolons?) +unreachable_code # unreachable code +missing_break # missing break statement +missing_break_for_last_case # missing break statement for last case in switch +comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==) +inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement +useless_void # use of the void type may be unnecessary (void is always undefined) +multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs +use_of_label # use of label -block_without_braces # block statement without curly braces +leading_decimal_point # leading decimal point may indicate a number or an object member +trailing_decimal_point # trailing decimal point may indicate a number or an object member +octal_number # leading zeros make an octal number +nested_comment # nested comment +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma +ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +empty_statement # empty statement or extra semicolon -missing_option_explicit # the "option explicit" control comment is missing +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag +dup_option_explicit # duplicate "option explicit" control comment +useless_assign # useless assignment +ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity +ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent) +missing_default_case # missing default case in switch statement +duplicate_case_in_switch # duplicate case in switch statements +default_not_at_end # the default case is not at the end of the switch statement +legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax +jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax +useless_comparison # useless comparison; comparing identical expressions +with_statement # with statement hides undeclared variables; use temporary variable instead +trailing_comma_in_array # extra comma is not recommended in array initializers +assign_to_function_call # assignment to a function call +parseint_missing_radix # parseInt missing radix parameter ### Output format # Customize the format of the error message. # __FILE__ indicates current file path # __FILENAME__ indicates current file name # __LINE__ indicates current line # __ERROR__ indicates error message # # Visual Studio syntax (default): +output-format __FILE__(__LINE__): __ERROR__ # Alternative syntax: #+output-format __FILE__:__LINE__: __ERROR__ ### Context # Show the in-line position of the error. # Use "+context" to display or "-context" to suppress. # +context ### Semicolons # By default, assignments of an anonymous function to a variable or # property (such as a function prototype) must be followed by a semicolon. # +lambda_assign_requires_semicolon ### Control Comments # Both JavaScript Lint and the JScript interpreter confuse each other with the syntax for # the /*@keyword@*/ control comments and JScript conditional comments. (The latter is # enabled in JScript with @cc_on@). The /*jsl:keyword*/ syntax is preferred for this reason, # although legacy control comments are enabled by default for backward compatibility. # +legacy_control_comments ### JScript Function Extensions # JScript allows member functions to be defined like this: # function MyObj() { /*constructor*/ } # function MyObj.prototype.go() { /*member function*/ } # # It also allows events to be attached like this: # function window::onload() { /*init page*/ } # # This is a Microsoft-only JavaScript extension. Enable this setting to allow them. # -jscript_function_extensions ### Defining identifiers # By default, "option explicit" is enabled on a per-file basis. # To enable this for all files, use "+always_use_option_explicit" #-always_use_option_explicit +always_use_option_explicit # Define certain identifiers of which the lint is not aware. # (Use this in conjunction with the "undeclared identifier" warning.) # # Common uses for webpages might be: +define window +define document +define alert +define $ +define jQuery +define IPA_DOMAIN +define IPA_REALM +define IPA ### Files # Specify which files to lint # Use "+recurse" to enable recursion (disabled by default). # To add a set of files, use "+process FileName", "+process Folder\Path\*.js", # or "+process Folder\Path\*.htm". # +process ffconfig.js +process ffconfig_page.jsfreeipa-3.3.4/install/html/Makefile.in0000664000175000017500000003221312271707662017174 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = html DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_SYSCONF_DIR)/html app_DATA = \ ffconfig.js \ ffconfig_page.js \ ssbrowser.html \ browserconfig.html \ unauthorized.html \ ipa_error.css \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign html/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign html/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/wsgi/0000775000175000017500000000000012271707664015135 5ustar mkosekmkosekfreeipa-3.3.4/install/wsgi/Makefile.am0000664000175000017500000000037612271663206017170 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/wsgi app_DATA = \ plugins.py \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/wsgi/plugins.py0000664000175000017500000000333012271663206017160 0ustar mkosekmkosek# Authors: Petr Vobornik # # Copyright (C) 2013 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 . # """ Plugin index generation script """ import os from ipapython.ipa_log_manager import root_logger PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins" def get_plugin_index(): if not os.path.isdir(PLUGINS_DIR): raise Exception("Supplied plugin directory path is not a directory") dirs = os.listdir(PLUGINS_DIR) index = 'define([],function(){return[' index += ','.join("'"+x+"'" for x in dirs) index += '];});' return index def get_failed(): return 'define([],function(){return[];});/*error occured: serving default */' def application(environ, start_response): try: index = get_plugin_index() status = '200 OK' except Exception, e: root_logger.error('plugin index generation failed: %s' % e) status = '200 OK' index = get_failed() headers = [('Content-type', 'application/javascript'), ('Content-Length', str(len(index)))] start_response(status, headers) return [index] freeipa-3.3.4/install/wsgi/Makefile.in0000664000175000017500000003175112271707662017207 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = wsgi DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/wsgi app_DATA = \ plugins.py \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign wsgi/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign wsgi/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/ui/0000775000175000017500000000000012271707664014601 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/build/0000775000175000017500000000000012271707664015700 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/build/freeipa/0000775000175000017500000000000012271707664017313 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/build/freeipa/Makefile.am0000664000175000017500000000105612271663206021342 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/ui/js/freeipa app_DATA = \ app.js \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in core := $(wildcard ../../src/freeipa/*.js) base := $(wildcard ../../src/freeipa/_base/*.js) widgets := $(wildcard ../../src/freeipa/widgets/*.js) nav := $(wildcard ../../src/freeipa/navigation/*.js) app.js: $(core) $(base) $(widgets) $(nav) ../../util/make-ui.sh freeipa-3.3.4/install/ui/build/freeipa/Makefile.in0000664000175000017500000003250612271707662021364 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = ui/build/freeipa DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/ui/js/freeipa app_DATA = \ app.js \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in core := $(wildcard ../../src/freeipa/*.js) base := $(wildcard ../../src/freeipa/_base/*.js) widgets := $(wildcard ../../src/freeipa/widgets/*.js) nav := $(wildcard ../../src/freeipa/navigation/*.js) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ui/build/freeipa/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ui/build/freeipa/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA app.js: $(core) $(base) $(widgets) $(nav) ../../util/make-ui.sh # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/ui/build/dojo/0000775000175000017500000000000012271707664016633 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/build/dojo/dojo.js0000664000175000017500000024747612271663206020141 0ustar mkosekmkosek(function(e,t){var n=function(){},r=function(e){for(var t in e)return 0;return 1},i={}.toString,s=function(e){return i.call(e)=="[object Function]"},o=function(e){return i.call(e)=="[object String]"},u=function(e){return i.call(e)=="[object Array]"},a=function(e,t){if(e)for(var n=0;nE&&(S=s(t[1])?e.replace(t[0],t[1]):t[1])}),S?Dt(S,0,n,r,i,o,u,f):(y=r[e],y?f?_t(y.pid,y.mid,y.pack,y.url):r[e]:(v=Ot(e,u),v?m=v[1]+e.substring(v[3]):c?m=h.location+"/"+p:g("config-tlmSiblingOfDojo")?m="../"+e:m=e,/(^\/)|(\:)/.test(m)||(m=i+m),m+=".js",_t(c,e,h,Mt(m))))},Pt=function(e,t){return Dt(e,t,Q,Z,p.baseUrl,Y,K)},Ht=function(e,t,n){return e.normalize?e.normalize(t,function(e){return Ft(e,n)}):Ft(t,n)},Bt=0,jt=function(e,t,n){var r,i,s,o;return r=e.match(/^(.+?)\!(.*)$/),r?(i=jt(r[1],t,n),A==O&&!i.executed&&(fn(i),i.injected===N&&!i.executed&&en(function(){Yt(i)}),i.executed?Jt(i):Tt.unshift(i)),i.executed===L&&!i.load&&Jt(i),i.load?(s=Ht(i,r[2],t),e=i.mid+"!"+(i.dynamic?++Bt+"!":"")+s):(s=r[2],e=i.mid+"!"+ ++Bt+"!waitingForPlugin"),o={plugin:i,mid:e,req:xt(t),prid:s}):o=Pt(e,t),Z[o.mid]||!n&&(Z[o.mid]=o)},Ft=p.toAbsMid=function(e,t){return Pt(e,t).mid},It=p.toUrl=function(e,t){var n=Pt(e+"/x",t),r=n.url;return nn(n.pid===0?e:r.substring(0,r.length-5))},qt={injected:N,executed:L,def:C,result:C},Rt=function(e){return Z[e]=f({mid:e},qt)},Ut=Rt("require"),zt=Rt("exports"),Wt=Rt("module"),Xt=function(e,t){p.trace("loader-run-factory",[e.mid]);var n=e.def,r;_.unshift(e);if(g("config-dojo-loader-catches"))try{r=s(n)?n.apply(null,t):n}catch(i){X(W,e.result=l("factoryThrew",[e,i]))}else r=s(n)?n.apply(null,t):n;e.result=r===undefined&&e.cjs?e.cjs.exports:r,_.shift(e)},Vt={},$t=0,Jt=function(e){var t=e.result;return e.dynamic=t.dynamic,e.normalize=t.normalize,e.load=t.load,e},Kt=function(e){var t={};a(e.loadQ,function(n){var r=Ht(e,n.prid,n.req.module),i=e.dynamic?n.mid.replace(/waitingForPlugin$/,r):e.mid+"!"+r,s=f(f({},n),{mid:i,prid:r,injected:0});Z[i]||rn(Z[i]=s),t[n.mid]=Z[i],Lt(n),delete Z[n.mid]}),e.loadQ=0;var n=function(e){for(var n,r=e.deps||[],i=0;i")]),!e.def||t?Vt:e.cjs&&e.cjs.exports;if(!e.executed){if(!e.def)return Vt;var n=e.mid,r=e.deps||[],i,s,o=[],u=0;e.executed=k;while(u0&&a.attributes.length<40),n.clearElement=function(e){return e.innerHTML="",e},n.normalize=function(e,t){var r=e.match(/[\?:]|[^:\?]*/g),i=0,s=function(e){var t=r[i++];return t==":"?0:r[i++]=="?"?!e&&n(t)?s():(s(!0),s(e)):t||0};return e=s(),e&&t(e)},n.load=function(e,t,n){e?t([e],n):n()},n})},"dojo/_base/declare":function(){define(["./kernel","../has","./lang"],function(e,t,n){function f(e,t){throw new Error("declare"+(t?" "+t:"")+": "+e)}function l(e,t){var n=[],r=[{cls:0,refs:[]}],i={},o=1,a=e.length,l=0,c,h,p,d,v,m,g,y;for(;l=0;--c)v=h[c].prototype,v.hasOwnProperty("declaredClass")||(v.declaredClass="uniqName_"+u++),g=v.declaredClass,i.hasOwnProperty(g)||(i[g]={count:0,refs:[],cls:h[c]},++o),m=i[g],d&&d!==m&&(m.refs.push(d),++d.count),d=m;++d.count,r[0].refs.push(d)}while(r.length){d=r.pop(),n.push(d.cls),--o;while(y=d.refs,y.length==1){d=y[0];if(!d||--d.count){d=0;break}n.push(d.cls),--o}if(d)for(l=0,a=y.length;l=0;--o)s=e[o],u=s._meta,s=u?u.ctor:s,s&&s.apply(this,f?f[o]:n);s=this.postscript,s&&s.apply(this,r)}}function E(e,t){return function(){var n=arguments,r=n,i=n[0],s;if(!(this instanceof n.callee))return N(n);t&&(i&&(s=i.preamble,s&&(r=s.apply(this,r)||r)),s=this.preamble,s&&s.apply(this,r)),e&&e.apply(this,n),s=this.postscript,s&&s.apply(this,n)}}function S(e){return function(){var t=arguments,n=0,r,i;if(!(this instanceof t.callee))return N(t);for(;r=e[n];++n){i=r._meta,r=i?i.ctor:r;if(r){r.apply(this,t);break}}r=this.postscript,r&&r.apply(this,t)}}function x(e,t,n){return function(){var r,i,s,o=0,u=1;n&&(o=t.length-1,u=-1);for(;r=t[o];o+=u)i=r._meta,s=(i?i.hidden:r.prototype)[e],s&&s.apply(this,arguments)}}function T(e){o.prototype=e.prototype;var t=new o;return o.prototype=null,t}function N(e){var t=e.callee,n=T(t);return t.apply(n,e),n}function C(e,t,o){typeof e!="string"&&(o=t,t=e,e=""),o=o||{};var u,p,g,N,k,L,A,O=1,M=t;s.call(t)=="[object Array]"?(L=l(t,e),g=L[0],O=L.length-g,t=L[O]):(L=[0],t?s.call(t)=="[object Function]"?(g=t._meta,L=L.concat(g?g.bases:t)):f("base class is not a callable constructor.",e):t!==null&&f("unknown base class. Did you use dojo.require to pull it in?",e));if(t)for(p=O-1;;--p){u=T(t);if(!p)break;g=L[p],(g._meta?m:r)(u,g.prototype),N=new Function,N.superclass=t,N.prototype=u,t=u.constructor=N}else u={};C.safeMixin(u,o),g=o.constructor,g!==i.constructor&&(g.nom=a,u.constructor=g);for(p=O-1;p;--p)g=L[p]._meta,g&&g.chains&&(A=r(A||{},g.chains));u["-chains-"]&&(A=r(A||{},u["-chains-"])),g=!A||!A.hasOwnProperty(a),L[0]=N=A&&A.constructor==="manual"?S(L):L.length==1?E(o.constructor,g):w(L,g),N._meta={bases:L,hidden:o,chains:A,parents:M,ctor:o.constructor},N.superclass=t&&t.prototype,N.extend=y,N.createSubclass=b,N.prototype=u,u.constructor=N,u.getInherited=h,u.isInstanceOf=v,u.inherited=d,u.__inherited=c,e&&(u.declaredClass=e,n.setObject(e,N));if(A)for(k in A)u[k]&&typeof A[k]=="string"&&k!=a&&(g=u[k]=x(k,L,A[k]==="after"),g.nom=k);return N}var r=n.mixin,i=Object.prototype,s=i.toString,o=new Function,u=0,a="constructor",d=e.config.isDebug?p:c;return e.safeMixin=C.safeMixin=g,e.declare=C,C})},"dojo/_base/kernel":function(){define(["../has","./config","require","module"],function(e,t,n,r){var i,s,o={},u={},a={config:t,global:this,dijit:o,dojox:u},f={dojo:["dojo",a],dijit:["dijit",o],dojox:["dojox",u]},l=n.map&&n.map[r.id.match(/[^\/]+/)[0]],c;for(s in l)f[s]?f[s][0]=l[s]:f[s]=[l[s],{}];for(s in f)c=f[s],c[1]._scopeName=c[0],t.noGlobals||(this[c[0]]=c[1]);a.scopeMap=f,a.baseUrl=a.config.baseUrl=n.baseUrl,a.isAsync=n.async,a.locale=t.locale;var h="$Rev: 30226 $".match(/\d+/);a.version={major:1,minor:8,patch:3,flag:"",revision:h?+h[0]:NaN,toString:function(){var e=a.version;return e.major+"."+e.minor+"."+e.patch+e.flag+" ("+e.revision+")"}},1,Function("d","d.eval = function(){return d.global.eval ? d.global.eval(arguments[0]) : eval(arguments[0]);}")(a),a.exit=function(){},1,typeof console!="undefined"||(console={});var p=["assert","count","debug","dir","dirxml","error","group","groupEnd","info","profile","profileEnd","time","timeEnd","trace","warn","log"],d;i=0;while(d=p[i++])console[d]||function(){var e=d+"";console[e]="log"in console?function(){var t=Array.apply({},arguments);t.unshift(e+":"),console.log(t.join(" "))}:function(){},console[e]._fake=!0}();e.add("dojo-debug-messages",!!t.isDebug),a.deprecated=a.experimental=function(){},e("dojo-debug-messages")&&(a.deprecated=function(e,t,n){var r="DEPRECATED: "+e;t&&(r+=" "+t),n&&(r+=" -- will be removed in version: "+n),console.warn(r)},a.experimental=function(e,t){var n="EXPERIMENTAL: "+e+" -- APIs subject to change without notice.";t&&(n+=" "+t),console.warn(n)}),1;if(t.modulePaths){a.deprecated("dojo.modulePaths","use paths configuration");var v={};for(s in t.modulePaths)v[s.replace(/\./g,"/")]=t.modulePaths[s];n({paths:v})}return 1,a.moduleUrl=function(e,t){a.deprecated("dojo.moduleUrl()","use require.toUrl","2.0");var r=null;return e&&(r=n.toUrl(e.replace(/\./g,"/")+(t?"/"+t:"")+"/*.*").replace(/\/\*\.\*/,"")+(t?"":"/")),r},a._hasResource={},a})},"dojo/_base/config":function(){define(["../has","require"],function(e,t){var n={},r=t.rawConfig,i;for(i in r)n[i]=r[i];return n})},"dojo/_base/lang":function(){define(["./kernel","../has","../sniff"],function(e,t){t.add("bug-for-in-skips-shadowed",function(){for(var e in{toString:1})return 0;return 1});var n=t("bug-for-in-skips-shadowed")?"hasOwnProperty.valueOf.isPrototypeOf.propertyIsEnumerable.toLocaleString.toString.constructor".split("."):[],r=n.length,i=function(t,n,r){var i,s=0,o=e.global;if(!r){if(!t.length)return o;i=t[s++];try{r=e.scopeMap[i]&&e.scopeMap[i][1]}catch(u){}r=r||(i in o?o[i]:n?o[i]={}:undefined)}while(r&&(i=t[s++]))r=i in r?r[i]:n?r[i]={}:undefined;return r},s=Object.prototype.toString,o=function(e,t,n){return(n||[]).concat(Array.prototype.slice.call(e,t||0))},u=/\{([^\}]+)\}/g,a={_extraNames:n,_mixin:function(e,i,s){var o,u,a,f={};for(o in i){u=i[o];if(!(o in e)||e[o]!==u&&(!(o in f)||f[o]!==u))e[o]=s?s(u):u}if(t("bug-for-in-skips-shadowed")&&i)for(a=0;a2)return a._hitchArgs.apply(e,arguments);n||(n=t,t=null);if(a.isString(n)){t=t||e.global;if(!t[n])throw['lang.hitch: scope["',n,'"] is null (scope="',t,'")'].join("");return function(){return t[n].apply(t,arguments||[])}}return t?function(){return n.apply(t,arguments||[])}:n},delegate:function(){function e(){}return function(t,n){e.prototype=t;var r=new e;return e.prototype=null,n&&a._mixin(r,n),r}}(),_toArray:t("ie")?function(){function e(e,t,n){var r=n||[];for(var i=t||0;i=0),e.add("khtml",r.indexOf("Konqueror")>=0?i:undefined),e.add("webkit",parseFloat(n.split("WebKit/")[1])||undefined),e.add("chrome",parseFloat(n.split("Chrome/")[1])||undefined),e.add("safari",r.indexOf("Safari")>=0&&!e("chrome")?parseFloat(r.split("Version/")[1]):undefined),e.add("mac",r.indexOf("Macintosh")>=0),e.add("quirks",document.compatMode=="BackCompat"),e.add("ios",/iPhone|iPod|iPad/.test(n)),e.add("android",parseFloat(n.split("Android ")[1])||undefined);if(!e("webkit")){n.indexOf("Opera")>=0&&e.add("opera",i>=9.8?parseFloat(n.split("Version/")[1])||i:i),n.indexOf("Gecko")>=0&&!e("khtml")&&!e("webkit")&&e.add("mozilla",i),e("mozilla")&&e.add("ff",parseFloat(n.split("Firefox/")[1]||n.split("Minefield/")[1])||undefined);if(document.all&&!e("opera")){var s=parseFloat(r.split("MSIE ")[1])||undefined,o=document.documentMode;o&&o!=5&&Math.floor(s)!=o&&(s=o),e.add("ie",s)}e.add("wii",typeof opera!="undefined"&&opera.wiiremote)}return e})},"dojo/_base/array":function(){define(["./kernel","../has","./lang"],function(e,t,n){function s(e){return r[e]=new Function("item","index","array",e)}function o(e){var t=!e;return function(n,i,o){var u=0,a=n&&n.length||0,f;a&&typeof n=="string"&&(n=n.split("")),typeof i=="string"&&(i=r[i]||s(i));if(o)for(;u0)return a.lastIndexOf(s,o,u);var l=s&&s.length||0,c=e?l+r:n,h;u===i?h=e?n:l+r:u<0?(h=l+u,h<0&&(h=n)):h=u>=l?l+r:u,l&&typeof s=="string"&&(s=s.split(""));for(;h!=c;h+=t)if(s[h]==o)return h;return-1}}var r={},i,a={every:o(!1),some:o(!0),indexOf:u(!0),lastIndexOf:u(!1),forEach:function(e,t,n){var i=0,o=e&&e.length||0;o&&typeof e=="string"&&(e=e.split("")),typeof t=="string"&&(t=r[t]||s(t));if(n)for(;i':"<"+p.join("><")+">",p.post=""}e.toDom=function(t,n){n=n||r.doc;var i=n[c];i||(n[c]=i=++l+"",f[i]=n.createElement("div")),t+="";var s=t.match(a),o=s?s[1].toLowerCase():"",h=f[i],p,d,v,m;if(s&&u[o]){p=u[o],h.innerHTML=p.pre+t+p.post;for(d=p.length;d;--d)h=h.firstChild}else h.innerHTML=t;if(h.childNodes.length==1)return h.removeChild(h.firstChild);m=n.createDocumentFragment();while(v=h.firstChild)m.appendChild(v);return m},e.place=function(n,r,s){r=i.byId(r),typeof n=="string"&&(n=/^\s*90)&&(t<96||t>111)&&(t<186||t>192)&&(t<219||t>222)&&t!=229;if(r||e.ctrlKey){var i=r?0:t;if(e.ctrlKey){if(t==3||t==13)return n.call(e.currentTarget,e);i>95&&i<106?i-=48:!e.shiftKey&&i>=65&&i<=90?i+=32:i=f[i]||i}var s=c(e,{type:"keypress",faux:!0,charCode:i});n.call(e.currentTarget,s),o("ie")&&d(e,s.keyCode)}}),i=t(e,"keypress",function(e){var t=e.charCode;return t=t>=32?t:0,e=c(e,{charCode:t,faux:!0}),n.call(this,e)});return{remove:function(){r.remove(),i.remove()}}}}else o("opera")?p=function(e,n){return t(e,"keypress",function(e){var t=e.which;return t==3&&(t=99),t=t<32&&!e.shiftKey?0:t,e.ctrlKey&&!e.shiftKey&&t>=65&&t<=90&&(t+=32),n.call(this,c(e,{charCode:t}))})}:p=function(e,n){return t(e,"keypress",function(e){return h(e),n.call(this,e)})};var v={_keypress:p,connect:function(e,t,n,r,i){var s=arguments,o=[],u=0;o.push(typeof s[0]=="string"?null:s[u++],s[u++]);var f=s[u+1];o.push(typeof f=="string"||typeof f=="function"?s[u++]:null,s[u++]);for(var l=s.length;u-1){var o=t.split(/\s*,\s*/),u=[],a=0,f;while(f=o[a++])u.push(r(e,f,n,i,s));return u.remove=function(){for(var e=0;e=0&&(o.width=r+s),i>=0&&(o.height=i+s)}function u(e){return e.tagName.toLowerCase()=="button"||e.tagName.toLowerCase()=="input"&&(e.getAttribute("type")||"").toLowerCase()=="button"}function a(e){return i.boxModel=="border-box"||e.tagName.toLowerCase()=="table"||u(e)}var i={};i.boxModel="content-box",e("ie")&&(i.boxModel=document.compatMode=="BackCompat"?"border-box":"content-box"),i.getPadExtents=function(t,i){t=n.byId(t);var s=i||r.getComputedStyle(t),o=r.toPixelValue,u=o(t,s.paddingLeft),a=o(t,s.paddingTop),f=o(t,s.paddingRight),l=o(t,s.paddingBottom);return{l:u,t:a,r:f,b:l,w:u+f,h:a+l}};var s="none";i.getBorderExtents=function(t,i){t=n.byId(t);var o=r.toPixelValue,u=i||r.getComputedStyle(t),a=u.borderLeftStyle!=s?o(t,u.borderLeftWidth):0,f=u.borderTopStyle!=s?o(t,u.borderTopWidth):0,l=u.borderRightStyle!=s?o(t,u.borderRightWidth):0,c=u.borderBottomStyle!=s?o(t,u.borderBottomWidth):0;return{l:a,t:f,r:l,b:c,w:a+l,h:f+c}},i.getPadBorderExtents=function(t,s){t=n.byId(t);var o=s||r.getComputedStyle(t),u=i.getPadExtents(t,o),a=i.getBorderExtents(t,o);return{l:u.l+a.l,t:u.t+a.t,r:u.r+a.r,b:u.b+a.b,w:u.w+a.w,h:u.h+a.h}},i.getMarginExtents=function(t,i){t=n.byId(t);var s=i||r.getComputedStyle(t),o=r.toPixelValue,u=o(t,s.marginLeft),a=o(t,s.marginTop),f=o(t,s.marginRight),l=o(t,s.marginBottom);return{l:u,t:a,r:f,b:l,w:u+f,h:a+l}},i.getMarginBox=function(o,u){o=n.byId(o);var a=u||r.getComputedStyle(o),f=i.getMarginExtents(o,a),l=o.offsetLeft-f.l,c=o.offsetTop-f.t,h=o.parentNode,p=r.toPixelValue,d;if(e("mozilla")){var v=parseFloat(a.left),m=parseFloat(a.top);!isNaN(v)&&!isNaN(m)?(l=v,c=m):h&&h.style&&(d=r.getComputedStyle(h),d.overflow!="visible"&&(l+=d.borderLeftStyle!=s?p(o,d.borderLeftWidth):0,c+=d.borderTopStyle!=s?p(o,d.borderTopWidth):0))}else(e("opera")||e("ie")==8&&!e("quirks"))&&h&&(d=r.getComputedStyle(h),l-=d.borderLeftStyle!=s?p(o,d.borderLeftWidth):0,c-=d.borderTopStyle!=s?p(o,d.borderTopWidth):0);return{l:l,t:c,w:o.offsetWidth+f.w,h:o.offsetHeight+f.h}},i.getContentBox=function(s,o){s=n.byId(s);var u=o||r.getComputedStyle(s),a=s.clientWidth,f,l=i.getPadExtents(s,u),c=i.getBorderExtents(s,u);return a?(f=s.clientHeight,c.w=c.h=0):(a=s.offsetWidth,f=s.offsetHeight),e("opera")&&(l.l+=c.l,l.t+=c.t),{l:l.l,t:l.t,w:a-l.w-c.w,h:f-l.h-c.h}},i.setContentSize=function(t,r,s){t=n.byId(t);var u=r.w,f=r.h;if(a(t)){var l=i.getPadBorderExtents(t,s);u>=0&&(u+=l.w),f>=0&&(f+=l.h)}o(t,NaN,NaN,u,f)};var f={l:0,t:0,w:0,h:0};return i.setMarginBox=function(s,l,c){s=n.byId(s);var h=c||r.getComputedStyle(s),p=l.w,d=l.h,v=a(s)?f:i.getPadBorderExtents(s,h),m=i.getMarginExtents(s,h);if(e("webkit")&&u(s)){var g=s.style;p>=0&&!g.width&&(g.width="4px"),d>=0&&!g.height&&(g.height="4px")}p>=0&&(p=Math.max(p-v.w-m.w,0)),d>=0&&(d=Math.max(d-v.h-m.h,0)),o(s,l.l,l.t,p,d)},i.isBodyLtr=function(n){return n=n||t.doc,(t.body(n).dir||n.documentElement.dir||"ltr").toLowerCase()=="ltr"},i.docScroll=function(r){r=r||t.doc;var s=t.doc.parentWindow||t.doc.defaultView;return"pageXOffset"in s?{x:s.pageXOffset,y:s.pageYOffset}:(s=e("quirks")?t.body(r):r.documentElement)&&{x:i.fixIeBiDiScrollLeft(s.scrollLeft||0,r),y:s.scrollTop||0}},e("ie")&&(i.getIeDocumentElementOffset=function(r){r=r||t.doc;var i=r.documentElement;if(e("ie")<8){var s=i.getBoundingClientRect(),o=s.left,u=s.top;return e("ie")<7&&(o+=i.clientLeft,u+=i.clientTop),{x:o<0?0:o,y:u<0?0:u}}return{x:0,y:0}}),i.fixIeBiDiScrollLeft=function(r,s){s=s||t.doc;var o=e("ie");if(o&&!i.isBodyLtr(s)){var u=e("quirks"),a=u?t.body(s):s.documentElement,f=t.global;return o==6&&!u&&f.frameElement&&a.scrollHeight>a.clientHeight&&(r+=a.clientLeft),o<8||u?r+a.clientWidth-a.scrollWidth:-r}return r},i.position=function(r,s){r=n.byId(r);var o=t.body(r.ownerDocument),u=r.getBoundingClientRect();u={x:u.left,y:u.top,w:u.right-u.left,h:u.bottom-u.top};if(e("ie")<9){var a=i.getIeDocumentElementOffset(r.ownerDocument);u.x-=a.x+(e("quirks")?o.clientLeft+o.offsetLeft:0),u.y-=a.y+(e("quirks")?o.clientTop+o.offsetTop:0)}if(s){var f=i.docScroll(r.ownerDocument);u.x+=f.x,u.y+=f.y}return u},i.getMarginSize=function(t,s){t=n.byId(t);var o=i.getMarginExtents(t,s||r.getComputedStyle(t)),u=t.getBoundingClientRect();return{w:u.right-u.left+o.w,h:u.bottom-u.top+o.h}},i.normalizeEvent=function(t){"layerX"in t||(t.layerX=t.offsetX,t.layerY=t.offsetY);if(!e("dom-addeventlistener")){var n=t.target,r=n&&n.ownerDocument||document,s=e("quirks")?r.body:r.documentElement,o=i.getIeDocumentElementOffset(r);t.pageX=t.clientX+i.fixIeBiDiScrollLeft(s.scrollLeft||0,r)-o.x,t.pageY=t.clientY+(s.scrollTop||0)-o.y}},i})},"dojo/mouse":function(){define("dojo/mouse",["./_base/kernel","./on","./has","./dom","./_base/window"],function(e,t,n,r,i){function o(e,n){var i=function(i,s){return t(i,e,function(e){if(n)return n(e,s);if(!r.isDescendant(e.relatedTarget,i))return s.call(this,e)})};return i.bubble=function(t){return o(e,function(e,n){var r=t(e.target),i=e.relatedTarget;if(r&&r!=(i&&i.nodeType==1&&t(i)))return n.call(r,e)})},i}n.add("dom-quirks",i.doc&&i.doc.compatMode=="BackCompat"),n.add("events-mouseenter",i.doc&&"onmouseenter"in i.doc.createElement("div")),n.add("events-mousewheel",i.doc&&"onmousewheel"in i.doc);var s;n("dom-quirks")&&n("ie")||!n("dom-addeventlistener")?s={LEFT:1,MIDDLE:4,RIGHT:2,isButton:function(e,t){return e.button&t},isLeft:function(e){return e.button&1},isMiddle:function(e){return e.button&4},isRight:function(e){return e.button&2}}:s={LEFT:0,MIDDLE:1,RIGHT:2,isButton:function(e,t){return e.button==t},isLeft:function(e){return e.button==0},isMiddle:function(e){return e.button==1},isRight:function(e){return e.button==2}},e.mouseButtons=s;var u;return n("events-mousewheel")?u="mousewheel":u=function(e,n){return t(e,"DOMMouseScroll",function(e){e.wheelDelta=-e.detail,n.call(this,e)})},{_eventHandler:o,enter:o("mouseover"),leave:o("mouseout"),wheel:u,isLeft:s.isLeft,isMiddle:s.isMiddle,isRight:s.isRight}})},"dojo/_base/sniff":function(){define(["./kernel","./lang","../sniff"],function(e,t,n){return e._name="browser",t.mixin(e,{isBrowser:!0,isFF:n("ff"),isIE:n("ie"),isKhtml:n("khtml"),isWebKit:n("webkit"),isMozilla:n("mozilla"),isMoz:n("mozilla"),isOpera:n("opera"),isSafari:n("safari"),isChrome:n("chrome"),isMac:n("mac"),isIos:n("ios"),isAndroid:n("android"),isWii:n("wii"),isQuirks:n("quirks"),isAir:n("air")}),e.locale=e.locale||(n("ie")?navigator.userLanguage:navigator.language).toLowerCase(),n})},"dojo/keys":function(){define("dojo/keys",["./_base/kernel","./sniff"],function(e,t){return e.keys={BACKSPACE:8,TAB:9,CLEAR:12,ENTER:13,SHIFT:16,CTRL:17,ALT:18,META:t("webkit")?91:224,PAUSE:19,CAPS_LOCK:20,ESCAPE:27,SPACE:32,PAGE_UP:33,PAGE_DOWN:34,END:35,HOME:36,LEFT_ARROW:37,UP_ARROW:38,RIGHT_ARROW:39,DOWN_ARROW:40,INSERT:45,DELETE:46,HELP:47,LEFT_WINDOW:91,RIGHT_WINDOW:92,SELECT:93,NUMPAD_0:96,NUMPAD_1:97,NUMPAD_2:98,NUMPAD_3:99,NUMPAD_4:100,NUMPAD_5:101,NUMPAD_6:102,NUMPAD_7:103,NUMPAD_8:104,NUMPAD_9:105,NUMPAD_MULTIPLY:106,NUMPAD_PLUS:107,NUMPAD_ENTER:108,NUMPAD_MINUS:109,NUMPAD_PERIOD:110,NUMPAD_DIVIDE:111,F1:112,F2:113,F3:114,F4:115,F5:116,F6:117,F7:118,F8:119,F9:120,F10:121,F11:122,F12:123,F13:124,F14:125,F15:126,NUM_LOCK:144,SCROLL_LOCK:145,UP_DPAD:175,DOWN_DPAD:176,LEFT_DPAD:177,RIGHT_DPAD:178,copyKey:t("mac")&&!t("air")?t("safari")?91:224:17}})},"dojo/dom-class":function(){define("dojo/dom-class",["./_base/lang","./_base/array","./dom"],function(e,t,n){function u(e){if(typeof e=="string"||e instanceof String){if(e&&!s.test(e))return o[0]=e,o;var n=e.split(s);return n.length&&!n[0]&&n.shift(),n.length&&!n[n.length-1]&&n.pop(),n}return e?t.filter(e,function(e){return e}):[]}var r="className",i,s=/\s+/,o=[""],a={};return i={contains:function(t,i){return(" "+n.byId(t)[r]+" ").indexOf(" "+i+" ")>=0},add:function(t,i){t=n.byId(t),i=u(i);var s=t[r],o;s=s?" "+s+" ":" ",o=s.length;for(var a=0,f=i.length,l;a-1&&s.splice(e,1)},o}})})},"dojo/when":function(){define("dojo/when",["./Deferred","./promise/Promise"],function(e,t){"use strict";return function(r,i,s,o){var u=r&&typeof r.then=="function",a=u&&r instanceof t;if(!u)return i?i(r):(new e).resolve(r);if(!a){var f=new e(r.cancel);r.then(f.resolve,f.reject,f.progress),r=f.promise}return i||s||o?r.then(i,s,o):r}})},"dojo/Deferred":function(){define("dojo/Deferred",["./has","./_base/lang","./errors/CancelError","./promise/Promise","./promise/instrumentation"],function(e,t,n,r,i){"use strict";var s=0,o=1,u=2,a="This deferred has already been fulfilled.",f=Object.freeze||function(){},l=function(e,t,n,r,i){t===u&&d.instrumentRejected&&e.length===0&&d.instrumentRejected(n,!1,r,i);for(var s=0;s");r.instrumentRejected=f,a=parseInt(o[0],10)||a}}}})},"dojo/promise/tracer":function(){define(["../_base/lang","./Promise","../Evented"],function(e,t,n){"use strict";function s(e){setTimeout(function(){i.apply(r,e)},0)}var r=new n,i=r.emit;return r.emit=null,t.prototype.trace=function(){var t=e._toArray(arguments);return this.then(function(e){s(["resolved",e].concat(t))},function(e){s(["rejected",e].concat(t))},function(e){s(["progress",e].concat(t))}),this},t.prototype.traceRejected=function(){var t=e._toArray(arguments);return this.otherwise(function(e){s(["rejected",e].concat(t))}),this},r})},"dojo/io-query":function(){define("dojo/io-query",["./_base/lang"],function(e){var t={};return{objectToQuery:function(r){var i=encodeURIComponent,s=[];for(var o in r){var u=r[o];if(u!=t[o]){var a=i(o)+"=";if(e.isArray(u))for(var f=0,l=u.length;f0?r:null},_indexRoutes:function(){var e,t,n,r,i=this._routes;r=this._routeIndex={};for(e=0,t=i.length;e=0?e.substring(n+1):""}function h(){return c(location.href,"#")}function p(){r.publish("/dojo/hashchange",[h()])}function d(){if(h()===u)return;u=h(),p()}function v(e){if(a){if(a.isTransitioning()){setTimeout(i.hitch(null,v,e),l);return}var t=a.iframe.location.href,n=t.indexOf("?");a.iframe.location.replace(t.substring(0,n)+"?"+e);return}location.replace("#"+e),!f&&d()}function m(){function y(){u=h(),a=m?u:c(g.href,"?"),f=!1,d=null}var r=document.createElement("iframe"),s="dojo-hash-iframe",o=n.dojoBlankHtmlUrl||t.toUrl("./resources/blank.html");n.useXDomain&&!n.dojoBlankHtmlUrl&&console.warn("dojo.hash: When using cross-domain Dojo builds, please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl to the path on your domain to blank.html"),r.id=s,r.src=o+"?"+h(),r.style.display="none",document.body.appendChild(r),this.iframe=e.global[s];var a,f,d,v,m,g=this.iframe.location;this.isTransitioning=function(){return f},this.pollLocation=function(){if(!m)try{var e=c(g.href,"?");document.title!=v&&(v=this.iframe.document.title=document.title)}catch(t){m=!0,console.error("dojo.hash: Error adding history entry. Server unreachable.")}var n=h();if(f&&u===n){if(!m&&e!==d){setTimeout(i.hitch(this,this.pollLocation),0);return}y(),p()}else if(u!==n||!m&&a!==e){if(u!==n){u=n,f=!0,d=n,r.src=o+"?"+d,m=!1,setTimeout(i.hitch(this,this.pollLocation),0);return}m||(location.href="#"+g.search.substring(1),y(),p())}setTimeout(i.hitch(this,this.pollLocation),l)},y(),setTimeout(i.hitch(this,this.pollLocation),l)}e.hash=function(e,t){return arguments.length?(e.charAt(0)=="#"&&(e=e.substring(1)),t?v(e):location.href="#"+e,e):h()};var u,a,f,l=n.hashPollFrequency||100;return s(function(){"onhashchange"in e.global&&(!o("ie")||o("ie")>=8&&document.compatMode!="BackCompat")?f=r.connect(e.global,"onhashchange",p):document.addEventListener?(u=h(),setInterval(d,l)):document.attachEvent&&(a=new m)}),e.hash})},"dojo/ready":function(){define("dojo/ready",["./_base/kernel","./has","require","./domReady","./_base/lang"],function(e,t,n,r,i){var s=0,o,u=[],a=0,f=function(){s=1,e._postLoad=e.config.afterOnLoad=!0,u.length&&o(l)},l=function(){if(s&&!a&&u.length){a=1;var e=u.shift();try{e()}finally{a=0}a=0,u.length&&o(l)}};n.on("idle",l),o=function(){n.idle()&&l()};var c=e.ready=e.addOnLoad=function(t,n,r){var s=i._toArray(arguments);typeof t!="number"?(r=n,n=t,t=1e3):s.shift(),r=r?i.hitch.apply(e,s):function(){n()},r.priority=t;for(var a=0;a=u[a].priority;a++);u.splice(a,0,r),o()};1;var h=e.config.addOnLoad;return h&&c[i.isArray(h)?"apply":"call"](e,h),e.config.parseOnLoad&&!e.isAsync&&c(99,function(){e.parser||(e.deprecated("Add explicit require(['dojo/parser']);","","2.0"),n(["dojo/parser"]))}),r(f),c})},"dojo/store/Observable":function(){define(["../_base/kernel","../_base/lang","../_base/Deferred","../_base/array"],function(e,t,n,r){var i=function(e){function f(t,r){var i=e[t];i&&(e[t]=function(e){if(a)return i.apply(this,arguments);a=!0;try{var t=i.apply(this,arguments);return n.when(t,function(t){r(typeof t=="object"&&t||e)}),t}finally{a=!1}})}var i,s=[],o=0;e=t.delegate(e),e.notify=function(e,t){o++;var n=s.slice();for(var r=0,i=n.length;r-1?g:n.length;n.splice(w,0,t),y=r.indexOf(h(n),t),n.splice(w,1),f.start&&y==0||!a&&y==n.length?y=-1:n.splice(y,0,t)}}else t&&(s!==i?y=g:f.start||(y=e.defaultIndex||0,n.splice(y,0,t)));if((g>-1||y>-1)&&(u||!h||g!=y)){var E=d.slice();for(l=0;v=E[l];l++)v(t||m,g,y)}})});var a={};return a.remove=a.cancel=function(){var e=r.indexOf(d,t);e>-1&&(d.splice(e,1),d.length||s.splice(r.indexOf(s,v),1))},a}}return l};var a;return f("put",function(t){e.notify(t,e.getIdentity(t))}),f("add",function(t){e.notify(t)}),f("remove",function(t){e.notify(undefined,t)}),e};return t.setObject("dojo.store.Observable",i),i})},"dojo/_base/Deferred":function(){define(["./kernel","../Deferred","../promise/Promise","../errors/CancelError","../has","./lang","../when"],function(e,t,n,r,i,s,o){var u=function(){},a=Object.freeze||function(){},f=e.Deferred=function(e){function v(e){if(l)throw new Error("This deferred has already been resolved");o=e,l=!0,m()}function m(){var e;while(!e&&p){var n=p;p=p.next;if(e=n.progress==u)l=!1;var r=c?n.error:n.resolved;i("config-useDeferredInstrumentation")&&c&&t.instrumentRejected&&t.instrumentRejected(o,!!r);if(r)try{var a=r(o);if(a&&typeof a.then=="function"){a.then(s.hitch(n.deferred,"resolve"),s.hitch(n.deferred,"reject"),s.hitch(n.deferred,"progress"));continue}var f=e&&a===undefined;e&&!f&&(c=a instanceof Error),n.deferred[f&&c?"reject":"resolve"](f?o:a)}catch(h){n.deferred.reject(h)}else c?n.deferred.reject(o):n.deferred.resolve(o)}}var o,l,c,h,p,d=this.promise=new n;this.resolve=this.callback=function(e){this.fired=0,this.results=[e,null],v(e)},this.reject=this.errback=function(e){c=!0,this.fired=1,i("config-useDeferredInstrumentation")&&t.instrumentRejected&&t.instrumentRejected(e,!!p),v(e),this.results=[null,e]},this.progress=function(e){var t=p;while(t){var n=t.progress;n&&n(e),t=t.next}},this.addCallbacks=function(e,t){return this.then(e,t,u),this},d.then=this.then=function(e,t,n){var r=n==u?this:new f(d.cancel),i={resolved:e,error:t,progress:n,deferred:r};return p?h=h.next=i:p=h=i,l&&m(),r.promise};var g=this;d.cancel=this.cancel=function(){if(!l){var t=e&&e(g);l||(t instanceof Error||(t=new r(t)),t.log=!1,g.reject(t))}},a(d)};return s.extend(f,{addCallback:function(t){return this.addCallbacks(s.hitch.apply(e,arguments))},addErrback:function(t){return this.addCallbacks(null,s.hitch.apply(e,arguments))},addBoth:function(t){var n=s.hitch.apply(e,arguments);return this.addCallbacks(n,n)},fired:-1}),f.when=e.when=o,f})},"dojo/store/Memory":function(){define(["../_base/declare","./util/QueryResults","./util/SimpleQueryEngine"],function(e,t,n){var r=null;return e("dojo.store.Memory",r,{constructor:function(e){for(var t in e)this[t]=e[t];this.setData(this.data||[])},data:null,idProperty:"id",index:null,queryEngine:n,get:function(e){return this.data[this.index[e]]},getIdentity:function(e){return e[this.idProperty]},put:function(e,t){var n=this.data,r=this.index,i=this.idProperty,s=e[i]=t&&"id"in t?t.id:i in e?e[i]:Math.random();if(s in r){if(t&&t.overwrite===!1)throw new Error("Object already exists");n[r[s]]=e}else r[s]=n.push(e)-1;return s},add:function(e,t){return(t=t||{}).overwrite=!1,this.put(e,t)},remove:function(e){var t=this.index,n=this.data;if(e in t)return n.splice(t[e],1),this.setData(n),!0},query:function(e,n){return t(this.queryEngine(e,n)(this.data))},setData:function(e){e.items?(this.idProperty=e.identifier,e=this.data=e.items):this.data=e,this.index={};for(var t=0,n=e.length;to)?-1:1}return 0});if(n&&(n.start||n.count)){var o=i.length;i=i.slice(n.start||0,(n.start||0)+(n.count||Infinity)),i.total=o}return i}switch(typeof t){default:throw new Error("Can not query with a "+typeof t);case"object":case"undefined":var r=t;t=function(e){for(var t in r){var n=r[t];if(n&&n.test){if(!n.test(e[t],e))return!1}else if(n!=e[t])return!1}return!0};break;case"string":if(!this[t])throw new Error("No filter function "+t+" was found in store");t=this[t];case"function":}return i.matches=t,i}})},"dojo/query":function(){define("dojo/query",["./_base/kernel","./has","./dom","./on","./_base/array","./_base/lang","./selector/_loader","./selector/_loader!default"],function(e,t,n,r,i,s,o,u){"use strict";function E(e,t){var r=function(r,i){if(typeof i=="string"){i=n.byId(i);if(!i)return new t([])}var s=typeof r=="string"?e(r,i):r?r.orphan?r:[r]:[];return s.orphan?s:new t(s)};r.matches=e.match||function(e,t,n){return r.filter([e],t,n).length>0},r.filter=e.filter||function(e,t,n){return r(t,n).filter(function(t){return i.indexOf(e,t)>-1})};if(typeof e!="function"){var s=e.search;e=function(e,t){return s(t||document,e)}}return r}t.add("array-extensible",function(){return s.delegate([],{length:1}).length==1&&!t("bug-for-in-skips-shadowed")});var a=Array.prototype,f=a.slice,l=a.concat,c=i.forEach,h=function(e,t,n){var r=new(n||this._NodeListCtor||b)(e);return t?r._stash(t):r},p=function(t,n,r){return n=[0].concat(f.call(n,0)),r=r||e.global,function(e){return n[0]=e,t.apply(r,n)}},d=function(e,t){return function(){return this.forEach(p(e,arguments,t)),this}},v=function(e,t){return function(){return this.map(p(e,arguments,t))}},m=function(e,t){return function(){return this.filter(p(e,arguments,t))}},g=function(t,n,r){return function(){var i=arguments,s=p(t,i,r);return n.call(r||e.global,i)?this.map(s):(this.forEach(s),this)}},y=function(e){var n=this instanceof b&&t("array-extensible");typeof e=="number"&&(e=Array(e));var r=e&&"length"in e?e:arguments;if(n||!r.sort){var i=n?this:[],o=i.length=r.length;for(var u=0;u-1)return f(e,n);var r=n?n.ownerDocument||n:t.doc||document,s=(i?/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/:/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/).exec(e);n=n||r;if(s){if(s[2]){var l=t.byId?t.byId(s[2]):r.getElementById(s[2]);if(!l||s[1]&&s[1]!=l.tagName.toLowerCase())return[];if(n!=r){var c=l;while(c!=n){c=c.parentNode;if(!c)return[]}}return s[3]?o(s[3],l):[l]}if(s[3]&&n.getElementsByClassName)return n.getElementsByClassName(s[4]);var l;if(s[5]){l=n.getElementsByTagName(s[5]);if(!s[4]&&!s[6])return l;e=(s[4]||"")+s[6]}}if(i)return n.nodeType===1&&n.nodeName.toLowerCase()!=="object"?u(n,e,n.querySelectorAll):n.querySelectorAll(e);l||(l=n.getElementsByTagName("*"));var h=[];for(var p=0,d=l.length;p-1&&(" "+n.className+" ").indexOf(t)>-1}},"#":function(e){return function(t){return t.id==e}}},r={"^=":function(e,t){return e.indexOf(t)==0},"*=":function(e,t){return e.indexOf(t)>-1},"$=":function(e,t){return e.substring(e.length-t.length,e.length)==t},"~=":function(e,t){return(" "+e+" ").indexOf(" "+t+" ")>-1},"|=":function(e,t){return(e+"-").indexOf(t+"-")==0},"=":function(e,t){return e==t},"":function(e,t){return!0}},u={};return function(e,n,r){var f=u[n];if(!f){if(n.replace(/(?:\s*([> ])\s*)|(#|\.)?((?:\\.|[\w-])+)|\[\s*([\w-]+)\s*(.?=)?\s*("(?:\\.|[^"])+"|'(?:\\.|[^'])+'|(?:\\.|[^\]])*)\s*\]/g,function(e,n,r,u,l,c,h){return u?f=a(f,t[r||""](u.replace(/\\/g,""))):n?f=(n==" "?s:o)(f):l&&(f=a(f,i(l,h,c))),""}))throw new Error("Syntax error in query");if(!f)return!0;u[n]=f}return f(e,r)}}();if(!e("dom-qsa"))var f=function(e,t){var n=e.match(s),r=[];for(var i=0;i=0;f--){var l=i?this._cloneNode(t[f]):t[f];if(t._runParse&&e.parser&&e.parser.parse){u||(u=o.ownerDocument.createElement("div")),u.appendChild(l),e.parser.parse(u),l=u.firstChild;while(u.firstChild)u.removeChild(u.firstChild)}f==a-1?s.place(l,o,r):o.parentNode.insertBefore(l,o),o=l}},position:d(o.position),attr:h(v(u),f),style:h(v(a),f),addClass:p(i.add),removeClass:p(i.remove),toggleClass:p(i.toggle),replaceClass:p(i.replace),empty:p(s.empty),removeAttr:p(u.remove),marginBox:d(o.getMarginBox),place:function(e,n){var r=t(e)[0];return this.forEach(function(e){s.place(e,r,n)})},orphan:function(e){return(e?t._filterResult(this,e):this).forEach(l)},adopt:function(e,n){return t(e).place(this[0],n)._stash(this)},query:function(e){if(!e)return this;var n=new c;return this.map(function(r){t(e,r).forEach(function(e){e!==undefined&&n.push(e)})}),n._stash(this)},filter:function(e){var r=arguments,i=this,s=0;if(typeof e=="string"){i=t._filterResult(this,r[0]);if(r.length==1)return i._stash(this);s=1}return this._wrap(n.filter(i,r[s],r[s+1]),this)},addContent:function(e,t){e=this._normalize(e,this[0]);for(var n=0,r;r=this[n];n++)this._place(e,r,t,n>0);return this}}),c})},"dojo/promise/all":function(){define(["../_base/array","../Deferred","../when"],function(e,t,n){"use strict";var r=e.some;return function(i){var s,o;i instanceof Array?o=i:i&&typeof i=="object"&&(s=i);var u,a=[];if(s){o=[];for(var f in s)Object.hasOwnProperty.call(s,f)&&(a.push(f),o.push(s[f]));u={}}else o&&(u=[]);if(!o||!o.length)return(new t).resolve(u);var l=new t;l.promise.always(function(){u=a=null});var c=o.length;return r(o,function(e,t){return s||a.push(t),n(e,function(e){l.isFulfilled()||(u[a[t]]=e,--c===0&&l.resolve(u))},l.reject),l.isFulfilled()}),l.promise}})}}}),function(){var e=this.require;e({cache:{}}),!e.async&&e(["dojo"]),e.boot&&e.apply(null,e.boot)}()freeipa-3.3.4/install/ui/build/dojo/Makefile.am0000664000175000017500000000044212271663206020660 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/ui/js/dojo app_DATA = \ dojo.js \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/ui/build/dojo/Makefile.in0000664000175000017500000003206212271707662020701 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = ui/build/dojo DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/ui/js/dojo app_DATA = \ dojo.js \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ui/build/dojo/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ui/build/dojo/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/ui/build/Makefile.am0000664000175000017500000000040012271663206017717 0ustar mkosekmkosekAUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = \ dojo \ freeipa \ $(NULL) EXTRA_DIST = \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in $(NULL) freeipa-3.3.4/install/ui/build/Makefile.in0000664000175000017500000004216512271707662017753 0ustar mkosekmkosek# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = ui/build DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = \ dojo \ freeipa \ $(NULL) EXTRA_DIST = \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ui/build/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ui/build/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done check-am: all-am check: check-recursive all-am: Makefile installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ distclean distclean-generic distclean-tags distdir dvi dvi-am \ html html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am $(NULL) # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/ui/jquery-ui.css0000664000175000017500000010120112202434255017223 0ustar mkosekmkosek/*! * jQuery UI CSS Framework 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Theming/API */ /* Layout helpers ----------------------------------*/ .ui-helper-hidden { display: none; } .ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } .ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } .ui-helper-clearfix:after { clear: both; } .ui-helper-clearfix { zoom: 1; } .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } /* Interaction Cues ----------------------------------*/ .ui-state-disabled { cursor: default !important; } /* Icons ----------------------------------*/ /* states and images */ .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } /* Misc visuals ----------------------------------*/ /* Overlays */ .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } /*! * jQuery UI CSS Framework 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Theming/API * * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=%27Liberation%20Sans%27,%20Arial,%20Sans,%20sans-serif&fwDefault=normal&fsDefault=1em&cornerRadius=0.3em&bgColorHeader=225314&bgTextureHeader=01_flat.png&bgImgOpacityHeader=8&borderColorHeader=a3a3a3&fcHeader=eeeeee&iconColorHeader=bbbbbb&bgColorContent=f9f9f9&bgTextureContent=04_highlight_hard.png&bgImgOpacityContent=100&borderColorContent=cccccc&fcContent=222222&iconColorContent=222222&bgColorDefault=5e5e5e&bgTextureDefault=02_glass.png&bgImgOpacityDefault=40&borderColorDefault=777777&fcDefault=e3e3e3&iconColorDefault=ededed&bgColorHover=1c1c1c&bgTextureHover=02_glass.png&bgImgOpacityHover=55&borderColorHover=000000&fcHover=ffffff&iconColorHover=ffffff&bgColorActive=ffffff&bgTextureActive=01_flat.png&bgImgOpacityActive=65&borderColorActive=cccccc&fcActive=222222&iconColorActive=222222&bgColorHighlight=ffeb80&bgTextureHighlight=06_inset_hard.png&bgImgOpacityHighlight=55&borderColorHighlight=ffde2e&fcHighlight=363636&iconColorHighlight=4ca300&bgColorError=cd0a0a&bgTextureError=06_inset_hard.png&bgImgOpacityError=45&borderColorError=9e0505&fcError=ffffff&iconColorError=ffcf29&bgColorOverlay=aaaaaa&bgTextureOverlay=04_highlight_hard.png&bgImgOpacityOverlay=40&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=03_highlight_soft.png&bgImgOpacityShadow=50&opacityShadow=20&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px */ /* Component containers ----------------------------------*/ .ui-widget { font-family: 'Liberation Sans', Arial, Sans, sans-serif; font-size: 1em; } .ui-widget .ui-widget { font-size: 1em; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: 'Liberation Sans', Arial, Sans, sans-serif; font-size: 1em; } .ui-widget-content { border: 1px solid #cccccc; background: #f9f9f9 url(images/ui-bg_highlight-hard_100_f9f9f9_1x100.png) 50% top repeat-x; color: #222222; } .ui-widget-content a { color: #222222; } .ui-widget-header { border: 1px solid #a3a3a3; background: #225314 url(images/ui-bg_flat_8_225314_40x100.png) 50% 50% repeat-x; color: #eeeeee; font-weight: bold; } .ui-widget-header a { color: #eeeeee; } /* Interaction states ----------------------------------*/ .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #777777; background: #5e5e5e url(images/ui-bg_glass_40_5e5e5e_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #e3e3e3; } .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #e3e3e3; text-decoration: none; } .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #000000; background: #1c1c1c url(images/ui-bg_glass_55_1c1c1c_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; } .ui-state-hover a, .ui-state-hover a:hover { color: #ffffff; text-decoration: none; } .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #cccccc; background: #ffffff url(images/ui-bg_flat_65_ffffff_40x100.png) 50% 50% repeat-x; font-weight: normal; color: #222222; } .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #222222; text-decoration: none; } .ui-widget :active { outline: none; } /* Interaction Cues ----------------------------------*/ .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #ffde2e; background: #ffeb80 url(images/ui-bg_inset-hard_55_ffeb80_1x100.png) 50% bottom repeat-x; color: #363636; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #9e0505; background: #cd0a0a url(images/ui-bg_inset-hard_45_cd0a0a_1x100.png) 50% bottom repeat-x; color: #ffffff; } .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } /* Icons ----------------------------------*/ /* states and images */ .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } .ui-widget-header .ui-icon {background-image: url(images/ui-icons_bbbbbb_256x240.png); } .ui-state-default .ui-icon { background-image: url(images/ui-icons_ededed_256x240.png); } .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } .ui-state-active .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_4ca300_256x240.png); } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffcf29_256x240.png); } /* positioning */ .ui-icon-carat-1-n { background-position: 0 0; } .ui-icon-carat-1-ne { background-position: -16px 0; } .ui-icon-carat-1-e { background-position: -32px 0; } .ui-icon-carat-1-se { background-position: -48px 0; } .ui-icon-carat-1-s { background-position: -64px 0; } .ui-icon-carat-1-sw { background-position: -80px 0; } .ui-icon-carat-1-w { background-position: -96px 0; } .ui-icon-carat-1-nw { background-position: -112px 0; } .ui-icon-carat-2-n-s { background-position: -128px 0; } .ui-icon-carat-2-e-w { background-position: -144px 0; } .ui-icon-triangle-1-n { background-position: 0 -16px; } .ui-icon-triangle-1-ne { background-position: -16px -16px; } .ui-icon-triangle-1-e { background-position: -32px -16px; } .ui-icon-triangle-1-se { background-position: -48px -16px; } .ui-icon-triangle-1-s { background-position: -64px -16px; } .ui-icon-triangle-1-sw { background-position: -80px -16px; } .ui-icon-triangle-1-w { background-position: -96px -16px; } .ui-icon-triangle-1-nw { background-position: -112px -16px; } .ui-icon-triangle-2-n-s { background-position: -128px -16px; } .ui-icon-triangle-2-e-w { background-position: -144px -16px; } .ui-icon-arrow-1-n { background-position: 0 -32px; } .ui-icon-arrow-1-ne { background-position: -16px -32px; } .ui-icon-arrow-1-e { background-position: -32px -32px; } .ui-icon-arrow-1-se { background-position: -48px -32px; } .ui-icon-arrow-1-s { background-position: -64px -32px; } .ui-icon-arrow-1-sw { background-position: -80px -32px; } .ui-icon-arrow-1-w { background-position: -96px -32px; } .ui-icon-arrow-1-nw { background-position: -112px -32px; } .ui-icon-arrow-2-n-s { background-position: -128px -32px; } .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } .ui-icon-arrow-2-e-w { background-position: -160px -32px; } .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } .ui-icon-arrowstop-1-n { background-position: -192px -32px; } .ui-icon-arrowstop-1-e { background-position: -208px -32px; } .ui-icon-arrowstop-1-s { background-position: -224px -32px; } .ui-icon-arrowstop-1-w { background-position: -240px -32px; } .ui-icon-arrowthick-1-n { background-position: 0 -48px; } .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } .ui-icon-arrowthick-1-e { background-position: -32px -48px; } .ui-icon-arrowthick-1-se { background-position: -48px -48px; } .ui-icon-arrowthick-1-s { background-position: -64px -48px; } .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } .ui-icon-arrowthick-1-w { background-position: -96px -48px; } .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } .ui-icon-arrow-4 { background-position: 0 -80px; } .ui-icon-arrow-4-diag { background-position: -16px -80px; } .ui-icon-extlink { background-position: -32px -80px; } .ui-icon-newwin { background-position: -48px -80px; } .ui-icon-refresh { background-position: -64px -80px; } .ui-icon-shuffle { background-position: -80px -80px; } .ui-icon-transfer-e-w { background-position: -96px -80px; } .ui-icon-transferthick-e-w { background-position: -112px -80px; } .ui-icon-folder-collapsed { background-position: 0 -96px; } .ui-icon-folder-open { background-position: -16px -96px; } .ui-icon-document { background-position: -32px -96px; } .ui-icon-document-b { background-position: -48px -96px; } .ui-icon-note { background-position: -64px -96px; } .ui-icon-mail-closed { background-position: -80px -96px; } .ui-icon-mail-open { background-position: -96px -96px; } .ui-icon-suitcase { background-position: -112px -96px; } .ui-icon-comment { background-position: -128px -96px; } .ui-icon-person { background-position: -144px -96px; } .ui-icon-print { background-position: -160px -96px; } .ui-icon-trash { background-position: -176px -96px; } .ui-icon-locked { background-position: -192px -96px; } .ui-icon-unlocked { background-position: -208px -96px; } .ui-icon-bookmark { background-position: -224px -96px; } .ui-icon-tag { background-position: -240px -96px; } .ui-icon-home { background-position: 0 -112px; } .ui-icon-flag { background-position: -16px -112px; } .ui-icon-calendar { background-position: -32px -112px; } .ui-icon-cart { background-position: -48px -112px; } .ui-icon-pencil { background-position: -64px -112px; } .ui-icon-clock { background-position: -80px -112px; } .ui-icon-disk { background-position: -96px -112px; } .ui-icon-calculator { background-position: -112px -112px; } .ui-icon-zoomin { background-position: -128px -112px; } .ui-icon-zoomout { background-position: -144px -112px; } .ui-icon-search { background-position: -160px -112px; } .ui-icon-wrench { background-position: -176px -112px; } .ui-icon-gear { background-position: -192px -112px; } .ui-icon-heart { background-position: -208px -112px; } .ui-icon-star { background-position: -224px -112px; } .ui-icon-link { background-position: -240px -112px; } .ui-icon-cancel { background-position: 0 -128px; } .ui-icon-plus { background-position: -16px -128px; } .ui-icon-plusthick { background-position: -32px -128px; } .ui-icon-minus { background-position: -48px -128px; } .ui-icon-minusthick { background-position: -64px -128px; } .ui-icon-close { background-position: -80px -128px; } .ui-icon-closethick { background-position: -96px -128px; } .ui-icon-key { background-position: -112px -128px; } .ui-icon-lightbulb { background-position: -128px -128px; } .ui-icon-scissors { background-position: -144px -128px; } .ui-icon-clipboard { background-position: -160px -128px; } .ui-icon-copy { background-position: -176px -128px; } .ui-icon-contact { background-position: -192px -128px; } .ui-icon-image { background-position: -208px -128px; } .ui-icon-video { background-position: -224px -128px; } .ui-icon-script { background-position: -240px -128px; } .ui-icon-alert { background-position: 0 -144px; } .ui-icon-info { background-position: -16px -144px; } .ui-icon-notice { background-position: -32px -144px; } .ui-icon-help { background-position: -48px -144px; } .ui-icon-check { background-position: -64px -144px; } .ui-icon-bullet { background-position: -80px -144px; } .ui-icon-radio-off { background-position: -96px -144px; } .ui-icon-radio-on { background-position: -112px -144px; } .ui-icon-pin-w { background-position: -128px -144px; } .ui-icon-pin-s { background-position: -144px -144px; } .ui-icon-play { background-position: 0 -160px; } .ui-icon-pause { background-position: -16px -160px; } .ui-icon-seek-next { background-position: -32px -160px; } .ui-icon-seek-prev { background-position: -48px -160px; } .ui-icon-seek-end { background-position: -64px -160px; } .ui-icon-seek-start { background-position: -80px -160px; } /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ .ui-icon-seek-first { background-position: -80px -160px; } .ui-icon-stop { background-position: -96px -160px; } .ui-icon-eject { background-position: -112px -160px; } .ui-icon-volume-off { background-position: -128px -160px; } .ui-icon-volume-on { background-position: -144px -160px; } .ui-icon-power { background-position: 0 -176px; } .ui-icon-signal-diag { background-position: -16px -176px; } .ui-icon-signal { background-position: -32px -176px; } .ui-icon-battery-0 { background-position: -48px -176px; } .ui-icon-battery-1 { background-position: -64px -176px; } .ui-icon-battery-2 { background-position: -80px -176px; } .ui-icon-battery-3 { background-position: -96px -176px; } .ui-icon-circle-plus { background-position: 0 -192px; } .ui-icon-circle-minus { background-position: -16px -192px; } .ui-icon-circle-close { background-position: -32px -192px; } .ui-icon-circle-triangle-e { background-position: -48px -192px; } .ui-icon-circle-triangle-s { background-position: -64px -192px; } .ui-icon-circle-triangle-w { background-position: -80px -192px; } .ui-icon-circle-triangle-n { background-position: -96px -192px; } .ui-icon-circle-arrow-e { background-position: -112px -192px; } .ui-icon-circle-arrow-s { background-position: -128px -192px; } .ui-icon-circle-arrow-w { background-position: -144px -192px; } .ui-icon-circle-arrow-n { background-position: -160px -192px; } .ui-icon-circle-zoomin { background-position: -176px -192px; } .ui-icon-circle-zoomout { background-position: -192px -192px; } .ui-icon-circle-check { background-position: -208px -192px; } .ui-icon-circlesmall-plus { background-position: 0 -208px; } .ui-icon-circlesmall-minus { background-position: -16px -208px; } .ui-icon-circlesmall-close { background-position: -32px -208px; } .ui-icon-squaresmall-plus { background-position: -48px -208px; } .ui-icon-squaresmall-minus { background-position: -64px -208px; } .ui-icon-squaresmall-close { background-position: -80px -208px; } .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } .ui-icon-grip-solid-vertical { background-position: -32px -224px; } .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } .ui-icon-grip-diagonal-se { background-position: -80px -224px; } /* Misc visuals ----------------------------------*/ /* Corner radius */ .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 0.3em; -webkit-border-top-left-radius: 0.3em; -khtml-border-top-left-radius: 0.3em; border-top-left-radius: 0.3em; } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 0.3em; -webkit-border-top-right-radius: 0.3em; -khtml-border-top-right-radius: 0.3em; border-top-right-radius: 0.3em; } .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 0.3em; -webkit-border-bottom-left-radius: 0.3em; -khtml-border-bottom-left-radius: 0.3em; border-bottom-left-radius: 0.3em; } .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 0.3em; -webkit-border-bottom-right-radius: 0.3em; -khtml-border-bottom-right-radius: 0.3em; border-bottom-right-radius: 0.3em; } /* Overlays */ .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_highlight-hard_40_aaaaaa_1x100.png) 50% top repeat-x; opacity: .30;filter:Alpha(Opacity=30); } .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_highlight-soft_50_aaaaaa_1x100.png) 50% top repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*! * jQuery UI Resizable 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Resizable#theming */ .ui-resizable { position: relative;} .ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*! * jQuery UI Selectable 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Selectable#theming */ .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } /*! * jQuery UI Accordion 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Accordion#theming */ /* IE/Win - Fix animation bug - #4615 */ .ui-accordion { width: 100%; } .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; } .ui-accordion .ui-accordion-li-fix { display: inline; } .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; } .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; } .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; } .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; } .ui-accordion .ui-accordion-content-active { display: block; } /*! * jQuery UI Autocomplete 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Autocomplete#theming */ .ui-autocomplete { position: absolute; cursor: default; } /* workarounds */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ /* * jQuery UI Menu 1.8.21 * * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Menu#theming */ .ui-menu { list-style:none; padding: 2px; margin: 0; display:block; float: left; } .ui-menu .ui-menu { margin-top: -3px; } .ui-menu .ui-menu-item { margin:0; padding: 0; zoom: 1; float: left; clear: left; width: 100%; } .ui-menu .ui-menu-item a { text-decoration:none; display:block; padding:.2em .4em; line-height:1.5; zoom:1; } .ui-menu .ui-menu-item a.ui-state-hover, .ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; } /*! * jQuery UI Button 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Button#theming */ .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ .ui-button-icons-only { width: 3.4em; } button.ui-button-icons-only { width: 3.7em; } /*button text element */ .ui-button .ui-button-text { display: block; line-height: 1.4; } .ui-button-text-only .ui-button-text { padding: .4em 1em; } .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } /* no icon support for input elements, provide padding by default */ input.ui-button { padding: .4em 1em; } /*button icon element(s) */ .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } /*button sets*/ .ui-buttonset { margin-right: 7px; } .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } /* workarounds */ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ /*! * jQuery UI Dialog 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Dialog#theming */ .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; } .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } .ui-draggable .ui-dialog-titlebar { cursor: move; } /*! * jQuery UI Slider 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Slider#theming */ .ui-slider { position: relative; text-align: left; } .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } .ui-slider-horizontal { height: .8em; } .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } .ui-slider-horizontal .ui-slider-range-min { left: 0; } .ui-slider-horizontal .ui-slider-range-max { right: 0; } .ui-slider-vertical { width: .8em; height: 100px; } .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } .ui-slider-vertical .ui-slider-range-min { bottom: 0; } .ui-slider-vertical .ui-slider-range-max { top: 0; }/*! * jQuery UI Tabs 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Tabs#theming */ .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; } .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; } .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; } .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } .ui-tabs .ui-tabs-hide { display: none !important; } /*! * jQuery UI Datepicker 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Datepicker#theming */ .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } .ui-datepicker .ui-datepicker-prev { left:2px; } .ui-datepicker .ui-datepicker-next { right:2px; } .ui-datepicker .ui-datepicker-prev-hover { left:1px; } .ui-datepicker .ui-datepicker-next-hover { right:1px; } .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } .ui-datepicker select.ui-datepicker-month-year {width: 100%;} .ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-year { width: 49%;} .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } .ui-datepicker td { border: 0; padding: 1px; } .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } /* with multiple calendars */ .ui-datepicker.ui-datepicker-multi { width:auto; } .ui-datepicker-multi .ui-datepicker-group { float:left; } .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } /* RTL support */ .ui-datepicker-rtl { direction: rtl; } .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } .ui-datepicker-rtl .ui-datepicker-group { float:right; } .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ .ui-datepicker-cover { display: none; /*sorry for IE5*/ display/**/: block; /*sorry for IE5*/ position: absolute; /*must have*/ z-index: -1; /*must have*/ filter: mask(); /*must have*/ top: -4px; /*must have*/ left: -4px; /*must have*/ width: 200px; /*must have*/ height: 200px; /*must have*/ }/*! * jQuery UI Progressbar 1.8.21 * * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * * http://docs.jquery.com/UI/Progressbar#theming */ .ui-progressbar { height:2em; text-align: left; overflow: hidden; } .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }freeipa-3.3.4/install/ui/images/0000775000175000017500000000000012271707664016046 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/images/firefox-icon.png0000664000175000017500000001373312202434255021136 0ustar mkosekmkosek‰PNG  IHDR27NòtEXtSoftwareAdobe ImageReadyqÉe<}IDATxÚÜZi\ÕuþÞÚ¯·éÙG3i4ÄH„„™Œ…+N°I/©‚Û! ŽƒË‰‹ry)ì„ØÁx 8¶cWa›Â”7lf'–Á˜HˆKHBšÍ>ÝÓëë·æ»÷½5-]åT~d¨Ë½y}ßýÎùÎ9ß¹¯•0 ñÿáGÿs¾µûä¿( LØ?¥cÇm]P4‡ªñ#ª•C\S´xVT~FÏ(ª2Mߢ'›Œ¤5 'L‹7# Õ¼Ö–<Ö}îÈszÚzÉÉÛS¥G÷‡I°ª|¤¦†°øÌ£ySAÿ‘þ)þê¯ ?QByÂEn|ZÚç^müä9G@þ¹d&¸Óíª^lf“geº²[ºú;úÛº2m‰dBÕ2ku­3S(e’‡—ðWWhú£ïFøC‰ñ lÑÕð*+c\Ñ560²qçlݺ#ýèÉ¥1Ô¦±}Þ›Ükß|Íë›,;»ž_ª}à©î„ûìO÷=¾\¬~7Òï24ä•ÿc [T%¼!Ýf¼«}tX»äLìÃPWîd-W5Åâ`„‘×¼xî0uä:ulèJaÛP§ñý.ýÂyþ£Ï/|"] ¾¸ºÓ¸UUPþ_¢«¯þ'7óQS>–ëéJtoÙŽ3voÅŽ³‡6xv€.K‘.8¹ˆF3 ý0òÇÑÆ8Ãìÿå¾¥›~õìò_úЮSRÊC4ãî÷¢žxÄIã<¨¡v4OþzŠXo„×LÁí=‰Îá]Ù²£#½¨•jÈqkkB£9Ý D;v‚h¸ñìøâ÷@ζÀ÷ô§ x¹5xò¨ƒ¿5‹}ò´Í;GBí¥šÞK䊦ü~@Tß}õ¼Ów„¾o}ý7¦ˆ…7)Jð+C.LçºÑÖ{:2™4zz³(ªÈÓE_‡kWQŸŸBÝõà„- 8^«‹™`lŽŠçÃ$ð¡5ÈmÛ‰k¿SÅñ‰ üâ¦4n{ðÉo—F}ø›î¯•Š{±¢+¿HPwO Ç…_u?¡.•Ö9XyãCµ I¨ŸÓ/}–•D&7ƒiÒ •jvˆ¥²‚äoÿý7¿Ý×Á¸çópTZN•`äLЉ³›ÆdÑÆÌR…)XÃàYÛpýI|ïîC¸ö² Üzs÷i7c÷è½ß­üÜð¼7¾žg¢qc&ó¾Ð ¶8Köj¹ÃîèÕ:õRÝJÔu–ÙÅMñ#Y^×PŸžÃ›ï» #GDÚ/`áü·£ðΑ è¤Jk«JÄÔÿÆË¨ó÷¢€ŒE…kÍlØeVà`ÛŽ øÐzSO`÷ÍàÖ¯nà {¹•zðÎ{ÏíîþvvWòZÒÍ;uA\,Ÿb{ç{sÍ'Œ[Ï}uÕ2þµ¾ë‡:0Ò7‰dªˆ’чEã| ƒ‹Ï2·š˜[³O^úY êI„ôªE뉬¥6¢`¤w}üv®Œ„©Á®û¨”‹M[ƒÏ~étÜ|íx"uÇÞkÎZ?ª¤pMà¼:H …#s+@ôz0]”](« œyž†ï'ŸCàjŒÞne`´u"xSùc¨'3Èå<Ü¿íj(kG`;Bf#² άùB$H.ç9Ò÷åù *5Þ²ƒjÍE1æÐ#zº ·Ý¿€yÇaÜñÙ3ðн ÌÁêUûqͧÏÀ7ÿd™μ÷ì†r ß• 7ÇH­âËas,/¸«&§¨›Òè8»®o`iÂÃâd ‹3%,NLãøó/aæ•9ø¦‰tPNwâØðE0q0sÍ*TÄÌQ‰/ éR¬%IjŸ ugoN±®$ÛÈ­êÅ?~}KÓ¿Æ»¯ìÒ«Q:¼ˆÍíG1þÑ­xà_ZÉÂn¨bý9t ¥¨oÔ—™Ä4 5¡»¬n‚2VF…Ù¦#,æÑ÷ìÃÈ_´n´® o)QKDá`†òÃ(ÐE4vtZŒ#.™Ô¡'«T¨¤§Y ž67µ ÿÊÜuÓ$ÒëW¡lbù¹£¸üâ^Ü5Œé£îкQóJg![ƒ»Èð«W€„Z=ÓÞ¯aùP.݆¤”ª‘Z¾¤L¨ ªPP&„FT¡›*ÊŽ‚óðqØ8oóvÒ‰V6Ò8Ö¾™tÛH°Y Ä`Ĺ‚ 4z%Ý££J¯Tȧ®À@÷`î¬{þ«†ñ Ž!5² KS&œÃs¸ô=](¤4Öû orî6'»b ëÞ2*£2(•/.OL¼eùp.ãÄ‘©‹ôJ!+m(T®À¼_C‘òƒÙ‰‰dì‘o ûÄ7"EÊ{î™5ðÓ?ý2¶¿÷p ²ª @²8"ª- Z‘Æm[Ai¶ŒjÙµzaºß{d ã[ËPÚŽ#5”Äò‹dKŸ'K³[TÇB=¡gϯx¤2;/e{P)ª¾`ë„Ü<·òA‚Za fá^ ƒ"*$€€×uƒU†„̳)ëýº‡DO[ÎÇÝm#˜˜¬Ó(޼7 /˜ žh2>§ Õü"rÛ·£só&<úÜaçO•¬^vWš÷:H*exªßÎb” œâÎ/ÒÄÊ.ÕÁ¸S$Ÿ™QÄCÁ>#ºI*õX² Pܰ".B³ fM;ÏCïÛÞ k ÆôË(unÀ7ö´³`fÐ]²Y?"Ò#BªÐÛŽí“j:)UGe©€ÊrÏeâY\BX)bºdáà1göÓ°)z¹KH¥, X)†Òí,5ňb™¢xý¹W¬+N•–¥«aå V]adýPi4 ŠüOV;R½#…¶ñ·!;¸Fo?8ÚOy‹Œøí—õ1ÅÒ0¬„vÕ¥–OŒ­½ƒ4ÊÒÂÆPÜÿ$œgž–jyÙ1q€ó¬NõÙf'÷•î![º¾ǵ’ ³&º@Ô„– 7Þê !g‹}„¢ÉôIHEROn< ³»?èVB­2ñçöuáQ{-ú·žƒ±‘Õi”Ë^lˆŠë* ‹p§ŽÃ\GÒgÚ`ÏM3©¸Œ“*.Ú܆ç &X ‚M¬5%RØ  ç¸Fdwê(´ÎI$=A­‡" †¾5t½!Ï…Tºb£2>Dp 1 6Ï %â\¤a•Ygª§8’Ìl–UÅgžLáÁô9Ø4¾¯‰¥¼r=.¶*ìÙYؤÞÙA­L•LJ9U ̓˜¯-8³Ç¥åœZê<¾òáA<~ s†Yïx ÞR úKõaÂ/{ÞÜ!åòο¶DÑ´ âÕàiŸ^™)™­ÈEÁ&¼@ïÁÌ$¸y‹>…D6I ¦‚6Žub¯²^ÆCu™Ù&NÕ3€z¥†ÚܼÉIøTȾçÁ#M˜dd²à>h8¾Rpð•%\²ÓǺ¼ /£Ñëœ &š×ÕP*©úþCÞ†‹†S+1 œ ë¬wŒ?hP)Ž-Bh ?CÇ¢GÎVep&úжâ섃<…¤ã×Qã¦D_Ò Dä@f…¨(–+2f|¶ !‹%â0fB˜”ø6'12êÊÞ&ÙËÖ`ŽÏ÷hÞ–UìÔqqÂÈRõC¿f}/Œ¹ /±­‚›Þzi3SuyóîêÛû§Þ€Õ-ÂèOB)ò>U*_BâIB‰’†E0î‚rƒ!cB^÷c0ÌZ!û×µ©ÁjHUhz‚ÀK0W AZ#¦ )%ì©(+@Býµ™Z”rEõ”Æá“ÅŽÔž9z †ùãÒI -DÚò‘ß° ½ë¶²vTp‚A¸ ÊŠ@ ÿKeX·‰÷P;ü’ì$¨Ø+b…§Uwà({^°ðÎkH¯8{ˆ Ó¥¤23F = JÜ€ˆ‡}ƒ©0ÒÔC&d—heøû¾Gq ?†}þÈjuyÈ&6(>Ë*Áö–M«±Îôç°‚ ½–ÔEú´iå¢ôŒÔxÁ 6åLº§ŠD½È5Òô6µ•&þÆÂZr°Äú}õey\ºý,°¶¯±ƒã^Å[FÊÈ9,†¦&Â]E³Þ§cI‚=6$"  ^YÅvߊ[–/Çjã()©(Móg­2…?¶öâÂÞ£hg¿”Z…»­ÃÏŽ @«.Òò4žëIG@XíÙ9®í(ãüÑe(Ef³äk®ÚU‡Ë&ÌR=¼ehÅ~”ƒ½+©ÎÚ±¢?©¹á%ž¨”V’ŸÔ¢À±’°TdÓÜ=óÄáAœ94<ØuîÖÀ& ~°’e¡3ö°lŒ—™†K\È¡'D̤Û5É}E‰Á˜Bƒéòš#Z[ÿç.™ÁÍO›¸û({†™J7#Ç׸ù<®½DU>Ð‰Š [†ì"†ûú1[ ñ±3÷ÁÉ ÐÜ#5Y4>Ç-;Ö$?÷£ý˜›ìÆÛ>2þbÇe—Ð[öÉ‘^ ‚ÏY†6^vI¯r œé‰:Ö³r»R³hQmŽE™ ŸÈñ5»N}jÇ!\¿õz&‡/<»/.­ãSHÇü$”),çc#ûï_uzé·ò¼8×ÁT™MÁa†›WMÑV¨LÉ,Æ”û&Ûqû3Ûðù+Btìê}(œ:ª½ç Õâ'zóÙ¿BÁ÷‹b=|sÑWdûÞBßWÖD*Ž,%†.ú]HDjW€B™NLüòxöÏè˜-Q/QrtÐs› `ǧ¯ñ0dÚX.„H±'7;ÓM å‰<ëEæªNxËìCmk®yü­xßE‹xÿW½äú鳘œ¤;gßùa_Ëk£´/ï S&ܲü´ÓÒÈuF…R‚aJ–C1%¦Ÿ")h²Î˜â-:¾l2tÂ`ðhµ VWØÓèT ôä0;–jHô@MY(>5A=àÞêZ¬zC'Þñ¦Yö——‡÷ògõ ÇNŠ‘ÆÏAîûúŒ¡|­æF'ëââÀÁ*6mL²+UåQŽa‰ÓnS€á¬ê 0²-ƒ-NUä‘iTY…hÕuàkòÌLÈ·È7?Ž8x(Õ‘í€Ù—Eù¥9v  ²³¸z½MÕ} ¥ýÚ-õ…ðžD²ÅöÂ#wuëx×¢šïwë·ÔåC 5_¾Û/5“¤Óð:´7®›±W̸‰i½mjtü<†GIj,{ܪ*cE¥‡DöU"¡0L¯kƒÞe¡t`v¡\—£XBI(_j»2ÿ¡Öw±­u䤟º^O±ØÕ–ЮÌ;|-`³Ê¿|ÈÆ@Õ@  Œ{ºTį™ôžƒ Ñ!^3¢ksBðŠQ€Ú g¶³FÆ’åuª‡ V„Oz²Ía=ažÑ´ |8ÿïñyuØ Fzä;:®,œä‘é{{Nÿ"™sݲ8eüevC{NÃêAK¦fUX›ÞH¤4é%q“ؼ ’F}ˆÂë‚ۆȦܤìw¸òYs|§ÊݺÐS|–©==_2>xÞ-¥'ât×ü®0xµZ€(Msãwí¶ž¶«Y°ÿÍ®U2.”•öÔ䦻(&;ûL¤3ª,šš¥e5¦¤Y¤gq !´¡*½Ô0m"„ a‹K¤^æv?úw{޽ë©ã²X+yûļJ /4@hñ7óÅ;ß7²åÅÞó·ÐŽÛ…ø È]ñr³²àaz™-PVC–ÞIjpãšxÊÁÚ)Îò¢C>D©Úâ|¦ ƒ8˜.gðÜÜFlo7YÎÒcóög"ïÁ7ïÆ/…ñziPãaÆq$f± ÑÎx¿¶C{?÷û׌Ó%ÕÄù­ˆyH¡G_ý”Qåé‹ö£#¥D¨ÆÃŽg'â4Ñ+h¢4½ü0b–P ñœjü~–¥l<7­\™T•sëñËNñÚÀGlu-Zé„y¢ØJd;Î ¦^=¡HQyZs—gç‡x øÙ‚ùø=QcˆwEµ&@^<‚SQ«•VFì‰dô- 9˜ÌSvhs|gÔRžä¸ ­aŒ‰À)âý*ÍD Šœe“ÆŒf™êr)Ûcέ©•JÝ?^¨VX ^dç°°#~¾ÒD)÷„‰Vö©œê›Ê)fµ)V43b%Úá<ǽmžêO(£d™.J½“¥¥ƒõ$!Þ°±+Xô„û™uÔ²í¥šçbK×âg¥š‚¹?Sk¢»Ò’ˆNùŽðéÍk²†Ý²h#Ø!P];¬²ØçH5Ö.䲺ÒE09‘ n8ãE/¬HA¡eåZnÿ`Tj\o·ß”±ÂÖ½*/ž)+‡´+´ÒcZ%bë7ÇJë0›æ†Çô¦7Š˜Ï^Óp›9ñ¨Æ *8ñNµÖ#NS;)FÂ&w5»6hʵx“­C‡ÑD½‰’Ítš¬Úð¨×du§i®· §ÉCÍ넯E-Ä‹…-@Ô&ji-4Óš²^s š®-÷„-ÏRqâËCAËìµn¦X¨¿ÎãšãÄo©1­I¡ycê«¿ytR" [¾ ÓÌu­éßÁkì£Ù›+±¢¿Ö·ûš6¾FFký½ùóê)ÒyÐ’ ”S xµ‘‡¬IDATxÚbüÿÿ?%€‰BÀ"öíÛ'¤ú8H} €¸ÐÉÉé T€Í HjYÐ7àÓ¹wï^ uª'% i†ª¹@Õ@¤N,ð3(†ö±ÐùŒx] ¬šø65Œ ”LóѢѪ¦kZ¦x,B) îFFF‚þ¹†Èò ½Lâü’w°z…qÀs#@€I<=ìÅÁp£IEND®B`‚freeipa-3.3.4/install/ui/images/mainnav-tab-off.png0000664000175000017500000000021512202434255021502 0ustar mkosekmkosek‰PNG  IHDR)ôêCÒtEXtSoftwareAdobe ImageReadyqÉe</IDATxÚbúLïß¿g`b‚ÁBüû÷J‡Ì¦;w20€%Pµ\é-¢¦+vIEND®B`‚freeipa-3.3.4/install/ui/images/ui-bg_highlight-hard_100_f9f9f9_1x100.png0000664000175000017500000000012612202434255025011 0ustar mkosekmkosek‰PNG  IHDRdG,Z`IDAT•cøóçÏ&†áJüÿÿŸl±áIM" ±¶tg¯IEND®B`‚freeipa-3.3.4/install/ui/images/check-icon.png0000664000175000017500000000105412202434255020542 0ustar mkosekmkosek‰PNG  IHDR&/œŠtEXtSoftwareAdobe ImageReadyqÉe<ÎIDATxÚ¤’M(DQÇϼ#1M‘Âì,“B#±ð^…¬;¥|-Kk" ,hL²˜RŠ•Lˆ|Í0’ÏÉ÷õ¿Óé-XLnýîëž{ÿÿsÎ}Wã nFùR^3žwü¯~c0yâ ˆè†m3ÌN"1ÈS¼Š®!ÞãÀÆÃ*󩹬÷²·ã±UöÈOäƒh ŒnbU3U¾°AîRnmЧt"1›ÏÖ§7×zkß‚âu0 :‰UÛ«½ØË Ð 6&À 1i_bWܤ½ÎSÇèñU!î!&ÏÊçü>BI‚SþT¾ƒúq`,Óº´¬ä¸„ÑÖË`(œ™_œIÝ¢†Oï_ïQE“Es®CW ¥áßfƒðŽÀ‘R¬:œV¬üêg  =$nR0^°°{°[I‰ă{ðq©²íltV`u÷çcâfŽyG\lWì µ¢ä6€¯<-oºÝîd¾B݈zžcÎ)Ôµëö¨…XùH¹Ëb±äñ80ˆºt h¹wŒ§ˆƒ™úD}’©ÞÔä±{&À(ýV4õ ÞáÄy™©"SŒèî<ƒ'!~á×¥2ùø`%¨s‡ZhºWIEND®B`‚freeipa-3.3.4/install/ui/images/ui-bg_flat_8_225314_40x100.png0000664000175000017500000000032612202434255022534 0ustar mkosekmkosek‰PNG  IHDR(dƒcBìIDAThí×± ƒ@ÀИ€•Ø–¤¢@òOx.Oã;$˶¯Ÿ×÷qáA‹‹ùåô@._mðNƒžµAƒ¼ü¿3!!!!!!áß…>ô„„„„„„„„„„„„„„wŽÿÑO3¾ãiVVVVVVVVVVVVVVVVVVVVVVVV¾0Ý *´\VIEND®B`‚freeipa-3.3.4/install/ui/images/ipa-banner.png0000664000175000017500000000123412202434255020553 0ustar mkosekmkosek‰PNG  IHDR‚%Ž1«sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ-:GTÿ©tEXtCommentCreated with GIMPW÷IDATxÚí›áMÃ0F¿ ÈaNLÐt‚¶”lÐNLÐl@6À#dƒðç"ŽÃN“ªÐŠ|O² élçù|® iÛ„\q E PBE PBE PBE ü{m¤í%fÓóþÝÀ{u‘ˆÙôôµ‹ÉGö+4Þ=E8ž@%­‘òÀyŒ±~e&.Wéï)‚â@bÚÌÄÔrmà€—ë·î•~g(¦Mìþï]ó“uˆ[~€CòWç%§túÑén=‰QÍu¬Ãø¿º»ÿuÐÇÒ^“ ù’¾JÓ›jV²÷Ûo¶ä ÿ'ÿAüMþ1`PÏ!Ï@Ç÷|¹ú†5¯€_©—¦©óGÚ€b€·UVñååobm *ÞPôM {¤l¾|ò߀·Ë7¦2 ÑDr,jQå¹Ï·€ÎõlK$— }»Ê;ÿ¨¹éÞ9Ë{»S3GÏöÐp< m€ÌÕ)FŸ Ñ¤²8@@€€€4 ý [ÊZv <מ‘ËÚ£€A$ÇuS¥2•ãÖÀ:’cþ‘}„°–;9esÌA}ºò€ Tvòòâq ‡ågèZRÙ)°·žË·6ÀHgáV\£h`L@À«m„F8àuNထöÑ ûcÚ`!Œt6šâ€§R6ÇÔžÖóÏ6ÀŒ6 #èùÊ£€AF§fvŒp èÓ•Çke-ߎ±3ÂK0ߎ±ËMí¡À–Ì—Ôù…=…êÃ6ò‹jZ7@W5-`¬ZNo44 ê¹s´†€n=g.R€4hÃ0ðØD¸>ÙèÖóò"æíÜŸÝzμÄsì~t;Ù&B8À&Bx®º‰pýS ÉU@ç …@7’m"€‘Ñ&B ë€.߯nVeC÷7cÕ1v¡ Ñ¤rL¯œ¿)˜—x¶‰Fl"€Ã ]m"”ΰ'£omžJÙs=[‡€®œÊK<Çò†€u=—‹Î—P¯=;¶ê9¸‰¹Í@ÛG9›+ÐÆ6 «L帀º‘üq•wZ‹ž¦É£€-)˜oÇØå­…V  ‘"9úü±îÑåß@èÜС¼‰ðtå@©ìäÇGæ@© æÇG0 ½€N/n#åF8 ‘¶æ·±lj+ÐÐhj9v?º‘ó¦Bõ ƒ†Nåu3ì/éjÔs(G8Âý‚o Ë‘|áðD`¿K¸¯E䀮2˜cyŠ‹T`KºQÅ&BØå±‰°ùÐd›à˜K·¬€n*ty•÷|ç1 ›Ëó7R6?®òvt3:§òÇ)ºÊ`~l"4¶[ÊZŽeSkhX×szq›.$ `+ Ó‹K®iÃÐÐUÖr,ËÚ 44šN®f €-èò=ÐMç$–ေ¨ž`¬Î?Õа®ç* ó<‡“ì`­ìäÇUÞÁ 4ô´+ТöÇt,W¤Å4¬£9½Hå=ØO@Àñ€NSF8 ‘"9=[€¢³Ÿ`§%ž/oëÐsÁÓà͵'@_³Ù 4<Éè`^# àx@ီþÇ4Mê¶z æG@§K½=èÖsÙÌf `¤YkÐp@µ‰0vIŠäþ9Ð&¡ Ñá°‰žfôm¡t€ò¸ç%žcùÞQÐ0ŽéjZ@À:šóëèüêãMtªT–H.7 Þ6¦¿;ÆK$ç`Í9Ð@×cºéðh`K»‰¸m"\þHëÐNီ%•«è´µP@@7óu—æ³Ì“@:¯Ã8æÏ< ÄtжҹLåêh ]ÕM„ÀN´É x*esÐJºÝ\tºEÅ£€-ù.ç@Àsí9Ðizš&J)’;ÇØ®< (5üØDؽéÞ\îäÇ&Â%¨¥3Œ3:­CßÎßp•7l¥sæ³8‚s àY@‡f„à :o%t4ìjèô¢:ÆÎs€µö»`!l(7†<½.k`]Ë裧kK*w®òF8`¥‰äKú#Ï@gžÒ9·qZ7À:£Ó‹jèjNÚxl"tl5t»‰ðtçéÀ®€ö\`ÐÐU@Ïó¬¡`«žóVÂ[@»E¶ê¹ æ?š“í€,k¤l~œíhØjèàhxÁ# p@W™Ê·õ ã†nG844lÕs~ý8…xœÂ‘ßLÓä¹Àº›«‹TÌ@ÀX;ÞÈhX§s™ÊÕ&BÃÐÐÈ7&—PÜD˜Û à^Ï¡{áòæ|>{@°¶¤r5ÂQ®=2˜m"€‘þ&B£ÏЕ.K©ÎŽ‚€me-ß.R‰1 hØ èÌÑã€ýª‹T<X+SÙ 4`žè¯@»KÖšN¾ÝD¬@@O>paK$wÎÎí@W{´z€A:'±ü‘†€n=W#a5ØÜŠùz‰wÞ.X­@ÛDišÂÖ ´§æÀºØ|àÀ: óÛKùÙ4Mó'À›KaœF8²Ç ´h€­’ng 54léœ =Íy±üÀ 4¬ºìd#ðÄæGŒÑÓ€¦ž;mÆ]t0Â=››ƒuhXi"Y@ÀKm„Ö6G84tm^¤âÑÀÚæE* ¬ë¹tó°NeWÀ·€NMm ÖÊT~Œp4w|e-W ìq)³z.x4¼¹Æ›©á€FÓÉ΀ç ÝèD@e‰ä~@/¦iò€`Éf `d4-  ÛЀnf;€°Ú+XÍ@ÛD&’pÀÈæ 4ðTÐnð€½}:Îç³'U1.Ržôt~e!¬¹H¾E@ÏW”šNv‘ Œ4cŠ(.õ®çÂuºœÔ¨f 4¬ºœ¾”ŸÍO €7× ã¸UÖ@XMjØDTmޱ€×Y€+Ððº¸UÖÀ:•pÀÞzÐðj@»HÖ\¤¯«V cÔÓPsŒ›+ÐF8 ÑDrg¡­„°•ÇU@§ëÐø™s6ÂÏ3ºЧÓé|>#p/äåïK$÷7怲& /MbÏwžo.…ñhXg´€€½FÇØÙ>cV `dsútå@ÐýcìÖ €tT]' €n@—oãÖ@¸NjlŽphhhÄû#êºú+Ðù% [al!Èh#0²¹‰xJ@À«mŠ›3Ðá:ÞáÀ@u‘JŒ1X‡€«|ÊóæE*ÒÖýä"`+’4¼ÐiØŠäKóñ|çIðæRV ƒ°ÆF8`¤‰d›àHO hx> ì hWy@“Î΀Îçóf@ÿôÓO "Ù 4ŒŒŽ±3 Ùóh ›Ñ£€¶ aÏUÞÀXÐó<{"Pš¦i3 »SÒðžRNáÎÐÍè~@Ëh‡±‹T`d4Âa!4šH6Â}΀Ϻ4ïç;€7—Âxt ‡s  Éã†8 s ‡h{V ¥3Œ3Ú1v0JçÑ9ÐÒ£›e4ŒÃØ)0â*oØeï)¶òØ&BxžÑý€–Ñ0ãúHŽhO!TÎçóf@»Ê²½©h΀ÏgtgÚ 4„=ÇØ¥ùh 9Œm"€Ýp‘ à"èë†ñ¥|3_…ÕYwðžÖaì;8Àô¹H>›ÑV `W: hxÐÍ>B#p€hè3‡z´‰P:ÀXg:FƒÑÐc+Ð02áH'tÈh{6¦5j aÏ&B`Ì 4ô¥0n¶Vo¦iÐPtŠä~@w‡<àÚ 4¼ÎUÞÐ÷ü;#0Îc#p€hèÛ»-  ì¿ÊØŠäKùfžçæ¼³uှç#À˜€ ß- Í@@0 Ÿgú¬@ÀgY€>+ÐðY>ÐF8 á€ÏÐð¹€6ÂÁ|ž€ ß! çyöD`o@'6@ãf•Ù  @@€€ ~P—òM>¡ÃÐÐ c©À†®Ú*Ðh"Ù 4  àÕ€6 #ð: 4hÐðƒúŸ‘É8âÊ“_IEND®B`‚freeipa-3.3.4/install/ui/images/ui-bg_inset-hard_45_cd0a0a_1x100.png0000664000175000017500000000017312202434255024132 0ustar mkosekmkosek‰PNG  IHDRdG,Z`BIDAT•ÝÁ €@Ä2³;{pý·eMúÐDðy…cïÓ„„ÕéÆN0 öZX3X öÌ£wM0UXU_/¼€ ðg6>>±IEND®B`‚freeipa-3.3.4/install/ui/images/add-icon.png0000664000175000017500000000200112202434255020206 0ustar mkosekmkosek‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp ÚþfquIDATxÚbüÿÿ?%€‰B0ð°  ÂÙº&fï¡LÅËgN}1Ö¯_O’  Ø€hmUR hÂ@qýŠqç¡¶"ƒ~( ò† mX‚HÞ¥2G øúD#ø¥/àRÀ8š ÕzoèIEND®B`‚freeipa-3.3.4/install/ui/images/background-left.png0000664000175000017500000000617112270466515021624 0ustar mkosekmkosek‰PNG  IHDR ­/\å_ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¤IDATxÚìYAŽƒ0 ´“H<€ |Ÿÿpã ùBÝS»ZRoeÉÄ‘ª i”8xfâúë·,‹\G¢›ñx<~<ß[`JÉxFÑ™ÙxF50çìµ´ú=Ú§Ð>3ö)TïZ½´ý GØÌÇ1–ã8DDˆ™éúÿëºÒ¶mTÆqä“’}ßiš&šç™Jm×Ã0œñ–šíåœÏPJM×¥bfbæ{ Q)åýÒ"rºÅÛ¯J¬.ýVgL)Ä`椰¶™+ÕšÚÚa¬ùc´ç£=)ÔU³}Œ¡Bx#µŸá*åH3Gâ"ø£}Ý£—:F{ÇE8ˆP‘"x£¸ì3cßVl èxh:Úžšj†#Ð A\Ž'ÂYˆ ×>Ëûn!BEÚ§fìmÁÍìù¨Ö B¿§Ï>…cÝ£Þµc í­áCÂݵ© ár†°tŸ×æ¦6Ó”®#×ß#ÂW„\#\íû¬{ú¤™}yݧ¸úl 5urõÙÐpì4õzú”k¤0€AŠ0€ `À0€ `?>,ø¼Yí›IEND®B`‚freeipa-3.3.4/install/ui/images/remove-icon.png0000664000175000017500000000206412202434255020764 0ustar mkosekmkosek‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp ‚‚@¨IDATxÚbüÿÿ?%€‰B0ð°  Ôµ¶Ã%ñò™S `âº&f @j>ˆÝT]ɈÏ ô| ¦~¨æ~˜f$yœ8")*j¾¢‘4;â5èì @ʈ/@… ôf¨<Á@ü€CìÁX:ÙHœm€d3”*×ûXÊ^t²"ˆ†ò òx @ŠÆDh¸€èD4y0`Í ‡{5ÀݰIEND®B`‚freeipa-3.3.4/install/ui/images/search-icon.png0000664000175000017500000000216212202434255020733 0ustar mkosekmkosek‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp ÞæMæIDATxÚb`ÀtMÌ ˆŒhš€T=#k¾Ä—Ϝڀנæ¨f\`ÐB¬@m^l#b4¢»„J×#iv*ú€ä²@j?Ô:˜ 4̆FdÍ å7¢©C€Úpøÿ’‹P Úp‰/€Ã$Àæ˜!õ@ТV-Œ°b#4@ÞÙÔ„+R’`aäˆìm&$¿ ÄâL¿ÉEû‘ž_^@¶ ªi?Ô¸KHX Qd"Ũ‹ñ¤¢]"‹n€ºW÷ÏS¾õIEND®B`‚freeipa-3.3.4/install/ui/images/mainnav-tab-on.png0000664000175000017500000000164712202434255021356 0ustar mkosekmkosek‰PNG  IHDR){ˆÔ…tEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp AñIDATxÚbø÷ïÃ`Ä ÿÿÿÑtF6\kIEND®B`‚freeipa-3.3.4/install/ui/images/ui-bg_glass_55_1c1c1c_1x400.png0000664000175000017500000000025312202434255023133 0ustar mkosekmkosek‰PNG  IHDR_:MrIDAT8íÑ; !Ð ñÛØˆˆbmé=¼åUœKì®kóÚ$sÎM8rΛ½w°Öúëð“˹ÖÇ ”ò¯–Ÿ­µÍ#˜RC/hu?¿|”R6•R 1ôÞƒÎ9ÐZ j­A!Ä š^>Å*’üíIEND®B`‚freeipa-3.3.4/install/ui/images/Makefile.am0000664000175000017500000000311412271663206020072 0ustar mkosekmkosekNULL = appdir = $(IPA_DATA_DIR)/ui/images app_DATA = \ add-icon.png \ arrow-collapsed.png \ arrow-expanded.png \ background-center.png \ background-left.png \ background-right.png \ caution-icon.png \ centered-background.png \ check-icon.png \ combobox-open.png \ facet-tab-off.png \ facet-tab-on.png \ firefox-icon.png \ hover-tab.png \ ie-icon.png \ ipa-banner.png \ ipa-logo.png \ mainnav-background.png \ mainnav-tab-off.png \ mainnav-tab-on.png \ modal-background.png \ nav-arrow.png \ outer-background.png \ panel-background.png \ remove-icon.png \ reset-icon.png \ search-background.png \ search-icon.png \ spinner-header.gif \ spinner-small.gif \ static-background.png \ subnav-background.png \ top-background.png \ ui-bg_flat_65_ffffff_40x100.png \ ui-bg_flat_8_225314_40x100.png \ ui-bg_glass_40_5e5e5e_1x400.png \ ui-bg_glass_55_1c1c1c_1x400.png \ ui-bg_highlight-hard_100_f9f9f9_1x100.png \ ui-bg_highlight-hard_40_aaaaaa_1x100.png \ ui-bg_highlight-soft_50_aaaaaa_1x100.png \ ui-bg_inset-hard_45_cd0a0a_1x100.png \ ui-bg_inset-hard_55_ffeb80_1x100.png \ ui-icons_222222_256x240.png \ ui-icons_4ca300_256x240.png \ ui-icons_bbbbbb_256x240.png \ ui-icons_ededed_256x240.png \ ui-icons_ffcf29_256x240.png \ ui-icons_ffffff_256x240.png \ update-icon.png \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in freeipa-3.3.4/install/ui/images/mainnav-background.png0000664000175000017500000010414512270466515022323 0ustar mkosekmkosek‰PNG  IHDRÀH¶¿ ätEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp É­Ù`„ÙIDATxÚ´½k¯,¹Ž%F*"OÝ3ð«ÏwÛãñ¯ñôðÿÿnÀÓ·jgˆÞ)J|(Ωº{çÎŒT($Š\\\Døàóú?ý³ûOÞÐ~@~Ì{–Ë‚÷Nù¥Ÿ%ï{Éí2÷³ùm>Ÿ;xûñ|´?{wöȼ!!O‚YJÞ‰ñ¥xQå7‹æÙå7 éÚˆV‚;'”>ådH`Öö²Úó§-¹èiRúJ÷i¾°“9ß~Ä}Û-ððW|0òíJΗ1¥»22#/’¯×þì Ÿ<&xlç“{w‡”œÜÐÎÎ@l»ò‘<1>Ï—S´¹ì“µ«Ò͈ž{hZáÙªŽNíÁ »åYB˜Í<¸òv`ÏOjÜMÝ“£~fã¸A¾¹0Ý&[«E»ƒâ£~ÆÉÉî_0P‰§‘odò]/(y‰ùĸ>áÿå_*@™ÿ ž/RÍ]!¿Žfdú:úO/»hIÑ})R¯”g®0Ì|‹;…òæ2ã§‹jBìðôûõrÑß²,¬ê-²è–+_™Ô·èñTu©¢¦hë|DÎâò×:϶}ôîBNJYc Ö!Ås·vx–Ñ™÷ ž:ÆÇ̲ð–1—ÝNy¿$fç(óÊ8pEo1àƒÃÕ“áå'ÝÝ‹õ¨±§]œOóVªf’iž¥h ,· C:î_K|ºÐü\0^xýØEÚú‡ÂC],ù1/9/p^rråªnçû³¯û¿‰k‚‡ÄQs·Rô+n·^N5Ø0[l˜×ó“MaÏ”2¯Xœ )ýä‘׻̭W«ç±S>æ'H>nÂ[tÌ1éé!)ðìƒÅóOô Á1'ÎG@LZK«·|5Ö ŒÓér"㸇>çÔ >û 0qËËEJêoDÁšÑÒ·½|_™* &̹n¥K<ÚávŸ,n%¨+¹>¤·`—]1Óž™ÃN?xǪë7ƒwͧÁàv¬ÿdßlÿ‹ÞÀJì(GFÁuÝJà£÷¸ÑœI[ë{¡9tüPÌÁ†Þ1fŠ– –ÙÖèÝèŽ so×çÃÀ/a5è­êeaC`GìFFws›ˆÐô6~1ŠûW˜#¨í¹ˆó¼±ÅþsÔÀ3sE4væûã§·21Øïîêz‚ú`|tE iQ>ô™Tc@hö—¡j^ì'ÿrÇ.‰Í(¿·¸Ã²äR%ˆë’³Às`¢) \p;à:_¶7ÎÎI nÖ†å€;Öz¸–¿îN4òž©uËÈ;Óõ¾&ïî!bí‰{LاYæ­]fL<3åú¬É1]Òão¡ð²7i˜:W{z˜æ!µ­(ž/YË’: ‘ë²<Ù‡ŽGž%vrÀÛ2ømÏþ÷Çø?ÆÖw Œ½gŒx§x°YôPåƒ8_cóç®ôžœý 7î¡xÌÑB‰ž=¤s…WšOl¬F Èúpœ.|Œ©`Ppû ŠVžQ¬Râ9´ë ƒ–ø`+ž—Sæ­))b›ìÆ`£¹ÇÓÙá>à \ɜȂ±[Œ;—×.ˆœ^æZ–èøÏ—c”æÀ`üù `pN'>=Æ1ƒ’F8>ŽOžÛ”ú…‘I].nm“Åi¾x۩Ķçs½1ë6r-±I¢gÁ8s9™ÐsÁÝðú‰‰„ÔLç`˜[˧ŠYÏË_iž7šíT2-öj°[‡ºø¿-_-d¶9™ARz0صìY–\ÙáËGŠ@‰oÖÅ´–ù)óæ%ó¬I{ã%fþ”Ù¹ó×ÞvÇd‰ƒÿ2ç£Jñ±>;Œ1ÆïÓ8<ù™bh&zeY$°ƒTp‡€·=Ÿ.ôè”ÚðÒM¹G¡7#Í>:z.{I1éÄÔ»¾Mñ6ÆN9zq—]Æà…1Ÿ94 1²A~èÙ|LO"Škw–\ã†æÑ—ù§é.Œ¶pOÞbLP”?Tï,xŒ1JO1e„“öSORu°0íâ Ò4‡¼ %wysäìRŒæRœ‰€]ÝÌÂ%°Ì ¨xî¸0 ™äûd­3áò)-IÃÂZ䥖¢y°S¡óË6YìTõž ˜(Þ’žAñX0]´óÜÝÖ%žÅy RتλEIyHqÓ'ëÁ¥`¡gCìä“wî‚Á«ÜÝG&ï Þ 3rëúWïìt“×–†ž@#.rŒAôžÚF-/ÛÄðp>™¬ XgO—[qyÀ9´(U×{¼ÎìjˆMº»ôÁš¯¼821ì<¬|´ÁeåE›”v~†K@³n1 Ÿ€Ç»ƒEÕÛÓÁN5yöÒ‚c JàÅ0T<âTÕ»¢G™(ÆêƒïPjÜÀÖ˜æ“mŽb¡Gº`?°¹£5ª!¡8ЊŠkaN÷ÁÎë…À'|R‘—\­øVåÌ(bnÕ¦_ žïR(p:k`kì,—àƒ]Î"r"z@ÂM¬¡Ç¼R¿(¿@16@qÑ•=QÐ ¶Ü˜$ÓD^)d­ b'°Eû*]ܵQâ,yrBÊŸ¶—…ô$Àع´ˆÔ®½aÙç6‚·5¸ùºuc€ÈV„^¤QS¼Ÿb×âˆ.ÏÒÌ`.iÚ¼£%çGÆ ®À¥ÒRU·‘ Å ,šÄz.é4.'½kö+—B‚Ç5*s±òB;IxíÕøÑÁfÚÉ»}4•Óóa:ñaE&¦¦[þ¼’gš#/[†$}^²’dhG±K²%Åг„‘u²@òVr*ùPÏŸÈø'Ws²»ò%(7¸)6ÀJsä¥Á;iÀ›e Š·éZ›å§€BžôGäß@üøñ±“¸ƒÄ©¸+U¯¨Å.ˆä/\TâÕ€)Q!‚j¢l =áêÎFcàŒbÈF¾²ëÙ38ŠŒÝhÐÝä[zbÎvémÎÎEéYrß&ª¶s›Ô¤æÚ%`“cšá¬$ˆ­ ´~ žIšD !¦Ñz91÷à€íâi¯ú" òÕ›TmYFàÕÅbú˜¬ã á~?סx' D$ö’X-áéGv$*½ŒŠ±\î bèâÁ噇D»3ãï˜éŠª6󀯶‚%âÊZé‰bÖ$t.ÁÁL îÆ]`4"’GUˆ—‚ð@ùˆ@ ‚›ç°¢ôÎL—Ô^äÒ˜°ÃZ 5Ü‹âÊ6åBñ“…gú¾àqÜÉsRq§j„™Á-›K094Òc0c`f»m«Ò†ƒYK”âÇZ<¡LŒ]:ØÝZ‰QöÅÇ]¼áªêÝ\‡e#\·I Ð VfdR •g¡4ŤõFÈsðÀuHUó(¨¢s]sô$,!¥,SŠ(C,ÊaP øf|K±ý”]楢Åï œ3ØÕŒF¢–¶—h€R:!‰pxÂÁ”瀻S)7à”r< p ª<­­Û v‡B*êÈ[57õš`¸%Õ”û¨pü¨FéĸñÄÖ‚c\¾€i«Lá™gÂP|"b"ã.­EE x?cþòd™…~Vs/®û”‹ÉÅc*>šs’Êî èqB,X›<µÈ¹§ rÑe"%B+ÑRO„ÁÓ³Œ(y6€Ì–UÑoŽ*P1MçĪ osÖ°+䲸ãÃ&˜zoਫ਼?©BÆ´`7Êr¸B×ågà+Øå—’Dx‹V‡ÖÅË„$8«<÷ò ‰ÜšeÚ ÇûÏMÉKêójïø"®({ò€ôÄV¯¦ÂÝDkwºù2’b(C°sCݬÅÏÒÕ ¶É:HS«æAb¬òŽiÜù<[p=YrQ9bâAPM¸Mnå’rœŸJ°SÉÀ]*¼t=>1ƒŸIlòeOß'(ÆñªA¸³VeM÷@ñ€(÷̦ÙE³IaŠ{#a z¹¶g]-¹v­(Ñâ5;)ÎÅ€é q´3Pâîy÷>ðÜÄôÁ NÝ–L¹Ô—:/ÂHW¨xœH Ög ²WËê#¤¤aÆòºˆš[þhÒÿ"¥OªH1®tWKtúR3©1“”Äå"”f´]Øó8K¼ãjð¥Å ’VëÓjÈÆÖÝF5º(Hz{©-c? â¼¶{3½¬17V)7 ÆØâLä€8Eƒ±|;¥u™¸ËtA *ã^%w>Ãc~nï¤âQM  Ÿâ.)бм]ðÖ²ÙŠ 6WÄ   ½LÞ$`Z”±ZkðôïŠi8…A¢u©tr£}Š«ž(ȺGºÎ˜JGGª”{¨9>4yRƒAiEÄmzìYjŸˆßYÙrJ³:I»º¾ÒŽ”täAZúxXHyÙ@ÀƃT°ÌL•XLR¨;a‰Á*]$ëNš¹*i`´³›)1¼W‚4wä£`‹N¸u‘´'xYKòŠ áÐN±¤©†£,‡ïàIí@PŠaÍ"5®h‘$*‡®s¿8ô3b‹QróI®_€ñ2qæ„´—¤UI+AÞë”Ð4q+ â(¢#¦¡&xp¬+I–oyÜ•±¢©]ÔhVûÂg2´Û‡`%˜0Ö»Ît L¦Þ ù"´ÏµÏ˜j˜BLöE’OÞSâSŒjdŽ“sýböO%5èUY…ÊH3_u =½Ä¨s7nÙäðà´…”£Œ» ° û!=ôó2a¹kèÞ&uGù:‰V)¤Ú¸‘p5¦l%ŒauˆFÖɱgŠª5zE;Ð[x<ÑFyRiŠù ‰"r"5d Ló0SLÏÒ O²í6ßE“Û¬–‹ˆDÝ8ÑÌ(Î箿{/‘–ìüoŠ“ª¡å¹`JõX¶é6L9XgƒæHÈŒ÷`3¶É‚Ä]* ‚¬Ù¶l(ÒÃOHçóƒËÆ)q)EäØEØ9¥^·)´Ýd‹ äª×ûM_ðHñŽó'Éñ$½KN”¤@Àâ¸}9¡ÀöBòÕ4d²a˜u54¹<Êš–ØÏ+qŠ):æ!^o[™ö-·¼Þ„Ë8nÙ;ô¬Ôv[&©:Àlx ^ éÞŠ9lUÿsñŠÄËUð™L°…Ë,ÀŠi"b0¯#L}zÐÝÉEý¢ƒ ÄO9Áõ·•©Éª¦t%”8޲ÁamŽœ›òd¥B ¬L¦Þ…âFAäa«™ñ:?+ìêæƒ(M`€žºÒΑŠ\DÇ©A]Î1S_[iy±VÕ¤˜’óò Ð-/?¢¸¶Òí]ŒŠÒ(f¿P€›ºxjÒ¬{Û9,B"-% iUe½ê¨5w‰‹·ÐcÂ$ÔÉÈïô`Ï@“'þeq×KÚ‰E‘TjÞvãj¤(³þJ5Þm„CWOÔM£ÃL.ñ~±õvJ™.†5@ô* !.P£]À°duÜ`¯g0Ì+ŽQUbÎÌqßd*™J £$Å ¹l‚½Í’:yô@j“žIsÐîFÀÓT®±tƒ¥SBܶ˜Îí¶ ­Ä¨¶Ë¦¸ <öæ²kªêkª%‚qàž„ÿ“'QÝJ|¨%°c 4˜!õ¹Éãš‚AXò[y¸×É›À»Òœ%^±‘™ÚÆCT´+Ð_üRw¡–™MZÌbC@/©4«t³mP3%`q‚#Óƒ) [_‡Ò~l¸S™±¾¸¥ Vcîíó.^ï•K®æˆ…Ò¾IÜ#™§h!Vð(Þ‚[Ú&YóT 9;ê ºîá®M#¤H[Âw„Ð,˜C:2èxP¼6”µ°3—˜’ãaס bJ1+YâÞK´;1¦@@Êlƒ"Ž©´H¢)Y'ð8¦É×Ù9‰È|ð ìÒ͉'±kN‰Oü;rÙÑËÅEN^üí‚#íBbcÎ#fÄbZ\ O€ÒDs3_‰ ɹyO ÛmÂÇÅwÀ«µ@ì‘„gy‹;ˆQvJÖ¶ýG#UJJõd“æ¸ë9W¼À’vÙà¼Ý=™Û-‘S¼#¯>§ôÀM=Hóóð¬µ$¤-Nh×V3oKéÖ¡&•EÏéˆ[I’È%Ï%^eìЃXð¡"Ï[´ q…K€õæŠÉ¦©˜6{Èi¹",”Jîcô„ v¾€™{r»á•:kÜÈoA¬Ñk€—àXKjL‘%¥ hГ¥Ãðp_JÓp3)ÖJsÙ&%øêˆXl»úEÝæ#,vñ´Û®zÁ›ï¦¸»„m6NpkˆÕx(­h‰„œ(ŽîܬBÒÄŒâÅž ÄÅ`T϶uÀä!j9ž´¥@,ü„iáŽ+SÒ}g»á@Ú<¨"Gø –&tw®[,õ¤Ôi+;hƒ‚ܶ¤ ,ꚬ‡ü©¤}² F i'9URîÆŒŒGÑ"ùײëÆr–]—œÌI;® K}¤÷±Úˆ`òödkѳùàÀ«Å ‚Ó5_âS Ffq<¢ü*Äò¾»˜V%&F>,*±èá|A±hN’p´Bª—GD‹²}¸‚)•wéâ=‰ËîúXÑŒ»³„»p–že"s Õd –¹ …aÝ-ùÖb¼ó¨)¨üA N¦Œ¦î20ôŠ•;KJJ4G“¤jÞ_Šb'Ï&²]ßb@à9aš:O¦ì ±ÆHšP/NˆI[€$Þ1hK‹Æ[-FéæÐšÒå ©¢-ºýH+,³}ÌúÄ` `∓¿'ú""c ¼I·Y1­(#ÐA¶y5t ˜u´£Ì&¤ôÄk—# Æ©›û¤Çè8x8ydîÙ¨ÜÝgùŸ¼qI~›yŤÁTû‡R6˜Î—,çNû¶Åc.váÎ@IãÀ­ÎA> ÊúÁ ±"O·x’PÄ9%H|E i >&y›$¾(ÖŸ´'¤š§÷¥¶òlØY:"Ê€G·Ø¦“\s4z ¼LL LKôòN?yBáÉÉM)›'—™t#’ OL<©Žà:Šõl4\bÿ)_÷ÔMG)Ë犕IoE=·I‘2Å`<¤ªõ%¥U$õŽ)ãèõï„´Ì<íÚYdˆóŠÕc j’pLƒø§;³ У@ïDOdgj@*H¬ î”X`Gs*±,qI-¡+k“ˇQÚõMO‚Ýh%E¹e!–ÀØêïZÓ7ŒaÀ ò0sœÀ{2AÐÓž‘F’°s­’r[ˆ[òâóAF‡lÔF.ðÆÝ¨òæ—‘³i²wÍ 55hx€ð3¬Âä¤ÎeÍ`ǨžCU<«Ä¹HËë!-Ž„¸.p+»Ã ‚ aä–ØM‚TÓS]íÌø£ªWc[ï¶GGÀ‡8„4/LäÙ–[q Ä¡dŽ;B°Bì¸PŠ7îÑT¾0eÍ'A³Å#É Ö0÷&Ìch÷S[ù°Ä9Nª‰KÜb´zeþSäÜT/çPM4qÒ‡R—âþ#OÌM‰+\t!©U¥]ÓØÙÄâ•e€§ AùTÂÞÛvÞr[$ºÐE”zªý.Gjñ™ê“Ôî&‚£'LDš¢]÷Ô‹äÛ!æ bÃŽÿ=ÿZ2:¿=rª×2`ù”®³ª+Õ81  ‡â©º 32­n!ÛJüæm§Ã¼¾­ …x&Ñ €ÝŸ¬Jy~0xœœ¨:ƒDm¾F: ‰¤À’·ÀÅTÃå@Oë`1uþêø÷Õ(T¯„ÆjÔÍ„žuñŒRN˱̭‹)R*“bG[vAc” );W<ñ|!Q°n)¥Zt¿¨#Ÿâ Üžy‹o =zUI¬žÇóè1Iôâ¬ß…]ÿNò¶¤,j7É)­ÖÀþ_Æ»E“±Ñc¾Tkò{I,·<ÓÄh'§µ‹]QœÒÞÿ²’éBìÊT/ÖŠºZ` ü\ ¤¤^7ñ•´;qSdà) Ùξ'éLI1CR¹¤…š…žNβSªgˆ¶˜tröÁ‡ñ. ààƒ´ùdzxÒ¡â–:v°`–MÄ=héJ;T޼pÇ•8}q´î*q¡xÙÏâõFO:`‘'y »rrˆ£ömsr7ƒ˜¦Fž,†uñ«q!Hå¸ .òÌÀëŠä.‹b â(&£lˆÛO@ Tç€ÆŽAVÛZfGãÖ˜`0$ðÄrq.JÛ¡Y”¢·¹¼Áæm¬é,»b>[¹ÈÅ3U%FFs~E‰S4K 5dn{Tà‚q[4\c',œ¢JpHÛXºr ‹ü\Qn±‡ª„)¢ æ¨Fv™·8pYû./™že*Ð믉F׿<Û4kÍjZÔ ÁYSÓṕى7Å@2¤×°“ÔL–Á¶ÍMR±“×Ïåè¢þ‘B@·É’÷(ž©¬*Z+ éÈÓ˜VöÑÒÀ»Ž.˦¸vÒT€Û[$oaSônZ )É€ Üz|º6!aü£W á F ygºÌº]¢íTˆýFŠI óÌÏ °‰Ô‘—…<…f×Ç­1G3ŠÈMåòðÌè( ³R;p 4ãÏJ. %¤F‰0Ë{²`¸Bñ©'”1^Ø–o_¤gÅ4OjGJl‘ Eø¶&#ûFi~v«ÔÏa A[ž{aJ?põ|`mÍåt2OdÈõ6?M˜­Ì¹ûŒÈCÑ ¦¯E6ĆRáTx€`qŠ7Ÿ¹¶7U¡È¢×4 2#‰lËóM‡­Stk¶Çƒ]ù¤¶"iF˜ˆ(Ѓ¡&Æ.À¿¨¸bPسíYR€2J–Fu#°c"‘Ùï‹äizvTA<ù¹þ4¥ë=Ô߬Þþ‹7‚'½`n—UÁ/ï)Þ‹Ö¥/LÀйÈ9€ä²ýlÖ;)8­AÕx¦6˜JÊ£Mò¤Ÿ(6û) ŽR„©B(y«a ¿¤ÙÄZ~[Çb»ÝrãDÃÄÝœ®jI;;‚òf(h1•7Ó¶Ø6®Cî,)ÝâA—þTRÞ †ˆ™{‡r-ì×QQpÉBe×6")¹­¹)óÑóQ À®7/žìëÅBÜýŽb×ol1Ú®ž× ¯t¡¤€_‰íÎ žv.z–ܽ¸;«e'?!%81î›c?厶¤åb‚Šyšîƒ³÷UÌjLô(Kà¶–*¿—™§1)ájBÐlˆÿ²<û–¤…ÇBR-Þ¹ÁYê[]v x½²]Cä^¤Ä_É1ÝYÃ@‘Å€Ô-Þ–LÜý’†¹¯‹›t(;Ðæ_’/†8¥ø [M‰dAçÄðŸr:Á¸‹¡]¸žÑw—‚Ý®Ë/³'hšæ»=Í(¨zÄ.ÊŠ]˜>h4}F ð\)Všƒ€QצïÑ! Í$oÿµ|*ÊEæ5`9„_<øÖM×´¦'‰àÑ[Þð°!n‹ÂŒ'V‰âÅ .ØYŸ¼ßŽüÿLÑy™ ’×r É 5çÏ­®Ž;·9q9u~_ËÊp0¨õÌ«A"4šî=…^59†¬D5+^ÿðãûš<{ؾBº•rb,íŸXøLÈy+:ö„L©J<ðþóó ÒCö‰’,yÍh…*²GAüDžø=à¹òÛ”W’8Â4!±€O„ßáãRä)'Ò¿<ÏÚEÙ3z<~ÜéG¿–æŒ~ìÀIPoƒßNóÊÛÎesú ›Ù2› „gŽ5¤®vDΜã|…@ÃÎýz>ˆ·&¿&rE Ç7‰'ž$zòœÎ“nÒðó:…Û™Ìe·[+šôÂâH+">bÐHe '3¹xÒ&Ž¢ûÖ¥a•\¨ž ÈánÏì_ˆk]ì?QzÞž©Û5é?–B†¸8<Γ`ìÄèÝ|ûj Óž£üŠ©w1hg×I‰»â3‡A/®Û¬w<àdê h*kS"5ÆWŠŸå£efŠW?jA¸bðu³P b®ˆÛ o‰»ŠqqÚ5•• q¸O5¹ìªì!ÎhEÉœDÚ^°xôܹ&«Å¡Á,ììIvQpäÓ.±C;+QRÍ#ˆPÆÛƇ Ë⃔#‚‡Ë“y’)oW¢—,޾¼X<‰3wêÜŽK%hcœ4¥ß2ŽÜ§»†Áè±HnÙ=0‰SZáäfj*‘Ø|Â`çêwF¤G» \¿U[äˆæ ,¾;»mµððP§˜´8‚è+YÜѦŸ ckèRÙ =Œ!MF@š‹\Uy–ãÐO½Ä½Ý1>–¹*A½Î2óeãñŒÁÔ”F–wÓMPóØÍõ奒.‰`B¯$ñ‹§·¸|E¤Á1¶Qg]¤$l ¸7P$Êi&‹¼jh‚òn§DñaÇ&*I‘b3F¤–pÖZûÓø¦ á,pªEPwÿÕéa'«¨MH s²ü;žŠReÂàúdBhÀ'ý³j¨í >ÚýÅ e4îåw~ÿ¯~n±OÅ÷Ï߯¼î?}¿ç¼_Éü.,¬E1IG÷ àýÕíyáýlPS{Ï€€Ðø#ÇÙ-ÃyË B¸eñ¾TçÔ4:¾ ò³W cP±¿þ›üU¦†W.üÎþ”90Fbl^Ðw6D¨´A°½®níû×cEM_§ ÿñJT°îvÊyÀÛÔ1˜2«L5Û’»ß|V…Þ7r¶Ù¨­IòºøGz úÍ¢Üþýï¼ËS½¹_¿Y6Ÿ?•Ï;ÛRiÿUULØV5õ<˜ü€lÛd©´ÕUÇ¥‡q’™Úöâ= ä=r"oèsòyCíƒqŽ3b¢vÁAjny{êYm7¢ Î)·O}}]Õ>ÙYcN–kj%4>ÒnälÖÀdÞp¶’{,³­h;÷ó¶ÊÛŠ‚ãFY°¼îñ°KÛ&B–ífËÿ}§Gõ>¼¡¸ÚŒ Ã*ò×ëž‘«ôyiï<¨ËÅa…´‚ #ìjÀ£Š JsÄÏ…Ÿ ÖQJÐPÚe–íÇŸçó:ÿŠêU›-"wÅä¡j0çôì^ fnЮÓ/ìTëóSZÍ]cH(ÏSPF骦 GÞ;3o¤Î{õRÿZÒLôü-ßÖ³(÷DÕ¶‘Kw‰!âCBß]êÇH•Òöé ýQG{JƒQogB¦6š§¢PÖä»Y3Ôu¿ûÛ¦¿máùì ž¢?Ú=™¬Ë÷ñVokþmß<™—øUxÿU–!`Xànèïo¼Ž´-‹y•/Þâ{>0PÞFÞChÏq^cÍÑù¾Z­NÖ¾´÷«Y*Ê­¼î³(Ç=Fâdëõ™œï¹ºîãºúãþ~à áýÛ€ ž²"kqornÌš1Û6·žè¯%ƒ4`ó¼ÛJ&俨õ@ÆV&Ë€ò:¿äcbR‚¨Vн|»…'$~r£øSNÂð:(Ñ`ö|Ön{µiQ‰g°Ý(Â8”gÜ/<¯Æi„fÖ+ãØ>›®(à͘Y·íj¨´_`Lœ{~´'×2¤ö+;8ÍgÒ¼’98¤¤Ë’êÑ”ågxâšÍé àKp‘:…Žâú^âÍz;úƒ˜”ÿò¹nwœPUââŒÇµì*_Z¶k°¡±H¡¿G# rôî9^ç¿ ¸BÒf"çÁà® lÒöØâ-“RÀâÎ&‰,1z|5YÚHí8R;*±¬Ï6{žäôéwˆôúJfÒ¶†ÚïG¤\Ôb?ì( )E'XÞmÏâb‚£•ïµ®­ë_Ø=¹K²]¬nz Qe7Q¾YùÍvãQºUi.ì(ŸCýh?Ìko 8N¯v)äc%]8gâj¹i‡oþnÛRFD¥Ü.~Õê=‡•{  ¯ýWZÎZœ›^ãîÁ©™<±{´U§5g †3Aùä»n÷¥¸4R ¸;‘ã© ~?×úÒ6±2⣗Ù½Tô{0 €Æò Ñ·M“ÂŽéqQÜ?AÚ~vÔOÜwÁhh4ÖörÙ>Æ¢ŒŽGŒÊFeó§£¶¨|öΡÐe/$)W Ó ƒ|Ѽ3$kCæ‚ɱ»ÆrS•Ï+)um8©ø˜€§ãaÚ­j|ÖàÓ ¥ôzF¿Èõžû —q³EûÍ`ROEҸ§•kãÙp÷Ë|¤Â— ® _/©Šõ=æƒþk?N¨ðطЇ†ˆ+qú+ŒÆ;©ïçÏ› ‡¤ ç¬èCeKñÆÀñzè|CLšD¯üß]Á¶À¶Äå± žQ3ÑWr])Ä æiAP$‘D¥˜¶¤§_õ#0¾ÄúÑ š´ñŒž>yML ´?M ¦)ªâ0œ Ŧ]=¯¹¡êÑÚÄ[jra­8ìdKÑŒÖP¹¹ÑõöÉH˜ ¬tŒÐÈÏ¥£ªÄ>ð•³ìnÛùq´±¡*/SêK.³<$ùNÄáû=î `§T]°ØÀ ¾ÎyϹø£ É·gÐ34jlåö/ ºÇÙ\F™ä6à1RYîQÝÁ@…ì•û ö'Rú¥zB–Kû«àä)ÓÄÄ[î™)8ìÓq¿xH  Ö}ðTMC¼g¦ö ô¾`°=/êq—f2´ÃòugÌ OEƒc¦Ó\#ÝK¨#°?‘sŠ'C‘Å~ÍðLnkR˜£¬û~¥[î3fö,ÿ©hÙß‹·­JZë!Jn‡BŒ /*²Yc$;¢täg»'bÛÚc—•”Bê¿ ~ò‚¡Ùµ"ô²ù³³N³«´~ŠßCšßH|Q)¹wr,7ÎÎÌõµý~ÕÕhæE 'j1d@úAȼµ®qúº- O ûÝ•å ž›¤cæÂŽÐºÐ¹kÂ(kÈC²äE·°8Ü‚fènZD7¼ÐÓ//ø¤ɬÿW£NC9ÉC»i‚Ùõ]m®z&ö¿ óÑó5Ðñmh7³v¾8 )ÿîj3Õg…œV7­x$x"÷q)Ũž¯Y ÕbEñˆ@A÷;0M¼Ê=é¼~.r”«§ûƒqãƒG‰î½[-tˆŸHÔJ=í÷芔üÁ,ž¤OJ”K%ÓSŒêHÞ ½BðÒ[ÛmÞX¸wæÉ?ç;jl«÷<Õ©ð;Âo·kø†ÁúÖ)<¾Ú ö› †fë¬ úÎÞÀÎ¥ºåFò£Û#©Èc¨ÝÔ4'ì}ߎ¤q¯› ¡§ó⑟÷)Ò¤Få™pÒ&ó=?‡v\•'A-›÷Ø*³Ñˆ)†õ¶Ñ‡˜>2¨Æ5œË?px}Úª4Ëþýç¯ûãßKè:à·ûCU´™uùØL±íʽ°kí9C`JL¹¿º*–6ÚL;!h°eÄíø$þà7T•ï.~ýÌ3ªÕužðUƪn¬¿ïɪE7¹³.×oPÏ>Û’D¾î´µq5Ǧ[{¿îuÈ‹å³~Úm©gu£¾*äI]|›Ä b²lÛS’O'qñƒ.ÕIÇ_`2ËæI÷Å)¹¿§/oàªw õaz¢-! ¾]¿âÄͼ[‚ü¤vïÖ ðX+‹à¡P©gN‘cÚTKs©O9V0ð{4l3¡ð,õüu7f(fÑRªœ1ûsyG˜¢j¼K’ xi«…ƒð| Îj²œßþôæG~¿áEÓ‰‹ÈÌTF¦›ñ¯‹ŽŠA¨¨? j[4öCݰ&À &‹"Gårllìöõ½Ââ84ãpÆœ¾lsÖ;'¤ÁçÊã×L€^éÒ€á ÃC¶ÅËêí¦’úÁ/P%10ŠÈ±29ùö Ï?1&]Jg¢·™ì‘#ú ÑÈÿÁHâ§JÛ½ÓLEE†%#A4sòˆ‰ÜÊ‘ÕEOúD\epi¨¹ã-ŸÀwÚÇО õQ]÷_¯VàX:juqvô`2I+¿Úa›¨¶ò¯–óÄQSuÝ_V™™ÐF^tö;VQxRwkxz¯2Ø•e.Ûœ\¥/o€Õ?&>L¿ÿú¦ ¨îе‡’ ÔNtç`lsq—Iƒå8ÿ Jš§Cààÿ–å¢k2fø.àü >v .–â@/ÿG–Perz!Ä—Å”,Š#Q&][’Þ_e…Ó!yêÏè%û»ÆÍ4NÕ±Ô)H Þæ•VÌ¡7ÈK2<æ(Œø3—ä÷hØù1Rÿê¶%‹²1ч9ãñ×Ò\ñ´t ºüG !¯6kö :À ýh@1hb1þ®¡•&Ðo¨»Úpˆ›l» Î6"¦Xúâ‡ð i6x½U˳ŠFLëóÀ¼-‘„ƒ+QHUD@/x,šíæwú'$xJç-zÊnô‚q‚2Ü</ _Ôõß´æm´,ƒüF" Ö¢Þ ƒ9¶Ñ¼U[’ý˜ïeºQ…‰êëZr4O¡y³ø £>Ó-ÀÆw°_Þâ§D¡‡ç¼ÍäÀã=¸b@ZXƒñü†ßtµ 䋦AC©[jî¼­ê¿|ðý T*×Ê„W&ÉôÓ‚œÀ£0@Òý×c”º¿q<)‡ÃZåÙœZ:VJ4èìGÓX–MS-§Nƒ] õ1Tê¼ó~› ²mUží•ÊgçycÉ=pÇl?öånm_͇~ßRŒî· Oøã‰Ðöï™ÿŽýþ Ž-µW$Súãþê/èþûÛ—¼™³©ýW¬F®uù:ÞË-ì$öÈ u+O] ó÷-¹ä”½½íóžÌ„KÐô6y½wÞ íëŽÚ¿¢%U.§bŸGxP‡ÊäŽNK"×n~¥Ïuðûóàæ²ãëNɋ퉿îW^÷ºzÃôæ6à7(4xñ…ßÞ‰4¾úõW>yEéòùö~qëáKòçØÍõyacŸß³19i¬[Pcn÷ *iÐW{r¿~©I¹^—÷Ykʦ$C Ö^8*’¯%õSB#t3ÔBŠÜ›¤`ñš¯ûÁ‰éxñsDNé|Aÿë%x³zèíÿÚDï·¿ïïn÷sÔ o¿^ÞR~CÎ/4à%÷7®·]]g׉¤àÌU/ ¡i§"™°o!pkïÒ§6)z-®±KÄÔ@â‰3 …æyÁ;ÄqûØåƒ(k{ÞœžÂ^A*¥2ãâ]g-¾;§l»@YüÅôt± ØåÔxTÄ26R™ªïÿ¢| PÌ =Ÿ†ZlgÕÜàŸßó~©3ÜK4¼B.pîú˜ïšÒ"n=¯'Š7´OY¬.x ŠÜåf»Ã‡Ãù;Õ­ñn¨ã­tþ¿_û>䇿U>…Nðã6Ž ûåZ ú0hÜn!ØgµŸ'5*?ŒkõýÕm… ážÉß©à#´!ãê{_7¥Ip4°í·ûR3 ˆI„?øÿp¸½ÿû(º>îÂ÷2þÁïçïÐ!µð8•o@Ï0QêPí°îZªÍª"V¬C%ÉÁ{íâÞòèå¸,sÐÛ|_M¦º`§ªªÝo¾µÞ » kÝÑj ­±:…á%[JäaÏ0›‹…§äà8?Pûº5ËÀh 3Ïnjûuk,~l‰³sß|}íôKt->ýÅ·ÐÜqšÙá¯óñæäÅ$.qâ_ïq äþ“·Mþ=Ì¡‘Žî÷Ÿ³YÓ–ßÉ3Ç=ĉî%‘ÆËsaa—„µ®Zøcz|Ì‹ ¬xÍë‹=ÒWt4#9HUwƒ=]°#ÜÐSŽ/~@È¿~~þñwã‘·‰þíÎxý®Š6–§õ#:Yx<=Z”Ѫa‘‚§ØÁ±ñ®[‘},uV2íÎFï‹ é¹R›È¥aàaCÌêÞ¶ÉpÑß„•@ætu!ï9éKr#"³¢‰lY:ÒæMʼnŠq{ÿå5ß»Æeí¡KÊ_‰B8R’í#=’Vclã=p"PI<]Œ÷i½áÜV’™±·Úþ8gÿO{2åjSÞír¢‘åÀv‡÷eÀõJ?½¾Áq Á8úîЄʹ?5ö=Eµk”6è('.7Üuq>÷¸i`Ý߆+hÊ·“T¹²çU襀1© =`Z'oÆÉ æuŸ¬fcåÁ¢°‰¶MZJô‡ øß rk Ý_`,‰6iº0fHšÞCz³kþ7ßOêè¢Ü`ƒ—Êu“¡©gfÊ#Õ¼ŽO,¡±Øk>úuJ÷Ý„8,xØšë­rÎ*ûj_[„)´¡Û0¿ù7•×}óš Á¸HÑ7-uÀÔÏK9ˆ'ã÷‚Ã!×ÝÖ[÷¦¹,åvãÚ¯zf)´GóÆ.õmÃ]ùø‹WËÓ>Õþ”;Â>ò“F6 ò:ŽË `Ïr°IiH.ö½„ª´·ª„ù¥~Ðó}ܾJeç©-­¢Ê?NÉÆ9LЧöÔ2P u„'Š4ú¹ÔUY/XòâêÚ˜îJ+O¾BsFeÀëiŒÞ¡ ¶`TPˆ6Ò¬:f;˜üöãö†ÛzCK½j'êñÒ¡”ʉž}ãõ¹çËk>tN£ µ€ç…ò] ¼¢Öfø8ÿë83Z¹ýúˆ.½1Yª²üSãšO •IFªuå³åu,Íâ!ÕOÈv×zàJ?>#…¼Ý Ä îÕÀª· $W@ ‰\iu…,&ŒË#¡®4ç¾¾Âm~§™Ž0j™uYºpY徇Œ.ƒáL0uœ3ž½êš-cµyÏoUƒ¥yÀvúc+ÎCÅxûj‚®“°P‡ðþHÅî»tÞÕ­üû-ƒóæË^m3" JÀØkG{QÝwa›ÈIu§ñ͵•ÙU(ÎÊz^¬ÝQ唺¥ª(ªíõ‹¯v,Eåhê vp×Pä`朖 ™ˆ(Ðg¸U¶Ñ¾ptciSŠèCÝË×ùËÍ¥¥³F3™&S/£õ™ ¸ÓMƒ,­¿úY‡Puc$øûÆ_µ‡/>O¥èhÈ•0‰ X`»ñ"„Í_e_ÜKåÅuíµz§‹]ð&“r°´Eów‰-R“)h,ù¤ bqÛ¦Zƒ¼tߪä༟Ñ=sÕj*¤þA¼ga@]¼_ÌÇhÉ«ææ6ç¦yÉ•F«Ú\L¶ÉŠ_x½}Aß]®Ç¢%ß)hhWÔ!£ËÅE)Ué„åû›âIµ‹†´ß¨â™Y–˜áKâʇêvj—òp ïw¹fÁI§_ZÉ,ª‚¾œ/Î%àøh/ Ÿƒ€C_¨²îЋŸàK{h¢€Äþ¤šbv3åð\8ˆûȧm´Åä ¢Á*²trriªúT¼¦f¸Ú;…Œ|ŸìøïþŽ£ö‹éë¤ÞsP"¯WLsjK›Mœaé™ã!)0©¹–ù]Fõ^¯¤SšËX€@ 7ghD7Xƒ°Ë½þâÇ/&ž”`§VuÑÊ—Õqg)ºë„Émo¶ J¶¬Øñ+àÁzNÈ®³®Ü(O*“›1êøAU,+pÐ&¦ë‘á@‡NN Ý2°k¾.·´cÁ¿ÿïwÎ¾é· YE=‹V6óþ¤÷`Z‡Ä†Î]´“,•yW_wì""'¶ÆË†uÎSgì’¼ÿ0ã­ÄäÁUÍ“¹c…z“_»÷ƒ]—CÒ#úh Y-{ÝepBòR»ø[+(7ý»:åñ›9í8œ0×ÙOrÉ”Gð°Þ©ž’zfÏ£ó);E]gêcà— yàû*­Ã_ƒîè„ëõñ¡›JÆKH½ÐUJ^Ð%ö^wªWz¸|q"û5“¤_|< ØÏÈWCÕŒY¿оTÊ¥2¤ÚAVÕçÒfk/œPy¿EPû1­0Šøž}%“‰rHÿ&±v„󙲰βh3+Tw¤Ô7í8Èœ÷Ÿr‡BôÁÔù€+ŠÑôÖÌlt¸Ò¢‹Ò@¤o^Ó´ù4*š™*ýÍ4¶ó‹}ý–±wÒØh‚Ëœìö|©•)Ûk_ê‘%óæ2’æs±6¥fK¦î´* ¤¿ªüdáz´›ÖM»—“F• Ñ81%ÕðýÁ¿Þá›A·œ^ò] …C· x)s׈m†›1æ/“ÒüÂeMÇYcQÿÎ8Egƒƒ«7³ç¿,SaIº~¿òïÿá^ RcANª]’h¿3ëû[ÿE“aÉ]é·jZ‘-íj®ÙVŽ&¤§xÊwpyõþ®ÞØŠé1Á½;—œ4̣؃7óïºËúŒ¯¶Ñu‘ÉÃøÝøá Ä’wÞŸÌfn}hŒÉ<8õÔ}á\~NþåÛŽüF£eæu¯ÛCšhÖÎÝ|©„µ ¹•-ª·ï¥¾ü S.ékÞíR`ð‚Ç2C9HÑ4W63LùzÀXE5°™\Ü‚ÁDÙ§rsE')5ó}Çab$ë=²Œ$ÂÝ+:o8æægP0—Q½ç¶EõnÙmîÕZp|)rL…U) ð2«9ä]à8§<,•q× A˜²Â •¿6æFU™_ûoä—U))¸¤hš¸œôb! ù¶ã6¼ ×ü|Ýñ‘¨»xãõó/ð©z}ÝóVSXàëÇGÅï`¶èyC§-°Ñ0Þ›å¨ÛÑP $Á7?`é Ùâ ©‹¨rûÌ®!UÒG‹·“!Ó‡.E´Qe["ZÚhaD÷‡8؆]·WØÕÐCJØ£4}ëÐ!(LÃ}Óß›ûTت÷ó*eTú"ÒlèT‹öd«þffTe³ÙWĶ?µÕ¸Èä¶ ª°SÞê›\¯Ê8ô2~óÁó[9gÍ[-üÐ Cì§TïàôíE0 Þ‚3.tÖ3[U³ô7Ç RÈ!Û ¸º½¿Ut´MôfÕËqS÷_ß³˜)˜-àó¹êÚQçPï“ÚžwÛ¿/ÞÝrò~Á Ž€b]Ã\À3‘Z¨8½ø7ßçˆN'LøÇ|_ýM„•|)ý½UõâºýtÙé\7ê#a[GvKBÀFü("ñÍ›„cÚîÒ«m-WÂNÎIáø  ­û[š >f{G-è˜ÊêÚ¸#³"ïj˜ë‘ ç¾…õ¡÷öy/]\˜^ê²çlÆÕÇëð /*'OAÉÍ.51ž¡øð`þTH“'èçÝý­$¼‰ŽŽ™¨í2:hÛ8—&.Ÿöwà|ÅÛèVׯÀÍŠ¾¡ÃHÇÕ²“‘˜ Wöa¡ §|ëÚJfáÿ½öƒUrN¼p¸¶eVoN$0Ëð­ŠY…'*Žrû Ô5ºË’û¿Çðƒoá‹õ7CQòÔA]—£#âËjê^Å×ÍJºOhº}3º¹Æhï,¥R·Î¢Nbdu±FÙ{g Ò(ÝÐùzÔ%:Ñ4/[ÖþS³½SÙжgçy?rSnºK¹oª_SÏk”ÇÁc_6R´.²Û”û™ÃÝ‹Òf–©ú¡5/†ÅOª¶f™@ñz_fÆ­J ä±èœ(’4÷ô€¹1Í¡ä&Þ:ëFwž÷^o¡zÝyÁ¿Üs{ÞPôËxèe '×7-`çè¤C>\ò0Úß ÁD`•£ª1,_Ô'PNñw+·“¬â((¼œhÎð±+à\»Ò<0œÓYŠ/Ëw±ÈÁÊíß /àÙyššVê¡©žËâoDÞ–p¨8Zu"ùÞscëšÚ;'BO˜4׺»³ÈkXN‹q·éÓá#.Òº89ˆÎŠÊ[–ˆ1×C¥¸£8ĈÞâZ¸hB ºa»>϶ßMÞ].O_×Õ­ª0$;…Rq$Ð.Tá([˜^AËC=Uf@òú¿ã8葳 Ä€ÔoÄe0zNøýãRò¯4âO9)þ¦ákÿãß÷ü̾àgoU{‹ª¬˜g6}ÒNÇÉ`– ææ4÷•£Ñù fÑÄåÔ? Ëeªlù‚Ǥ‹­ ì2Y‰ rŽÿ=¡#'€nÎr†˜¶ì°|H_Tâ¦N²F8Ôªž;Óèhêäº}.ô›ƒ”Ƚr8_û×,ùúYŽ dTé×,ñã;¬°vZÙÿšŒ5½ÍŒðH±ÛÕ©R£EX…¶ œ²kèuñRÜâG{V… ýúÒ În¨jÇæ1XÀ“Á">¡«)H(\ÌtÜVøMs–£Wš¿Ôp.lãr_p4òP]ËÍ|èùè²Â°”…ÌM%µæ ¤\´VƒÝÅ>}3í,Ðzv^Jó2?2À•éÔŠ3]¸»º8doiu~“=>¾þ¾®Oµþõ÷VNÉ †ÒˆŒíTÖ3zˆÓ! ; ,[cÞ­ F¸äoé!GÉSóiÐ8IÈÓÒPÍÐE\ÑQe\Q\ÜGDñ'Ь¶º‘™?æx`)̨j†Ê·{ŠˆXâ¦j Çlš:‘É£­Ogáÿð+Z@£Ç«0 Ê5Ëù˜!ab2†è,]8`X$’̃ü¢‘w’œXóêõŒ &ØÈv"@ÁsÒ®óVò£¥NÅsEµä\vK] -”HŽ<åÑð†òæË[Houx5–×ešH—%}¨ òÕØÛ—)Þm/V݉÷5+‹L‰ˆ—~8šË «Y·Öhuô2Žp>Àá–ÚIr¿Iw.%üÒé¤9Bð)@s¿£20…M”ÀóòWäÆcŽ~ª•j–<9íNŠMŒÔq–#oLœ J B¦9NJ¨ëííÓ· ŠCZŽŸ‡I¨ƒv i(èçRÐ µ§¼¡ÃxÓµÙž,,úƒY§Bø·ÎZ´6%üŒF%1÷ñj]Žkä1ªê·ÒnÿGíŠxzk¸ÐœË¢b¤®“@«°ñbv;ߺr™ºÏSo;½ª¬ËÍ>lcû65f'ŸçLT¬=Ü*WßwþÑ„®7‚^úæÕ®¤6_‚ó-½ÜGÁY¥ó>õ8§à‡aQ€%.Àž’qXÒßdþ4ôgf,s4?£@Ç“¦¼MŠÃŠÊÃ\¢:¡°æÞûgÕúGE™HJ÷ôÅÀöyU}¢oo¡¨Z)RÊÚ‘=hU’®,÷¦éL…É-¢ÞN£×„x9A.–Bo=í!Â|Ρ‘ ?§zY:ÏËò–™¹Ôüô~õ:Þ6WMúU§Zº¯xí Õ¶×';GÝ^5ºð’Ì?`jë#ïG5NRc™-­¦“š˜­Én[ä/ï|+²åʼn,T¹Q!.2~Ï©ªKÌðlôªSgÔüÔ–R®S¶í‹·€>*GytË~ÿ‡•&Í€ÒljÕš¿+fºVäþ6s/‹5‚äUmÎÝ›“¡_³×õ¦Ÿüºð–:³•‹NüTžƒ€t˜ÖDîÉ*ú•²ZùŽ.UTk5 ¢äz*€/v›Ä©`Qèöé0Šú–¥jÇ0T†&Àp¸ŠêòïTî9Chv=œà ïé¼KA!<þíW}=œby·i¢å¢½½<ÃaÊtÞä“GÃüe¨°ŸÙS}:©ÑË:Äób*š±Ùȋ®÷ÁB»L ¨Þ‡M€¢©ãÕ5fhgöÇg½ø´PÑÚ©Öö†âPGÁU2ä‚u¹AhTw1—ÖE)¯Ó¬±?°àm¬0¤ß0ô=ºR ÏÉnÍqEo Li3æ¨ã´òÙ œåf#YÞP¿>Þóù£WƒFù{t¬0gù1S°ôjœþ¤P†®$=_J^9TG7Ù›òW-¼u)«îÞ ®’K½LË鄕ã|·”…?™ÜRÕ—j²óÂÉo—žpZ‡þ ^²×êdNXÅ€·Y£°u‘ÁÌ—Bm€€qk˜¾@> Ó…–§ìw-ܳ@•ÀªVbñ¾iù3-².âN\:LªÚo!Wu^‡ú€&î 0Zó€Ѳ;j K^ˆ¦â4ICV‹Z;›àÚådIJ`ä_ÚÓÚϾõ™Žcƒ_óZÎŒ\0‚„–ÖW®|ñßT{HY<'÷)”ŠaiQiÝy : h²’o• ÆózóTUíÔÊD&öµ UÖX7qA–vzßÉ÷h,Y€–7Û>‚ÇÜÈ0<t8oÅö h½šª%Í:ÿùL£sv†^³ÌŸä¤‚MB->Ä¡qu¾¾fJ®FËЀ…ãqsÈeµ‡À†DS%¯‘/œÔ Lgíz¥e°ÔàEÇçe‰Fw¤÷œŠ¥FKR•)ÓĦ¤U•;]0К¤uiMóà¥;LºÖ=¼¥H¤´9i ‰ñâ-ï7 >—‡â66R{ꣅ5B–Œ@]øT4~‰WQùÓïÙ#yÏguyùWyL£#‰n¶² 8=ѧX^/£ {ò‚¼æ¨cq^iÖáî˜z  KN³T•i^èšßéìóº FrÔ™Ûë)IÑ‚©W Ü—†ùiPÆ]‹3Ý k~µ½W¸ -±Øg›t]í(»¢W£ÃèT™R#R#W×r\]ž?1&K—œإÀ§v5¸¦áhv†^\3±D–jå«Û--$Ô-Ü®úÈ ˜÷2ŸªÅ¯i9víµ\(®âºNÌ¥f»ù¥ÆÓ–û &€C¡Ö4ƒ! DLö’ húŽ#Oöå¥ìmz:ã9¨:ô‰Eí-æÓÃBìÊ\ü4©SFËO5¬M|ÂvðöÑZŸ¾!&¥|h—4¼‚‚²¨¹E5Ö*Oîż&U`ï•‚U˜ÝÿýƒÂ(· Jâd¼a XÄêœÒEåMR½øÜ:¹ïÃÅÍERJå£|\WSi‰ŒÒ-þ¼ËÛ$a¢äFÑÎÁ`üƒ+í*v ‡ õ8ǺõîJø.7|  a­ê·(Çu|z€5qÖÒyÒÈEñÕèœêÍ»4Ugi^̾¼”t€øF¤ ñÔu¶-#gíPå†àˆ©Zå;ôû‘T±ð-[n¡ÐšŽ½nækΞ¹nÓ Š<‘`ù3„|J2]!ô§ÂµÌ.•9$2á´ª–hqÑÐlQÓ©(¿í gü@w\Q³ÜÌ›ýàôqO^Ö–)G”³Í)«jnThv—M¨Mû?Y\¼tp†œ¦ÐQùHŒ1¶ºÁfÖ*Ž3´-ã·R¹~‰2Åm‹®9Yt¸çl »ÄLtù#oOœdað?þc¿±Ë7–û­ú§èç*Ž``iZÁXä ÿâ±adO ßz´tßirùg ¦²3FÕÈ@2§fÕðƾbÙTÄU†ìC}°âêÛ/§ Ø.–Z „FöFÀŠsS˪`_L ;a×<* jVÐe5$Œö‡¿OByF(_ܸVÌÌU¢²–ø€,æS åÆrI'ÏŒP‰³¹pyò‡&0Ë£ªT½(lT)§òi¬'xÝÂ]û¾ô¸¯cöD›†ùPç Yа®y32Ðô‘<{5çA­ÙúPù2ÅH&aíþô^í} ì²×uÄÎz¡ii•»W\»5d÷º5/hî8±ÍWѨ>ŠÖ^0Ãô¯×,øx*|H÷Bv÷%‡Y„…É'\sy+±™*Œ-½î‘C¿rUëYÜâ†â1dÔrB¿(Û¹°—¯·ü+AsÙþL*ÚÚì,ÒÚú:íl.’ÿ5›]/_Ø«C?^œG ¬0€ñ$ØÃQÖ°LxæoÑhç¾ó˜×LU×x¿veä=:_ï^0wæŽ@È’¶þn¼rÜ«ý„{ú3îlè‰RêÉ<¡¤Úñà¦Låéu~u"åP÷#uV4jn´°UEsS1['×Lɘú2ßUç>©;´s¢ídǶÿ§Øà ¼¹C·wš½ÆB#bÖû¼µh9T;òN5SâØ‘3ôR){·Ê÷K1Ðõ“ø‚ÑóäÕ¶Á‡¿P89ØfþÉ €aw)¥áçVî`/ÔüO`Å„8> ¸‘Ùž)€¸ÕXHù#¹W¯Çý”â<œ:{¨IÀ?Ë€¯?Ñùv%·¤’ÈÊ-dÚ–„ÒÂù–è2ÁTª(„baÎËûŠ#>ØÐ®•ªí°;–pp '—Ú »(ÔYH䕯$·þ®Ãݹ[EJ_ß®½Ø²v4º¨ð!¤Û‚PTOnâÅ*×Ó¸-›¦Ç›Û-$zbÆÚÅ1ö™Ø+-ä LN[—we¬èmZÞ|ªóCÒÐ&¢‚Cúï áî¢^é§9»‚—ÿU¡ž'3¹' ÄQë^t`JÞó_—­|ér~æDɹæ.ÝÃ诽'û¥’È4K(èããÍø«€¸B«u¹›¶mPðÞ7^‘øG8S”¨¯,Ž{弊VŒ±Ž¾däõŇ|Ø|MË=µÎøâR¨‘l˜}zíºÊ“9"÷Ըݨâ à †ªÿÇ—*NÃÑ_ýöœÕ•ò¾© ‹×Õ©«T¡SsßdD¶°À”CÀy„0ËK·sVèÅUÁÆ6˜$"ß ½ÚkF£›õ»ÍÁÑÅýðì˜òè“q®ªº@´×ufà­9­œn4÷á¿ý‡}Ѿ©ÞõwaÓ«:Rü÷íìÍÆEïsôÚéCúT>%"Nì´¹aLt²¾çÒKP 0ÀžF„¥Ž 2©#ë™JhÆÂ±§9ûu[ÎEBá4%ºÔÃõÈ—#ÓU5r•Ûµ¢–E.ÏÅŧiÙn#³[ùö2û§ìq{2ê?n7“BajL÷½sêhUÔ·g¤:ÎY×í²ñø î.^éåÙÇséiÒE| ·6®$ÒNüƒ^xX'´ØEh®IÀãyrpF&èèa§@ÄP¢nq)|.±.”JêepX ¥A@¾öÁ«·ºxõRgÕyëiˆº\aº0Rï¯+³÷ín^åÓÙ›fé g¦RÂñ`@Zí··âÁ ‡EH²û-Y ÿ “ò©•5x+q!Qx}«)l,‘Î(à¦ôhŽØöì.ÕÅMÞ¯7Žö¥¤2A°·úº7õSI°sù¹9šº¥¤\ÄI4zš’ׂŒ ".ß»™ÚÇí«Z]ÄúÇòuBÂ)à„¬DÙF†]1>ÀÔóŸÝ÷»É4z«¹©€KQÜÏ*6°T틟³ï{(¾½‘å‡%2q~{ƒòí‡bÉ}é¿*±çÙf6¸W\ Ÿž5–õïBTËL™%€…{U*Öña–‚³éÜ+­½‚ÿÃ?Æ0;Ÿ ¥NLŒËÔ–  ^—of…¾AµYRÄ׬qîNÙ/S¶%-”jYës¿ë?7Aœ~ e Qø“«daØïÅ«x›ü)Ìdr²..ðA«ï~ËBäH’¾7¿,ÿxtpË<"ÆOÕ'úÊÊUÉÙeÓ1{ÊÀD–•U2ØC.¢Ž`¡kn2†¥}™ðlùˆNµæHT]ßvGíç\)ƒiE#‡^Òjßé§ÙÌú«1NG Gáú¾Š“ÁN’*F…›Zº.-ÙNÅÜȼqKšrˆ S­Þ¥Ä ºÔÒ-®[ŠßR›T š^H¾`N*ïKa.¡ÏbšŠ½«‰ ŽŠAŠx †WDÍ2%ÂyôX‘|°riP ºe­ÖÎò-Ú:øÉŸÚõv­uØ8y‚ÂzÝoÀÆz*Ì­çÖK‡ÂuÝB[~ŸA–®#e¸ˆ#gRÊøˆ…] »1ú»Ú:ã‡ÙYï„øênü™æòj…;˜{­/Ù-ˆ©S8sxh&M-æÄRÉF#x¤,-M¼‰6Ë-èÄ&ªžš2Ãk-mM„í&Že»‘wa¥#ïÐk¬Ö>xi`©Å…RQ³G ×D7ÂÈb!LÄãSÏÊ…Ci½¬qeOëKR—2jJêBŒ?‰¿è‘áì™iBäIkáeØÃ說ãÇ'9i¡|Í"8È8¥Ô/(µèøeS–Z=¢Yü…Ÿñq6ÙÚgºfát€)‹g ¬>a”ÈP¹qZwæÀU´˜æ¬ÜA«©±¨±4çª/}{—@¾p›–†¦þU'ª´v6E-aæÁæÓJžE!ÞŠ*xÎÐé«0Ó[¥†e6†}¤I=lY"x‡A[p´™08kÝgó#Ð hQb¤ Mº Ò ­Íî­kC5Ä)•‹ø?L ,.Ï&djMž$˜v€êT[dãØ\€zmÜ‚‚ëÜégqÍ´Ÿ¢RaÈFg!#ì²ÿ*-fˆ—Dï~Œ»íbüjÞ.ž]¶Å#ME]Öåüã[©®ž|›¤Á6dbPºf‚vækÒ$ü4|F¦»OÓKÖÒÍeiÈzôtZ’ð­„A gÄ×H£"?º3zE&¬Yy~âC_¼«‚OdÅXûŒl^Ç{V1Õ@µM{ºýSJìÒê¡j抦ÝÉdIÂä¨+k̰ѷ’&0ò>ho—Ôi±g¬ÀXgN7Wj[£òØÞYµãÅ! ªE"¾»ì\ª£`·ùÁƒqTëqE¬í¢‰ª*ß{Ùâ‡Y`Í ÞÖªžB Àì~Myšuì¤A”ꃬ{ÀÂ[¿¼véÏ“³°nÆi…½ú¹ðÈGd¨ÔøL@jÿˆi›Rø`•NU²Þ*³Íz ŒeOÐû›hC"( ú¼Ù 3Ü^i…,»†Ttö¤hvo>…ñùÇ „sëÚ2‹rh•%°iMÝËLWÍ7|(Ö<œ@½ ^ðBsÝÇRÇmâ‰. Z†âÐ7…&©”+­2™†UŠº[d"(G«ECxˆ ¯ÃÔ­ƒ'á\L¹ëL݃ GÓ´E«âWfP™\1à9é†dü‰OTZ6UÁ{OÐ~…‡‹³‡¡5yà(¾YYÀñ–âh-ÙÝÚûk¤Î%’e™*Éeë]èÓS…Ú{°=y/y[1,(Öåó+dEB—ʹ‹†dkߢJ¾š:2ªþÅÓ[кV¨Œ /X3 d•u.š¤rÜu‚Bp6P»MÔ¨ä«û‘ߢ÷æà^ð>::é6/€ÎôC:ìšÄP bz´Ôì[˜~c%ÚÑŸB!‘}(ÌX‹º»¥;píPoSG EIäÅí1çâ‡zw'›²_(rÄóyÕŽõt§Ý.+Q'ôÈ^Jš´ÞbE-¥ÍfÒÐM.ež»?ryÛ…^g/éˆFysén»²½2qŠŠ‘Üé .µði1ÝÞ+Ä|eШB–øA^QçþÌ´÷O·¤]õ¼anj2Þm#hU ({ÅW¼¥àêJ]j®IÁË+CŠÇRuñ³©‹/y•[rý.pnèò"Ssc| ýt/Æ3…s &,w–¼¶ÕªË<éf³'-Y. `ÔŠ¾¤âz TX²R—6ªV;á€EûÇž©4tË—K‘HÝ1L±¨9kVŸ˜òªU±pgmóŠ*ÃÂ(]¡1Ë-÷:ÑÙKCšqn•~ÕýD*LMY‡üìèZ˦é‰û¥’\ŒÖ‡øª¯}ó5›`"Îâðý110_õ4Î+Aî‘æ´>‘Ï£p¸˧€eQ9ˆ×îõÜì°#=d‚Nô<N(5-Œ[šɼkt¥Â+¹.ÒùÕ=§x­XF¤AÞ^ó4a6…åGVµÑÀá J–Ù!uøIŸ~ªe`ãÕ•™¼(9}I+7ûóƒzɹÞ\â5¸H—IËîV¨§Ëà\ïùâ~i‡ù–¤Aå.–î,"+¾Õ9I­ûÑÛŸ®+¬d†§4&[˜6-â=WW{—' ñÏv›·i4ñ¡›S{*÷U‡‹«uoáWHœ]Õ?ަœR/°SáXìö1W× dØX7s¥? ÊÍJ:£WŸP ½QÇÙ ¿Òð“¶ðƒTï÷ÂÛ³Rß×ÄagAÔ‘8fÜ]{ö´¸Å&Å7®$‘N°àÜ4Ô4Eצ~ðbÒ­„½üKᔾo­ZY¡Júá!àR–SFtJño^Ú²f1s‘¥ŽÅ©8Oë[ôWOg:GJ-jU¼8R Mr“qGã=w$¾€éàs¤ E†ÓO}kºáË Ò´…]ï[R-¼™ûP8ˆ c“¦ãRBåA7­}ËÃlBÅ,º#Ýòf¤7ÛÚøÛZc£9¸Ú­ŽfÍãÃnųÚUHñQ¡´5ìTÇ5=úMk˜rj:] is›%ø%YLJê’:‚¾úgù É—B,‡U'¢cO†áÞ`.d–¸/ÉÀ–d¨{/…e‡aõÐ~vaЋ1_Û[.™ðb"å=X×Ð;ãõ‡Ní €.þ"#ÞB|µ<¯jrîn)FF„÷§¬_™>NËwØÕ[<׬2!â"¼€ì9 ±Üùͦ ßN ““JªêŒÊ­~¿:^âègá8œNE×;fêžTÉâ?épCS ƒ.mÞE `ßAhÆVEÛ»¨†µ×Ùhý,HIõ•¢ã!cN¿$»»ªŸh/df'–õ}r¦¸ÇbÓi‘ <“77n“¯ÑäH£ÒôŒˆ·ä« „öõæÂ-úäúEÅÄÊ$Ä$ø¢®6úí13¡Ì49œiî¤.øž·¶öi()åÇF«¤D`€K°¸ûÌi°«¤ëœ!qH¶hG"BYžKk8Ì—-e„ôL"âB•®0äÛ‰ÁŽB#«Ð¹*˜ ¡ /ÙVO„_»ê‰¬ óíÄ,Ÿ #U‚J-ñ`Ó;o €ây8‹’:a(_[1Û³mIŸl/RE &=«÷ø¡Öü$•øïþ«^öжÜJ„£«gáòÆÎÑB*Rið†NXuà¤H3R?´zîÏ=“Üè<ÈÂjDÿ*ÿ4 ÇuOŸ{áúýùÍæÊéO]D>ˆ^Üzíyä`ï(¹È2“Û _xhZˆ÷{ÁɃ9lÚÎGÎeóÿO —û*œÀQ0‡ž›ŠKݰ"AŒ¢òŸðYÏ@埥üCÿ¯²ùKB8Íö IH .K®ý©É±•™·zñÝuÿ™ˆ ]•>p@’m«8ȸaˆŒ4Ì“v¨ôà¡¿«LÉ«i£ €Äæ½½™J¼{÷ö6Dôap ª~èw¯Ù½pkbÄq°ðW®èbj¶ÛñçÌþ/¿mÑ*m^`)=žï‡»z@]+]¶^Ḃ¤·%OæCã¯h4g2›kØÙ‡;”îA{4XF—a·¯›ü.ö·oÁË•Ø5)0V¾¾12zá Hm‡·º¯îÇó¥úJæn†ÕÆáŸ‰#ùÊ˲®2ˆ:1U…+\~þê‚}.Ó.>†¬ØÚ:‰ÒZæ(ñÓ¡ºaßTFtX9NW¾¢,tl'^¾§â%†}€êHres¡¨wÄÔ¶Hâ •T—°Y[{¾[ã,aÉ…#D\‰BçXÒï?dê)_ñÒá¥þåè” ñ­6Âg´ÿé?¯~áþ^Ð{GM`O2IôÀ@¬äJG®ªf<`å½-ð—U´}ãO ž )ÿwx¡Ûõ§¡ŽA̋퀷Hdf?Éáî\çé!âþð»–W/…dÝ÷²CÙÝŸ- {»Ë“›ëÖÁc„À=©#»A.ËxT~•ÎI-ÿz°§Ê 'GdAŠ––+]“æ(Üò_ÇPµÇ[’¿¶QÉáü‹ø€XƒBãÕÔØÑÅ ?|ßz{ §:ŒA©ƒõø¡éåØû£¡ wkkà6šVThÖEñ2úö¥~®Ì,>öÙk \¸lëh]Ƚ©‹ +#å•ažwߨrAŸ¹:å asÓ)­7àÕ=]V^µ>{+óøËçtå–Rj[Z„ ©ewÅ „Ø# ÙèIæ/ &ÎBò«ßhŽŽô:׊ òYí{{Çq²•”øFWÞB¡I eÚ0H5º®WHV…FÝ¡ôWÏJ‡rñQýð™ðÆêQ(2±~¨‚]d^P D»7Œ£ÕQ‹sD›ÔðêÜ^¬”Ue1„XWÕtñFV:Ÿ5qF¤Å–¡SØÍÖ›¾¥¨Ù&­© Õ…¹œ \ôª>€ÞÒæó*/J(¸›à±À¼%Û8ß0A  Q#uŠÏ´ßÿöŸœ®žh……^.ÚFл7)rØÒ¸H'åtÁ?í~¹mü~¹ñæs!XÂvøõ¶õOüˇD‹?ãßÿ ãO^ùOŽ6Ï®®%q"òƒë¦Ó"Á¤! ÂknC4« OÆåä$éàmöyû”±:B˜6¢ÐϬNëL[¹@p{ÐXuÂÀ²ûïG‡93²„àˆ™ØooØ¡YAW3uµc® 4æ÷·¶Ûóüª§(/Dÿ‹ªÊ`áQzg>ÛóBÒr^VOyJ÷~SÙ´±X‘ZsÇãŒQDó¼ïfUUÍ[™åé.%”FÓƒ~Ÿ³ëPqÈ’Þ9á÷+ư÷­üŒð ˜;Ò'„?cÜÒVÌá^6ˆðsF{™½‹B«òð$]¬Ùb{ÿUŽ­mGî_ƒ\Š)² ÉSàWY“D ÖÞ‰S‰"ˆy©ç«ê\´zÕ^l*vóéÅDœÂ™aC$#¼LÛ 2Åê&ñWÖ<­±dŽòž<¾’XSOeõ¢‰ú2˜Àµ=b ÊT òf®Î‹­Ü¥ÊµL•‚Jin­rÅ¿þžÿu£VT>â`˜™”’üûè—ý›ó^Ž»#ß2ÄU8Â@I·6âVÏ¡S´ÛL÷cœí+ô5]æ@”M;øãz ô ÐÍ…OÌStM?©ñóÜŒˆ]*áo$æuËéÔù)™szÌA|úÎííäÐÒ(ÓlI´FC"&‘ú•ø×dªµË"Œ┟$Ü…^BÞéè^Ö®{2EaçO°Ad;›2ð „`®‚02µÊ*Z1§¢, (™%5Ûígäÿ.âtÑÝUTõÜ)©,‰9uxwö$Cr¨žQQìI·•üV:Ð]Q•ûA¶õspÿ<É>Šá™ÕJªX<”´œ¶$XËšØ^µ^r£ŠQ=É ÅÞ³k|,3MR¥¤Ðù'u0ë³³(Í^Û§êÙ;e^°D´VñJ=’ÂÉâ L –%nó˜Tá.ÀôWxö©öçuÍúÓy0ð“>èUIþ+ì&}HYûŸßÚ“å‰õvÉ{ˆ?7«ONÀB#ׯ5dÚꕉ¼Û&v (7!O ¥…в7« ÿ½äRe ¤¤·ªª ®BQû•Ì\ûì©6GÛ†8üŸ–*0š¤˜ {Z t·† Èh)ñ¯ [˜…EA5|ÍÌ ¡ßTœÑÁDêG%±„¹$Á2(T­ 4ú*ƒ¡1x‰kñŸþ9T“nÿþ¨S iVþV?ŠêMÕU²uÁã÷¯ù˜ ¼ì¿7flOÀàç< €¬¶ ÃýOåþŒhŽ¢|Ã\ÿúìŽ_z·4[¤ä4‡ ææ9!äafà4+‡pM=ƒigÕ¼1þUÀjÛ+“YÆÈe^5NöºtËJ £Ãs ­hÕ•Ó·‹þWqÕž›Ä×ã§_­,NT•´@Ovî"i¤kY®yÞÚö¦)öÐ¥*M÷{)¾K?wµ²Í—¢¤_3@Hr¼Ñ±Ò"«ªÓANÑÇ3Ojð,–Êž#68pË9¿ÙÔ–®œs/Š>$u„Cr[öZ#J~ÏÌëdµ5áÝ!L òâ¥r©6F•ö3¥BKëc^8¢D`Çñ€)Ép0$V˜UT`¶H³iV¥.ÿÒ—WD7ðR˜Üò6 ƒ ìPæ«*/T2p•Qÿó|¹¸W­1z ü1ðo¶ðOÑŸž¼ª±ˆL©ì/ÉÒ\0ãH¡ë„!ªbÇ“Ëô¤ ðúÑwlÇTuÇç,„_T1¥Ä·Bt)¦Û%(ZöÚÕF[ÍJS¾"ÕÕ i2ÆÁCjĘS5¶”žbdYºÙJRŽœÏS¸¤]Ý1sõ¾ÔUý´vZHeH—E}gôççÿøÏsÇÓ…è¿WŸ€œªp˜ûФô©Ç›¹xòÚeêŸ0~6ãóÐGÿe·þ9K!z`¯YñPüdËþåtÛëýÂl'HCNáÈgà9bëqþ¦ø·Š—ž…µ?+“ÇKOÖmαBœZä{A0h,sá9HI2Hù»¾p’ò«jOˆú;?l¼:ôüQ1yšaüºå8‡h=WT-ôÊvT·ôð´p8ëíUqËê³°µºUAþdºÐ-bêrl]*œ¨w«æ+7ŠmQÎ_ï°îÞ| ‰(¡øëÚ—.kxXI²éEŒ^o‚g¦ø·÷–X2ëj˜ãWNS|â}¢ Á/YoÞÀ\OàP/¾¹ŸœV=s¯¦ß#Ëû2ò_× ü°Ðà‘ʓˈsA½üÈŽÔ‡gЯáM’ sx}ù”»*ÜOÕ¬ÁžHÊí[ôGœà2÷k£¹7r+·RN‹‘K Ms.ëS'ðŸÿyV14Sùu9IÅpeÖšA¥]hÅÏ ý+ønwâ¤!ª+1oŒò~;«úÈ&Fjçàߤ5N³è|0¿Êüì§òÛODíö0Kf/¾²3½‘"=š1)·-]œF3ÏçÒ©ÃXMôù3ÝírQ^{ËVc—oö¶Ù•6õÑ¿Ëí™ìéç/Ó&àeK)JC¯©MBt¤¿¨Ž*’ú,\:ÒD»t›·«é—ÑZiý¹ë[åä2V*Q7cr³n¹\lÑÄââlÅk©73§ÓO]ˆÕ–¦†ºäë3ŸÇÍÕ1΄èµI#:¼+“PUuišó0o.¯­˜2,Tuÿêîh  ¨éu¨óÖ?Û ªà;Á¿E»6ä‰ÿ·ø—÷ù7þ÷çKŒ¢æVî׆7уVÿýWxâ?33‡Š¦À[í5õæe+Éép“[Þ|p¶ð v.•! ð0òí@yc§K±µÓÎ^õ¸‘ZLbÙ³ç57*ÓO°]ëKú?ãê÷Ž‘·>›à=?*ë#Òè <‚r47€†4¨êŸÃ %S™¤ŽpnDò¨›WÀ¥ú×<”ðFô—PüY2fŽõ&6qî„ù(BñÂÍB+¥a î2§æ#š¦7 *¨Ž{×™~MlW}9¼f‚J©8Fúª÷ ÌJû³8€–³ 8ŽŸW‚}>AÐIr‘zÔxôœèPJªêžÐ«ÈJ|D‘"ìæÞ:s·4 TgXÛ›¾)=E/wê~iÅ©•ý©ÚÞœ8 iiM_L»uœÝ”å„]²å96÷&m×:àäÖòCàÊê%CÆ&¶À›FÅ÷@à”dõ»~@è&7†ªÉð¸ÍÚ?Ûúì¿.ZÒR߇Ž%8ÈŽsK[=’Êhâu÷ 8u—GîÉ,2R@½5CË)·®Ë£}ÄštI®Þ]–gé„.: J{X0ѵ߄b–ÓÜÔZ¯Ìª4Å+8Û‡æªÂÚäO²ÛjÜ3dYÃõt ŽçbSv›ø}…†SHñ‡Ùù¨û]FŒK!ÚK¼6”Pš }‚)Öÿ:ç^Ž0Q¦Ó”à ¢I6[$ ¿Ù±38@JéKzáÊ‹JFQšƒƒìÑt yIîÕr1·¤ðú'¦x!³´µKVa·êl^´ÞÅ5s$.}3¤T£ÎÍ¥õàЅѳâÔz ¸?@aIþˆ²¨ù$c-©CVNä×Í|Óq Úuª›Â*÷óÒÂy–à§mÅ£×[ñ2m¼N±/¤F\”Guz.EQþÄÅ$6àŠ¨kñ´¯¬,>Í‘eÕbaŠ_¿`%È¿k mAÏGÁÙ¢æ6]Ͳ¥Ú2Œ( îj 8ÍÖƒ¤*-6ßhþ|£“‰ró3IÆ{il à\5@2½šœ‰%ŠpVÑÿþáeÞ\ oo´éÂÌsÅÙG¿p=·‘)ºýdÎ/Mä"ŸXX¹x½Õr:÷™¬³>­Á×xöE¤¬5ºE «s'heN[×gn»Æ—”*’=ÍUç&Z£>!ZT$¬¿lrɃÖÐt6^»…ÍãšCÁ›{&±rsf˜I ÷MWÂÞŽkˆfT%uܺ<*0T]åp‰”µ<ßBïV¤¸†ßpqRñͳ …|¹ÑèÄÊiÕÕ3;¸5Lûõ{_å†Zø{Ïû.¨<ägI;ù' bN¼™„ ×&ÝÕ+Xÿâ WÏÎË_æâ`^ÉA“~ªÝt_Ü(¾ÉZëÁ/„ïÎIÀž;¡ß졞òS/rsÓëî;ÓzôÒMI‰|ËÑvT…@ÏŽ ÀÃGÞ¡²0æf.…«ü»7—l¢j'D·y«"‡ö,‚VqÞ:-é7·î’*çQE]W£÷ÜY”mþó?ÍŽt~‰¬˜?ª¦¶?½šél„6e@/pTlO³!‹F/@Ñ>‡ëõ¸¿ßýCz1P‹wî2/,ç©ètðý&G¬Ú¥=A".‡yCHeùµÜÙs…—àÓƒAš*iD•v½©R•ª¾È‘y?0\TdzÚfN“[ kRx L—žvX(¼~ÄvÇ&—ËT—‰„4 ŽV{ÊO·6ö£¥©ÀÔ£~ùÆŠ^úq!Þ}›-³eQ´­¶—zÄÊŸOO“GݱÅãQW9kµH ŒxEt$ ˜­ iRúžê°Õ9š‹ÕªªrkŽìisý7zX›[âJ´¨ˆµ„‘C–ºßÙk}XK.F÷ ­¦u¸³45fƒûYÄmO†©pî4)ôÌVn=;iAŒÞ2 ¡™ š²ªÑ*Ý,ìÞ£‰ãEãWAaÅkopã¡d‰¥Leãp±·QSP7,lcõ¤–Am¾¤Ád…ù`Œ?bµ]\ñ&ëAWUŠž7À蚎ʕmçg‘Ä:®@@b £|s¦Úw§¥‚¸ÂÌŽ¸5?kœ%aîÞ§9E«l¶)}.3X …q¢ü¨o æ>i)*WCSWäØÏ6 &d¹ø"øMjµ€jT9ÄÅ9U5ùÄ4.µÐ™ê\±æ*—†‡S§Rà&M¤r\ȹvwo³$cS<ÔÉOYƒbE(Ô™ubªªT©¦­›TpMoiÒ.^ ˆ~Žü¯ÿhüÈ™³ø×ºzBU©ŠªÆ™W¢¨§õ¼hì!úä:×¼LíñLJiÄ:Ú»)ujóXgÞ›äPRûõ÷õ Ö´BypûTb±\‹¶>chDo 4s­PI)½·MD =ýF=3kWOÏk¯äp†ÏŸ¯œø“,:ë™ýšªÆÃ}‘Ôhê.«3]-‚Ü ¥,“˜3ÐÀCV…}“µGòŠy§X·Æ)óuƒðÚ‚²¼º.˧bã;d%úà îòt?¦é(±–u6?ŸÉŽÝ‡/h@"¥8Xcêö³è¼¨å¤ÉÁ·ú–bÂþ”`¤å%§à;èŠ$ÎãYðk z|ˆ‡r’B!»Þ@¦ZöªËd5^?ƒ­ãÁÑ`ˆ—^]šž¥75 ØÙú,U—^©i”ÃÔhn&YÈN64mwàW\¹HÙîscâž%)Y–‹œ¢èuÁKÒñ„mÚâ8}[n†¶2¦>T ¹§í±±R6ž×Ôu(ËÊž¯w}%°§½RT6ƒ]_¡Éô€Ä =5~ó7 ¾,«¦ˆ/ÿ`v°Ì˜Æ¢â\Æ XJ‹:)(™ú¦9wHĹÏIÕLÍö}  qWY„BŒüÅE§ #KËT¼Ï¯žRÞ>LêÿÂï`=P~~ƒH\ˆü’?2³A~×®e$7ëœUÍô†Í@.œRï Ñ)RᦻՋ gîªÚ%RqDP¥ÎE{^.øqÙ‡óÖöÔR•<ä·Èu ”pRû2å"ž˜ÆQBZ‰·¶'o¥ŸÇË%öÎE ^UD¤EÜgqÙ h$WƒE[)®’ZöÖ´çMD┨h íçd\¾€ ÑídJÈ ­ã¯D·,/J’ÜF&I0÷Þ³¢û‚±uˆE²OcZ`¢76O£ï/¡>£퀧Ñ/XQîöÑÌëÉRò›:“UJ·Ùæó¤ñ²$D6g P{ÕÉMe)ÿôuBönWà*ðBÓ»[7ðf‹Í¯¿åiæ´W\|ž¶¨"< 6Cž¼ýÝé—W€*í+‡Þ‘zÝ ¯¾Ex²“’¸,ókQœÃ»©pèƒjQqËu„m°{½Y8´iPò°‘«{º0`·Ä™,\ËžÛ“ êƒì¨ÙîÅ/ºÆ@ËÔš‡øHK}€‰ÜÔßi^R–JÕ)[Õ˜îC ®ê¿ÀÈ ¹Ô¢Ý•¨sº‹g÷FÂD†“#©\=|ôä‡-:á¶áWÙ0¬q4³x#X¿[™öUHKy?‚îd¿³xËØ2nØû«óŒ“+Y6œoƒƒQ–ãr;ðk%ô|~˜UräS À'»k@£È¿¡´UaI¼ZiáD4¢ïeÌò¤g¶)Ô8i›÷ó™DE¸ÞLAÜjÙ9LUDÉ€|“Nwìá¯V—Îm€Œ?29æP¯lÓŸf»Ä¢rò³HàFdˆÕ´¼·¼5ŒöìR[óˆ/ íût¨ -JooÊx·¸^²2¹;6 ñ "c·`ègòƲ,Õmb#MÒ PxÀ~‹S»ÍȭɃû räZÔûcI§rk4@>tMBïJ[K` •fp‰–¸ÏÈì=Þ=ã ŽÆ#3PYt¥©wê­,Ö*ra<öÙÒŸì83q_‹à¡#M%Úç^Ôgúq’^Aeáš,Ñ_†‹ë±;Æzð tËù¶Î×p'L‘þó?Ѝ vÁ¯z¥˜Ú`}‚7†±ÿÍö_¿¨/Ú0½÷ê†J>B}ìÌΣ°£]¼C¥ùvװ¿ŒIå+ö·7¥iä. ¤D(f§l`Eëq #¸3é —=Ðâ3v{2yO¾”‹D¨Cö3µ”Ã'•ˆzó@…#¡Ð¾07r¢$Á£·—= >ïæ©ÖD¥n3Òñ¸œo]퀣Âѹ±Ö ló<0]ýF øSÍo©{,^ºOÊr<ýÐÒŒ›4Šˆ/šÔ¾L"ψw‰èb¾)îó;Hý¥ÍüZ×ãfÖÁ—K~¸ie"~ˆÅOf:E= (ò,×¾§7¶×W~¡ßçmç1ÝŸáñúñÄF²O›G›"%lÊá’|5ÎXè‹ß QÕÊéŠb胓ÙÂéÞÚiÊgrªYozÏ’H'¦m»3Ìȃm!7Vª±–àÛ^í<»Òb(Tl¤·Ž$‡“cÔ¾ƒFó‘r\0P¢@Þks¾Ž×Þø0‘Nõ…³ýJ-8òX–Êòáæ4ûÓÏo ¾®W›nŽg™Î°i¡ëñC06Â.'½W×Ýv_£¡´ÿÞFÞ÷7`ï¡Ù #Š RC„XO©¾‘Ÿ³ìpi­¥¨÷¦´,»q+ð&.0´ù‰‹Ðì@Uo„Æ&†8Œ  Ú~²fx¼0$óHªC¢˜\䦱låÖc:Z•´ÿråCÞUE‹CÙ’HZ![¡Ã©C„ýð]ZR,Déýß½²q›lüa¥Íù@I£U–wˆÉôÍ%s÷–É: ñv~ d6ZH ŒT€]ó?–ï#Ûx¨´E¿e.¥3܆×äi‚ Ä?Ó6;@û„ÛõƒkòÔG¢u Ô ÌË…LT‰ƒ "º ±84ËjÒ5>Ó´xCL9þöˆ{ú6:)ܹØîš~GÉSjÀÆÄXväg¬@ö'`ÈjZh™>—8»?R³Ac$ÊÅJŒØWUÔP#SG·+x4Ín  8 󌲣»ß‰BPUQrc°1ù$¤< c Ô3?É—¯#…ì[ŽR-Åå)°ãûæè`ˆu,ºK/·Ž—íPmæâJ‰ö«5¡lrtFìpY×­ ùs”ØHË5ó•pÊ¢”ä—ã´Éýg×›îÝ7ÖöO¯UÓûŠ H+äù¹¹Ú-tàQÑO8«Óðžj‚çk¶3 Ë+æçFÿí¥c oÏš5yˆZ/æõÇqœý´CîÙTÇaÔ<@¾6AÚÅ[eÊœ¬p o±c}ÎvX{‹.Í\Ñ>9‰aã( 2\#× ¥rBgx®ê(Zs1,ƒcë{­ Ý‰%É~"dØð6{+¯¾ægµD9©8œ ®±¹J–‰ÇhArïèí³]3Êùn9þØO¶u3z+´®B%õäõ—<±“Üãéo/F»v_Ù™;|Gz³ôs¾“u ¤4»yÛÓ}õ¸Aô5êžøO¼Ûx>Ó]ÙÚ·‡%µ5ÏE“ƨ/5/I›¾Ivþˆ×’Dêu>!‰¾säØB÷ÏâqƒLåƒÑ!:æyæáY4Þä*DydIاr?“f:ÜoüBu·—'é ô;N˜éÔ¤ð÷ðá’{W¤´IH¨Á¹Sä¥ì¡ê6Nï²›å)²Lp$Á%Èo›éeÀé±RµØéÀ¹Û²gÁ;|Êþ:›¬m2…/Ýø—'õ4±Éî¸í –³°@Ê+lÝi6i3Zð ›ÆåbÏ›ÑÌ€çaà—Ä^7ÎÄàÝCÅ2IÖç,…/½aÅaâ )òḠèüÞt¹ /¼C~³¯¤‡ŽÅÜ@E|V†¢Èð½>æpƒz1“¹·É›ãêr>o\¶||ú0û$Ìg+²ë,·é/¿ü~â_ÿþçßþþ×?þç/ÚMÏ?¯½Ìá yôz€y'îj—yFáüˆY1r¯ºàß›1æðûäF\íN±¿¥|7—3ÞÂwË) ¿®U.ùN}nöÉÔç‡û?wÈ®ÓnöÛÿãÏ®Ÿw#þÛ»H~˜iï]!?Öi¿K}~Ç‘½³Ö¾ººû˸h­Íí‘ç&Ê_}þù|~|5k­…gð×ÇóŸÏŒ·Êoñ·ð+û­Q%«@¹pƇŸFCìü_kÚø|´·b« 6ßíÅ·°£†ã[û ìÒ\ {ËÚ8Ê/Ç7ÏëëäP,6×»È^±¿q4±-6g¬¯BÃËaºh»u¬•ãÎf‹<¬¹EeëÂ@䑽þ*wÎ:¬Ì›»…šƒ&,É0ùñõržÛÂþÄÕÖrYù°.pþ—ûCʼ´s!a[q-[%w?ޤ°‰•;6?ö3’—¤}Úžç¾bÍÄ­gšƱl>¹û¹PøøûÙŠýŸWóÀñ¿èŸƒIEND®B`‚freeipa-3.3.4/install/ui/images/panel-background.png0000664000175000017500000000041212202434255021750 0ustar mkosekmkosek‰PNG  IHDRJÜý5’tEXtSoftwareAdobe ImageReadyqÉe<¬IDATxÚì’Ñ Â0 E»Mu‚¨ûÿÿé/­If|¸%%)Â^|ØËáÞ&½ÍF¦œó0¦”¾8gÅM1+Чâ­xÁ.PwÅ7.H©˜#T}2¡0Àö•gø¶Sö¦ìé“®ò,ÛÁÅ~ Û3/Ù«²Sõ ¡­ŠLvfdšìžW/Œ”=½5~›[Ò UžyPñÞ —ëÁÐÌ€=i€Í$(7‰P%rp0æî¬J~QTÑ5'aÝ[Do¦ Ý»s j0öÝÈš0=ò9ù™håm.÷Áyc•]š×O×ãKBà| †pݘ3¥\\;j-m½’_ØÔ‘‡~{‘sIEND®B`‚freeipa-3.3.4/install/ui/images/ui-icons_222222_256x240.png0000664000175000017500000001042112202434255022110 0ustar mkosekmkosek‰PNG  IHDRðØIJùíPLTE$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$$"$ðÈNtRNS2P¿ƒ™."Tp@f`Í <BHJZ&0R,…4‡ÃjÉÏÇ8D½¹|«µ¥©­³(ýŸ$ï £b•¡¯lßF>n~‘hhÒHý…IDATxœí]bÛ¶ÉHªå„’-{iìZK:gó’lk×n­š-©ÓtI×õÞÿq€q? E²$ÛødK>$î>Á;”•ÊÈÈØPìZ…¢ØsÖV¯€h!˜Sy»„0E·0}H¹)-ðàæt k€íoÿܪKp”\RÎÏ  €ï.•E‹7¡¿ š)— *V;~ôPeÞâ Bx°*ò,=$z†¥Dؾ„í¢¬ úÅJ±½ÛïÒ¸Ù»¿„¶Ø9î{ ”‘‘‘‘‘‘±Ç¸ñHpÇqW@Äò"2'ðŸÛBúè[¥$ € @TàÕiºHÕ/äábÙ¥9ú6“!¡XãHq`DE¤Ç*RΖ€­ HV!Ÿ%ÙÚã…¢;ÐòÔðÁîÓá"¢ñúãò ÙiÆ]¿ ddddddddìëþÉÐ4yüµ5 ôô ‰Rb¹@(”8šÜÛCd‡öŪÐÝ¡¯,Ü@T@i¼ýÐb‰rq0alX!ô¶”ú° ¯p‰öeº, ëß=4bW ¼{¤ 5°­ÍƬhu~À(ÁQŠ^@ãó3Ú=î¢é"…bÿä5XC@J‘ޏC‡ª¤ú€Té®ï7¼ú6™‘‘‘‘‘‘q_±þ²Ô5à ©@,r šɩªDó«)°Tñ|žOœ…@å ON-Õ™ÊýÉ §÷¥’âýíò[n@ìØR¼¡™XôIm‹Ý‹(‰µá¡F Ê@”?±ð=0Þ puL‘˜;g$Òá@6η„ô „K`Êý>п» @h Õ£åüKV€nÅ"a¦"« ù%l‚@.v‰$/ðU^ôÖ GÈ:#`` ’ €u‚¬TtK©Þ~àÅ‹ÃZ Ýù5T¼¿‰%ÖkìõxÀ®ŸÉÈÈÈÈÈØkÜì]\*ìQÙÀ› ,Ò‡‹ÒëB†ª44 ÚOXKÍ|Šy‚Îgƒ¹Á+_M¤(ûlоEžO„ú V$ûT1BXõõ’b¢-Š|?@ ÔfóÕBßXràö%'@Ò¹A\ºI´á¹J,}†€BBcáó\V ñÊrÁ§£h(Ò]tIÈì^ªó¡}ÜÇÅoÎצo ¾S3ƒ ";£Ï÷Ê™ºìÑÁb}Ü"ß° —Ù){b$‘½¦¥ÆâãGwwݾŒŒŒŒŒ»ò–ßÈa‡œÞb"Þð)öïÓT@pš…F_er6JvШ¨áöÁ"mèÞ­¬M-ÁŸd7óê6”Ðx€¯¯„˰6Ó¥;Èì…/¯×ö“ìŒ`>KrP\Äö°_¸Ùë^uŒ1%“ÛOúT‚M²­è.±}¹–ðQ3æêñ€¶.Nسäã}«¡)½—ð>€÷ûäþ-âw`—ê—aƒø—ÿ+sy$ã€äÊt‡ø—)ÜN¬bFFFFÆýBeâ„jùúnNŠ¡Vn4ŒÕø,¹ÁA*õ™Xñâ*ÎÇ5«¤>ÙãP‹‡ªGæ…êa ¶ƒ3 Õõ{öoBˆ ‹&<ô”L[ §ÄÞNc.‹™­Ã¶Üi=Ã`ãQ@‰d‚¯µ ͆I¨Å.I«ëºlÀ`\tà[< èCit¡48Àù4É-rÀ Ž+ÀÌf³Øì‘±‚B€CB ÓÑMH i¤„Ÿôy }˜†Û>ÀÉÍrx¤ñ‰ÝýÄp|zø;BÀãÇ;áb±u¯‹rŒýŸc¨K¶Ÿú4t ôzÀ‘1†G~ ²þß`Ž†ØšÃùêKàÉ| Ì”>ú½Û¡²¯O$ÀØÿðìó~ ¶Ao)Š£¥0pzz ½}i´ý˜ûÓ`;ADÀ¹ÙûüÜm8n:ÁcfÚA@s7ºÁðŸ˜Lê÷ºÞ Z /..À»¨ð€êh8Ôoþ°r? Ú ÅNÇã9Œñ3BèÒ~o_ØÞ'`Àâo„€îpO-˜Ë :¸TGî L;ôÇ7ÇÝ]`ìÚ°B’€Ô%€Ë›>°î*wT´½îpMŸ©0HÝ}&t ¦ò·îÎ^1ˆÖ'Oqór'À2P«Í¡ª¦+Äz,tIW''|enÔþŒŒŒŒŒ=dzgñòRÌm˜[Nò¶Sùt÷K{›úÒ‰m²Ý娓Vžtû6¡ÉáÒ²R`úÔÑûšÎ¶NØ&}ÛöB Uå™(òr<ôqÈVyrÐrA**¿Ýدzg6ÓD#›± —–›óÑYP›`®ìîí¥áv‚Ïés€çÌ~(zûMlÞe¿|u¸ÌüQ¿a…*}ž+TŸÌ ²€ú“ºRÆùíX c"+*Ÿ NlôŸNûhc¿Ft‡ÀÛ—&àÅù‡ú¶¿Ô1%ØQ''ßê×?œlÚÃ׸•+&£r{ýj¸N‘಻® æ4ü) ÚËÃ`¨N狌€.½ Ûß­ˆ  ùüëÇ£Çÿü®•Üá—“§ôì)q ´2Ÿ?÷²ñýn¼3H€bÐÌø`ï}Ø ÷—­Âþ.`–ñõú§ìpqY1ûe_bûÕËïu÷7ùþe+NÍõ_Fö†¶Ý(êDTƒü,àÃÞL}LLžrûùmP5‹º|±x芥1Œc…ûŠx DAb ŒŒŒŒŒ`ˆ¦M(±ê7¼´ÐNEDï~žÏMzé Ðö+4ÆçÉBXd.ŽÃMzþËv͈ë¾µÓÏð¶«P×d8‰p¬ÿ<6?®Ø8ØN‘ý*xõêèÕ.»¾6Ú6G÷€­ìFåZû½ã…Å)ÝݦOéÉÉ ! ùlÅSsýÓÐh³èíæssàNðõp8Ú`'´0ö/<Æþš¤£s£ï©ß}ñ.æ@ǨÛsƒ7ξ§OÛŸVîDúú€a5ŸÏaŽvÜô]๘õúðÔm1™ø+ÝêŸÒ3äÃýyè6ðÛ õ‹ž>@ßu50ëÀPÚsÿÜÅ5‚¤1=Æë=§pý¢ *ÂKV•Ò«Ü‚Õã€ÝãøÝ»c$N®4(úX¹r2###c- ñê賟LóÓÙδÙ>޼]¯ûó5Ú.žsŸ´ÂYsÇ1ïÞf0Ã;ü'̨¦˜Yþg銛Â{“@9øà øÐÕ`aC(ލ=%bêoà2ÌÌ=­†Þnœò¤1ø jœ‡BŸ’o¨½S$nùãà#Ím“ݘú=iœê0ÁcÊÚï§ÝÈþÐÒÝi9Åö}ÔoI…Ù ¨Ýù®qãT‡š]òW%.Ãö‡(‰ËØ…æ]zÛ\ðx f³Ùö"]o°×'uÐ䫵tŠk{Àv;AëÍC3Ö†wž€w¨R_#÷±X» Þ(x§÷Ò‹/q%¶èùW¸ ¨þÅ›ÇÌÜhpíÄk_IöXŠùÇ'b§Éú/fXÞþ²Köi´"#####ã†QCL¼iÀˆ2téè àà€Ê5¬¶L0 ¶¬ÄêQiÞH“2;yÒTêOok;×¢ì Ù¶`õÃRš²Ng{z´y¼!—Kx²¢²·çmì?A(vø£UÒ~Œ°ÎmLÀ(`o/!nòÿ¤°mXŠ€-{ÀvûŽ÷[¾ € dÇw=Àn「ŒŒŒŒûøsdwåüzŽÖnê(åò}O®yŽ~­Ñó ãúmà ›ðï?XUÞ;,àš…V'+û €VŸ&ïJ¸Rê×Z]á§­§:£¥Ï×zC'ýÓ-߆ºžÝÈ@åy ö4¼­Úuó—þ §`VÛ“wö«ÑŠ#÷ýzP@Q˜ N>2/ÿý{¦\o)Žö”ëWøŒ›~a3xLÀw :_QÞ;Œì=pŠÖ¼èdt§Ãî\'8¸º¼ÂÝ~3áSRPÛ¡Ú6Æïõùy+ŸšÏÈÈÈÈXüù€”ÌQ­*¯ÚÞºr üù€”Ì—Ñ­*¯ÚÞºr gÐál™/¤\U^µ½uå$øóüœ|mbÃëVn–ÒÚòw \V½å|ù‡ÞöDËÍŠNVNåæþy‡À7ì¢ÚÙàëk<;œª/ËE}?E*dzgáO ú¨ß~ûègþœ/9¿®6˜Êæê½f c…D}% Š×g$õQî·Gž7öoŽ€)úº¡ÏU J¶ð˜˜o™,O@ú0ß¾Q(íòÀä;žbõ¹¬˜wõ“àÏ:5× úNŒwRÀåþN5ØIòöy'KË?}²¹:9‰mֽ߯®*§±í@fÝ@jU9m‡²ë†Ò«Ê´ÃÉ{öÿÓò$âØ——}öídF€âÿôp¿Ñ|%!DdF¸·>™ýû»}Gö€{ßÜ÷»@FFFFFFƦQÜžH ¹ ªÕºìÿí3 •Ðu øù¾Möo¸½·Ê~êvy»}¡mûwz<Ø7õ•ïnP9ørÆWkÿíñu= ©¯°|«ì_×n½ýëÞz쿳}@ÞþÛãIXÆn÷›‘±çø?Éæsn~‘hhÒHý…IDATxœí]bÛ¶ÉHªå„’-{iìZK:gó’lk×n­š-©ÓtI×õÞÿq€q? E²$ÛødK>$î>Á;”•ÊÈÈØPìZ…¢ØsÖV¯€h!˜Sy»„0E·0}H¹)-ðàæt k€íoÿܪKp”\RÎÏ  €ï.•E‹7¡¿ š)— *V;~ôPeÞâ Bx°*ò,=$z†¥Dؾ„í¢¬ úÅJ±½ÛïÒ¸Ù»¿„¶Ø9î{ ”‘‘‘‘‘‘±Ç¸ñHpÇqW@Äò"2'ðŸÛBúè[¥$ € @TàÕiºHÕ/äábÙ¥9ú6“!¡XãHq`DE¤Ç*RΖ€­ HV!Ÿ%ÙÚã…¢;ÐòÔðÁîÓá"¢ñúãò ÙiÆ]¿ ddddddddìëþÉÐ4yüµ5 ôô ‰Rb¹@(”8šÜÛCd‡öŪÐÝ¡¯,Ü@T@i¼ýÐb‰rq0alX!ô¶”ú° ¯p‰öeº, ëß=4bW ¼{¤ 5°­ÍƬhu~À(ÁQŠ^@ãó3Ú=î¢é"…bÿä5XC@J‘ޏC‡ª¤ú€Té®ï7¼ú6™‘‘‘‘‘‘q_±þ²Ô5à ©@,r šɩªDó«)°Tñ|žOœ…@å ON-Õ™ÊýÉ §÷¥’âýíò[n@ìØR¼¡™XôIm‹Ý‹(‰µá¡F Ê@”?±ð=0Þ puL‘˜;g$Òá@6η„ô „K`Êý>п» @h Õ£åüKV€nÅ"a¦"« ù%l‚@.v‰$/ðU^ôÖ GÈ:#`` ’ €u‚¬TtK©Þ~àÅ‹ÃZ Ýù5T¼¿‰%ÖkìõxÀ®ŸÉÈÈÈÈÈØkÜì]\*ìQÙÀ› ,Ò‡‹ÒëB†ª44 ÚOXKÍ|Šy‚Îgƒ¹Á+_M¤(ûlоEžO„ú V$ûT1BXõõ’b¢-Š|?@ ÔfóÕBßXràö%'@Ò¹A\ºI´á¹J,}†€BBcáó\V ñÊrÁ§£h(Ò]tIÈì^ªó¡}ÜÇÅoÎצo ¾S3ƒ ";£Ï÷Ê™ºìÑÁb}Ü"ß° —Ù){b$‘½¦¥ÆâãGwwݾŒŒŒŒŒ»ò–ßÈa‡œÞb"Þð)öïÓT@pš…F_er6JvШ¨áöÁ"mèÞ­¬M-ÁŸd7óê6”Ðx€¯¯„˰6Ó¥;Èì…/¯×ö“ìŒ`>KrP\Äö°_¸Ùë^uŒ1%“ÛOúT‚M²­è.±}¹–ðQ3æêñ€¶.Nسäã}«¡)½—ð>€÷ûäþ-âw`—ê—aƒø—ÿ+sy$ã€äÊt‡ø—)ÜN¬bFFFFÆýBeâ„jùúnNŠ¡Vn4ŒÕø,¹ÁA*õ™Xñâ*ÎÇ5«¤>ÙãP‹‡ªGæ…êa ¶ƒ3 Õõ{öoBˆ ‹&<ô”L[ §ÄÞNc.‹™­Ã¶Üi=Ã`ãQ@‰d‚¯µ ͆I¨Å.I«ëºlÀ`\tà[< èCit¡48Àù4É-rÀ Ž+ÀÌf³Øì‘±‚B€CB ÓÑMH i¤„Ÿôy }˜†Û>ÀÉÍrx¤ñ‰ÝýÄp|zø;BÀãÇ;áb±u¯‹rŒýŸc¨K¶Ÿú4t ôzÀ‘1†G~ ²þß`Ž†ØšÃùêKàÉ| Ì”>ú½Û¡²¯O$ÀØÿðìó~ ¶Ao)Š£¥0pzz ½}i´ý˜ûÓ`;ADÀ¹ÙûüÜm8n:ÁcfÚA@s7ºÁðŸ˜Lê÷ºÞ Z /..À»¨ð€êh8Ôoþ°r? Ú ÅNÇã9Œñ3BèÒ~o_ØÞ'`Àâo„€îpO-˜Ë :¸TGî L;ôÇ7ÇÝ]`ìÚ°B’€Ô%€Ë›>°î*wT´½îpMŸ©0HÝ}&t ¦ò·îÎ^1ˆÖ'Oqór'À2P«Í¡ª¦+Äz,tIW''|enÔþŒŒŒŒŒ=dzgñòRÌm˜[Nò¶Sùt÷K{›úÒ‰m²Ý娓Vžtû6¡ÉáÒ²R`úÔÑûšÎ¶NØ&}ÛöB Uå™(òr<ôqÈVyrÐrA**¿Ýدzg6ÓD#›± —–›óÑYP›`®ìîí¥áv‚Ïés€çÌ~(zûMlÞe¿|u¸ÌüQ¿a…*}ž+TŸÌ ²€ú“ºRÆùíX c"+*Ÿ NlôŸNûhc¿Ft‡ÀÛ—&àÅù‡ú¶¿Ô1%ØQ''ßê×?œlÚÃ׸•+&£r{ýj¸N‘಻® æ4ü) ÚËÃ`¨N狌€.½ Ûß­ˆ  ùüëÇ£Çÿü®•Üá—“§ôì)q ´2Ÿ?÷²ñýn¼3H€bÐÌø`ï}Ø ÷—­Âþ.`–ñõú§ìpqY1ûe_bûÕËïu÷7ùþe+NÍõ_Fö†¶Ý(êDTƒü,àÃÞL}LLžrûùmP5‹º|±x芥1Œc…ûŠx DAb ŒŒŒŒŒ`ˆ¦M(±ê7¼´ÐNEDï~žÏMzé Ðö+4ÆçÉBXd.ŽÃMzþËv͈ë¾µÓÏð¶«P×d8‰p¬ÿ<6?®Ø8ØN‘ý*xõêèÕ.»¾6Ú6G÷€­ìFåZû½ã…Å)ÝݦOéÉÉ ! ùlÅSsýÓÐh³èíæssàNðõp8Ú`'´0ö/<Æþš¤£s£ï©ß}ñ.æ@ǨÛsƒ7ξ§OÛŸVîDúú€a5ŸÏaŽvÜô]๘õúðÔm1™ø+ÝêŸÒ3äÃýyè6ðÛ õ‹ž>@ßu50ëÀPÚsÿÜÅ5‚¤1=Æë=§pý¢ *ÂKV•Ò«Ü‚Õã€ÝãøÝ»c$N®4(úX¹r2###c- ñê賟LóÓÙδÙ>޼]¯ûó5Ú.žsŸ´ÂYsÇ1ïÞf0Ã;ü'̨¦˜Yþg銛Â{“@9øà øÐÕ`aC(ލ=%bêoà2ÌÌ=­†Þnœò¤1ø jœ‡BŸ’o¨½S$nùãà#Ím“ݘú=iœê0ÁcÊÚï§ÝÈþÐÒÝi9Åö}ÔoI…Ù ¨Ýù®qãT‡š]òW%.Ãö‡(‰ËØ…æ]zÛ\ðx f³Ùö"]o°×'uÐ䫵tŠk{Àv;AëÍC3Ö†wž€w¨R_#÷±X» Þ(x§÷Ò‹/q%¶èùW¸ ¨þÅ›ÇÌÜhpíÄk_IöXŠùÇ'b§Éú/fXÞþ²Köi´"#####ã†QCL¼iÀˆ2téè àà€Ê5¬¶L0 ¶¬ÄêQiÞH“2;yÒTêOok;×¢ì Ù¶`õÃRš²Ng{z´y¼!—Kx²¢²·çmì?A(vø£UÒ~Œ°ÎmLÀ(`o/!nòÿ¤°mXŠ€-{ÀvûŽ÷[¾ € dÇw=Àn「ŒŒŒŒûøsdwåüzŽÖnê(åò}O®yŽ~­Ñó ãúmà ›ðï?XUÞ;,àš…V'+û €VŸ&ïJ¸Rê×Z]á§­§:£¥Ï×zC'ýÓ-߆ºžÝÈ@åy ö4¼­Úuó—þ §`VÛ“wö«ÑŠ#÷ýzP@Q˜ N>2/ÿý{¦\o)Žö”ëWøŒ›~a3xLÀw :_QÞ;Œì=pŠÖ¼èdt§Ãî\'8¸º¼ÂÝ~3áSRPÛ¡Ú6Æïõùy+ŸšÏÈÈÈÈXüù€”ÌQ­*¯ÚÞºr üù€”Ì—Ñ­*¯ÚÞºr gÐál™/¤\U^µ½uå$øóüœ|mbÃëVn–ÒÚòw \V½å|ù‡ÞöDËÍŠNVNåæþy‡À7ì¢ÚÙàëk<;œª/ËE}?E*dzgáO ú¨ß~ûègþœ/9¿®6˜Êæê½f c…D}% Š×g$õQî·Gž7öoŽ€)úº¡ÏU J¶ð˜˜o™,O@ú0ß¾Q(íòÀä;žbõ¹¬˜wõ“àÏ:5× úNŒwRÀåþN5ØIòöy'KË?}²¹:9‰mֽ߯®*§±í@fÝ@jU9m‡²ë†Ò«Ê´ÃÉ{öÿÓò$âØ——}öídF€âÿôp¿Ñ|%!DdF¸·>™ýû»}Gö€{ßÜ÷»@FFFFFFƦQÜžH ¹ ªÕºìÿí3 •Ðu øù¾Möo¸½·Ê~êvy»}¡mûwz<Ø7õ•ïnP9ørÆWkÿíñu= ©¯°|«ì_×n½ýëÞz쿳}@ÞþÛãIXÆn÷›‘±çø?Éæs?†ÿ Ëouýg^¥5XÉ äðŸÁ}áÿL;ÏÝeLŽNe¹ÎùöÉIEND®B`‚freeipa-3.3.4/install/ui/images/subnav-background.png0000664000175000017500000000232412202434255022153 0ustar mkosekmkosek‰PNG  IHDRÀež÷tEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp 40÷šHIDATxÚìÜ1’ƒ0 PcÎ —£å|t˜LúØ™Q³+ç½ÖCC÷çKZžç)ŸÇñlÛV ƒëºÊyžeß÷åÓ{í}ØZó÷H£ÖZz%ï0@¶<|~ÿɺ®Ã,+å0…eY†ïÝ<š›€ið· SÖ0Mø½ï[à·uðûzd2ʲ`¦ÑZ€˜_èdj€ ›P\«l @.£,k€ßǽ‡Qm 0ü‘аh²eY—®˜F¨6 ÀL4ÀÀIhØ,² í@6¡Ø,f¢`¡h;Àd€lF ðK€;µCa¦ô·IEND®B`‚freeipa-3.3.4/install/ui/images/ui-icons_ededed_256x240.png0000664000175000017500000001042112202434255022567 0ustar mkosekmkosek‰PNG  IHDRðØIJùíPLTEìîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîììîì&höaNtRNS2P¿ƒ™."Tp@f`Í <BHJZ&0R,…4‡ÃjÉÏÇ8D½¹|«µ¥©­³(ýŸ$ï £b•¡¯lßF>n~‘hhÒHý…IDATxœí]bÛ¶ÉHªå„’-{iìZK:gó’lk×n­š-©ÓtI×õÞÿq€q? E²$ÛødK>$î>Á;”•ÊÈÈØPìZ…¢ØsÖV¯€h!˜Sy»„0E·0}H¹)-ðàæt k€íoÿܪKp”\RÎÏ  €ï.•E‹7¡¿ š)— *V;~ôPeÞâ Bx°*ò,=$z†¥Dؾ„í¢¬ úÅJ±½ÛïÒ¸Ù»¿„¶Ø9î{ ”‘‘‘‘‘‘±Ç¸ñHpÇqW@Äò"2'ðŸÛBúè[¥$ € @TàÕiºHÕ/äábÙ¥9ú6“!¡XãHq`DE¤Ç*RΖ€­ HV!Ÿ%ÙÚã…¢;ÐòÔðÁîÓá"¢ñúãò ÙiÆ]¿ ddddddddìëþÉÐ4yüµ5 ôô ‰Rb¹@(”8šÜÛCd‡öŪÐÝ¡¯,Ü@T@i¼ýÐb‰rq0alX!ô¶”ú° ¯p‰öeº, ëß=4bW ¼{¤ 5°­ÍƬhu~À(ÁQŠ^@ãó3Ú=î¢é"…bÿä5XC@J‘ޏC‡ª¤ú€Té®ï7¼ú6™‘‘‘‘‘‘q_±þ²Ô5à ©@,r šɩªDó«)°Tñ|žOœ…@å ON-Õ™ÊýÉ §÷¥’âýíò[n@ìØR¼¡™XôIm‹Ý‹(‰µá¡F Ê@”?±ð=0Þ puL‘˜;g$Òá@6η„ô „K`Êý>п» @h Õ£åüKV€nÅ"a¦"« ù%l‚@.v‰$/ðU^ôÖ GÈ:#`` ’ €u‚¬TtK©Þ~àÅ‹ÃZ Ýù5T¼¿‰%ÖkìõxÀ®ŸÉÈÈÈÈÈØkÜì]\*ìQÙÀ› ,Ò‡‹ÒëB†ª44 ÚOXKÍ|Šy‚Îgƒ¹Á+_M¤(ûlоEžO„ú V$ûT1BXõõ’b¢-Š|?@ ÔfóÕBßXràö%'@Ò¹A\ºI´á¹J,}†€BBcáó\V ñÊrÁ§£h(Ò]tIÈì^ªó¡}ÜÇÅoÎצo ¾S3ƒ ";£Ï÷Ê™ºìÑÁb}Ü"ß° —Ù){b$‘½¦¥ÆâãGwwݾŒŒŒŒŒ»ò–ßÈa‡œÞb"Þð)öïÓT@pš…F_er6JvШ¨áöÁ"mèÞ­¬M-ÁŸd7óê6”Ðx€¯¯„˰6Ó¥;Èì…/¯×ö“ìŒ`>KrP\Äö°_¸Ùë^uŒ1%“ÛOúT‚M²­è.±}¹–ðQ3æêñ€¶.Nسäã}«¡)½—ð>€÷ûäþ-âw`—ê—aƒø—ÿ+sy$ã€äÊt‡ø—)ÜN¬bFFFFÆýBeâ„jùúnNŠ¡Vn4ŒÕø,¹ÁA*õ™Xñâ*ÎÇ5«¤>ÙãP‹‡ªGæ…êa ¶ƒ3 Õõ{öoBˆ ‹&<ô”L[ §ÄÞNc.‹™­Ã¶Üi=Ã`ãQ@‰d‚¯µ ͆I¨Å.I«ëºlÀ`\tà[< èCit¡48Àù4É-rÀ Ž+ÀÌf³Øì‘±‚B€CB ÓÑMH i¤„Ÿôy }˜†Û>ÀÉÍrx¤ñ‰ÝýÄp|zø;BÀãÇ;áb±u¯‹rŒýŸc¨K¶Ÿú4t ôzÀ‘1†G~ ²þß`Ž†ØšÃùêKàÉ| Ì”>ú½Û¡²¯O$ÀØÿðìó~ ¶Ao)Š£¥0pzz ½}i´ý˜ûÓ`;ADÀ¹ÙûüÜm8n:ÁcfÚA@s7ºÁðŸ˜Lê÷ºÞ Z /..À»¨ð€êh8Ôoþ°r? Ú ÅNÇã9Œñ3BèÒ~o_ØÞ'`Àâo„€îpO-˜Ë :¸TGî L;ôÇ7ÇÝ]`ìÚ°B’€Ô%€Ë›>°î*wT´½îpMŸ©0HÝ}&t ¦ò·îÎ^1ˆÖ'Oqór'À2P«Í¡ª¦+Äz,tIW''|enÔþŒŒŒŒŒ=dzgñòRÌm˜[Nò¶Sùt÷K{›úÒ‰m²Ý娓Vžtû6¡ÉáÒ²R`úÔÑûšÎ¶NØ&}ÛöB Uå™(òr<ôqÈVyrÐrA**¿Ýدzg6ÓD#›± —–›óÑYP›`®ìîí¥áv‚Ïés€çÌ~(zûMlÞe¿|u¸ÌüQ¿a…*}ž+TŸÌ ²€ú“ºRÆùíX c"+*Ÿ NlôŸNûhc¿Ft‡ÀÛ—&àÅù‡ú¶¿Ô1%ØQ''ßê×?œlÚÃ׸•+&£r{ýj¸N‘಻® æ4ü) ÚËÃ`¨N狌€.½ Ûß­ˆ  ùüëÇ£Çÿü®•Üá—“§ôì)q ´2Ÿ?÷²ñýn¼3H€bÐÌø`ï}Ø ÷—­Âþ.`–ñõú§ìpqY1ûe_bûÕËïu÷7ùþe+NÍõ_Fö†¶Ý(êDTƒü,àÃÞL}LLžrûùmP5‹º|±x芥1Œc…ûŠx DAb ŒŒŒŒŒ`ˆ¦M(±ê7¼´ÐNEDï~žÏMzé Ðö+4ÆçÉBXd.ŽÃMzþËv͈ë¾µÓÏð¶«P×d8‰p¬ÿ<6?®Ø8ØN‘ý*xõêèÕ.»¾6Ú6G÷€­ìFåZû½ã…Å)ÝݦOéÉÉ ! ùlÅSsýÓÐh³èíæssàNðõp8Ú`'´0ö/<Æþš¤£s£ï©ß}ñ.æ@ǨÛsƒ7ξ§OÛŸVîDúú€a5ŸÏaŽvÜô]๘õúðÔm1™ø+ÝêŸÒ3äÃýyè6ðÛ õ‹ž>@ßu50ëÀPÚsÿÜÅ5‚¤1=Æë=§pý¢ *ÂKV•Ò«Ü‚Õã€ÝãøÝ»c$N®4(úX¹r2###c- ñê賟LóÓÙδÙ>޼]¯ûó5Ú.žsŸ´ÂYsÇ1ïÞf0Ã;ü'̨¦˜Yþg銛Â{“@9øà øÐÕ`aC(ލ=%bêoà2ÌÌ=­†Þnœò¤1ø jœ‡BŸ’o¨½S$nùãà#Ím“ݘú=iœê0ÁcÊÚï§ÝÈþÐÒÝi9Åö}ÔoI…Ù ¨Ýù®qãT‡š]òW%.Ãö‡(‰ËØ…æ]zÛ\ðx f³Ùö"]o°×'uÐ䫵tŠk{Àv;AëÍC3Ö†wž€w¨R_#÷±X» Þ(x§÷Ò‹/q%¶èùW¸ ¨þÅ›ÇÌÜhpíÄk_IöXŠùÇ'b§Éú/fXÞþ²Köi´"#####ã†QCL¼iÀˆ2téè àà€Ê5¬¶L0 ¶¬ÄêQiÞH“2;yÒTêOok;×¢ì Ù¶`õÃRš²Ng{z´y¼!—Kx²¢²·çmì?A(vø£UÒ~Œ°ÎmLÀ(`o/!nòÿ¤°mXŠ€-{ÀvûŽ÷[¾ € dÇw=Àn「ŒŒŒŒûøsdwåüzŽÖnê(åò}O®yŽ~­Ñó ãúmà ›ðï?XUÞ;,àš…V'+û €VŸ&ïJ¸Rê×Z]á§­§:£¥Ï×zC'ýÓ-߆ºžÝÈ@åy ö4¼­Úuó—þ §`VÛ“wö«ÑŠ#÷ýzP@Q˜ N>2/ÿý{¦\o)Žö”ëWøŒ›~a3xLÀw :_QÞ;Œì=pŠÖ¼èdt§Ãî\'8¸º¼ÂÝ~3áSRPÛ¡Ú6Æïõùy+ŸšÏÈÈÈÈXüù€”ÌQ­*¯ÚÞºr üù€”Ì—Ñ­*¯ÚÞºr gÐál™/¤\U^µ½uå$øóüœ|mbÃëVn–ÒÚòw \V½å|ù‡ÞöDËÍŠNVNåæþy‡À7ì¢ÚÙàëk<;œª/ËE}?E*dzgáO ú¨ß~ûègþœ/9¿®6˜Êæê½f c…D}% Š×g$õQî·Gž7öoŽ€)úº¡ÏU J¶ð˜˜o™,O@ú0ß¾Q(íòÀä;žbõ¹¬˜wõ“àÏ:5× úNŒwRÀåþN5ØIòöy'KË?}²¹:9‰mֽ߯®*§±í@fÝ@jU9m‡²ë†Ò«Ê´ÃÉ{öÿÓò$âØ——}öídF€âÿôp¿Ñ|%!DdF¸·>™ýû»}Gö€{ßÜ÷»@FFFFFFƦQÜžH ¹ ªÕºìÿí3 •Ðu øù¾Möo¸½·Ê~êvy»}¡mûwz<Ø7õ•ïnP9ørÆWkÿíñu= ©¯°|«ì_×n½ýëÞz쿳}@ÞþÛãIXÆn÷›‘±çø?Éæs3Z‚d™=0~–›››K>{ö dÉb pÈC„ôm Ô"PÚžÄ;âããÃò!`8#¬L?IEND®B`‚freeipa-3.3.4/install/ui/images/arrow-expanded.png0000664000175000017500000000202712202434255021460 0ustar mkosekmkosek‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp lf$ë‹IDATxÚbüÿÿ?%€‰B@±, b×®]$ktssCº@lI„Þ5@üÅPðˆ7±"Í›€x®0øÄÑ@ü‡f‰„ñ8×cÑ 24Ùéøb¡ˆ÷a;Hl4¢Ûv‡«ð¦ƒ§Pÿ ¼ â&ÐÀ#;%Þ!”(‡~f0ÿÉ!ˆ):”:IEND®B`‚freeipa-3.3.4/install/ui/images/arrow-collapsed.png0000664000175000017500000000202412202434255021633 0ustar mkosekmkosek‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp Ĉ›ˆIDATxÚbüÿÿ?%€‰BÀcìÚµ‹( nnnx]ÀÄ-@ÌL‰ªø0+R–@| ˆÃ) D ^Äó¡l²c!ˆÏ±1%ÑȃË݈õ€ø ©|â, âw¸Ä¡PšäX˜Ä&ÄhÆæ‚@œKJ^`ðÜ`p­ˆ¶gIEND®B`‚freeipa-3.3.4/install/ui/images/ui-icons_ffffff_256x240.png0000664000175000017500000001042112202434255022600 0ustar mkosekmkosek‰PNG  IHDRðØIJùíPLTEüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþüüþü° ¼NtRNS2P¿ƒ™."Tp@f`Í <BHJZ&0R,…4‡ÃjÉÏÇ8D½¹|«µ¥©­³(ýŸ$ï £b•¡¯lßF>n~‘hhÒHý…IDATxœí]bÛ¶ÉHªå„’-{iìZK:gó’lk×n­š-©ÓtI×õÞÿq€q? E²$ÛødK>$î>Á;”•ÊÈÈØPìZ…¢ØsÖV¯€h!˜Sy»„0E·0}H¹)-ðàæt k€íoÿܪKp”\RÎÏ  €ï.•E‹7¡¿ š)— *V;~ôPeÞâ Bx°*ò,=$z†¥Dؾ„í¢¬ úÅJ±½ÛïÒ¸Ù»¿„¶Ø9î{ ”‘‘‘‘‘‘±Ç¸ñHpÇqW@Äò"2'ðŸÛBúè[¥$ € @TàÕiºHÕ/äábÙ¥9ú6“!¡XãHq`DE¤Ç*RΖ€­ HV!Ÿ%ÙÚã…¢;ÐòÔðÁîÓá"¢ñúãò ÙiÆ]¿ ddddddddìëþÉÐ4yüµ5 ôô ‰Rb¹@(”8šÜÛCd‡öŪÐÝ¡¯,Ü@T@i¼ýÐb‰rq0alX!ô¶”ú° ¯p‰öeº, ëß=4bW ¼{¤ 5°­ÍƬhu~À(ÁQŠ^@ãó3Ú=î¢é"…bÿä5XC@J‘ޏC‡ª¤ú€Té®ï7¼ú6™‘‘‘‘‘‘q_±þ²Ô5à ©@,r šɩªDó«)°Tñ|žOœ…@å ON-Õ™ÊýÉ §÷¥’âýíò[n@ìØR¼¡™XôIm‹Ý‹(‰µá¡F Ê@”?±ð=0Þ puL‘˜;g$Òá@6η„ô „K`Êý>п» @h Õ£åüKV€nÅ"a¦"« ù%l‚@.v‰$/ðU^ôÖ GÈ:#`` ’ €u‚¬TtK©Þ~àÅ‹ÃZ Ýù5T¼¿‰%ÖkìõxÀ®ŸÉÈÈÈÈÈØkÜì]\*ìQÙÀ› ,Ò‡‹ÒëB†ª44 ÚOXKÍ|Šy‚Îgƒ¹Á+_M¤(ûlоEžO„ú V$ûT1BXõõ’b¢-Š|?@ ÔfóÕBßXràö%'@Ò¹A\ºI´á¹J,}†€BBcáó\V ñÊrÁ§£h(Ò]tIÈì^ªó¡}ÜÇÅoÎצo ¾S3ƒ ";£Ï÷Ê™ºìÑÁb}Ü"ß° —Ù){b$‘½¦¥ÆâãGwwݾŒŒŒŒŒ»ò–ßÈa‡œÞb"Þð)öïÓT@pš…F_er6JvШ¨áöÁ"mèÞ­¬M-ÁŸd7óê6”Ðx€¯¯„˰6Ó¥;Èì…/¯×ö“ìŒ`>KrP\Äö°_¸Ùë^uŒ1%“ÛOúT‚M²­è.±}¹–ðQ3æêñ€¶.Nسäã}«¡)½—ð>€÷ûäþ-âw`—ê—aƒø—ÿ+sy$ã€äÊt‡ø—)ÜN¬bFFFFÆýBeâ„jùúnNŠ¡Vn4ŒÕø,¹ÁA*õ™Xñâ*ÎÇ5«¤>ÙãP‹‡ªGæ…êa ¶ƒ3 Õõ{öoBˆ ‹&<ô”L[ §ÄÞNc.‹™­Ã¶Üi=Ã`ãQ@‰d‚¯µ ͆I¨Å.I«ëºlÀ`\tà[< èCit¡48Àù4É-rÀ Ž+ÀÌf³Øì‘±‚B€CB ÓÑMH i¤„Ÿôy }˜†Û>ÀÉÍrx¤ñ‰ÝýÄp|zø;BÀãÇ;áb±u¯‹rŒýŸc¨K¶Ÿú4t ôzÀ‘1†G~ ²þß`Ž†ØšÃùêKàÉ| Ì”>ú½Û¡²¯O$ÀØÿðìó~ ¶Ao)Š£¥0pzz ½}i´ý˜ûÓ`;ADÀ¹ÙûüÜm8n:ÁcfÚA@s7ºÁðŸ˜Lê÷ºÞ Z /..À»¨ð€êh8Ôoþ°r? Ú ÅNÇã9Œñ3BèÒ~o_ØÞ'`Àâo„€îpO-˜Ë :¸TGî L;ôÇ7ÇÝ]`ìÚ°B’€Ô%€Ë›>°î*wT´½îpMŸ©0HÝ}&t ¦ò·îÎ^1ˆÖ'Oqór'À2P«Í¡ª¦+Äz,tIW''|enÔþŒŒŒŒŒ=dzgñòRÌm˜[Nò¶Sùt÷K{›úÒ‰m²Ý娓Vžtû6¡ÉáÒ²R`úÔÑûšÎ¶NØ&}ÛöB Uå™(òr<ôqÈVyrÐrA**¿Ýدzg6ÓD#›± —–›óÑYP›`®ìîí¥áv‚Ïés€çÌ~(zûMlÞe¿|u¸ÌüQ¿a…*}ž+TŸÌ ²€ú“ºRÆùíX c"+*Ÿ NlôŸNûhc¿Ft‡ÀÛ—&àÅù‡ú¶¿Ô1%ØQ''ßê×?œlÚÃ׸•+&£r{ýj¸N‘಻® æ4ü) ÚËÃ`¨N狌€.½ Ûß­ˆ  ùüëÇ£Çÿü®•Üá—“§ôì)q ´2Ÿ?÷²ñýn¼3H€bÐÌø`ï}Ø ÷—­Âþ.`–ñõú§ìpqY1ûe_bûÕËïu÷7ùþe+NÍõ_Fö†¶Ý(êDTƒü,àÃÞL}LLžrûùmP5‹º|±x芥1Œc…ûŠx DAb ŒŒŒŒŒ`ˆ¦M(±ê7¼´ÐNEDï~žÏMzé Ðö+4ÆçÉBXd.ŽÃMzþËv͈ë¾µÓÏð¶«P×d8‰p¬ÿ<6?®Ø8ØN‘ý*xõêèÕ.»¾6Ú6G÷€­ìFåZû½ã…Å)ÝݦOéÉÉ ! ùlÅSsýÓÐh³èíæssàNðõp8Ú`'´0ö/<Æþš¤£s£ï©ß}ñ.æ@ǨÛsƒ7ξ§OÛŸVîDúú€a5ŸÏaŽvÜô]๘õúðÔm1™ø+ÝêŸÒ3äÃýyè6ðÛ õ‹ž>@ßu50ëÀPÚsÿÜÅ5‚¤1=Æë=§pý¢ *ÂKV•Ò«Ü‚Õã€ÝãøÝ»c$N®4(úX¹r2###c- ñê賟LóÓÙδÙ>޼]¯ûó5Ú.žsŸ´ÂYsÇ1ïÞf0Ã;ü'̨¦˜Yþg銛Â{“@9øà øÐÕ`aC(ލ=%bêoà2ÌÌ=­†Þnœò¤1ø jœ‡BŸ’o¨½S$nùãà#Ím“ݘú=iœê0ÁcÊÚï§ÝÈþÐÒÝi9Åö}ÔoI…Ù ¨Ýù®qãT‡š]òW%.Ãö‡(‰ËØ…æ]zÛ\ðx f³Ùö"]o°×'uÐ䫵tŠk{Àv;AëÍC3Ö†wž€w¨R_#÷±X» Þ(x§÷Ò‹/q%¶èùW¸ ¨þÅ›ÇÌÜhpíÄk_IöXŠùÇ'b§Éú/fXÞþ²Köi´"#####ã†QCL¼iÀˆ2téè àà€Ê5¬¶L0 ¶¬ÄêQiÞH“2;yÒTêOok;×¢ì Ù¶`õÃRš²Ng{z´y¼!—Kx²¢²·çmì?A(vø£UÒ~Œ°ÎmLÀ(`o/!nòÿ¤°mXŠ€-{ÀvûŽ÷[¾ € dÇw=Àn「ŒŒŒŒûøsdwåüzŽÖnê(åò}O®yŽ~­Ñó ãúmà ›ðï?XUÞ;,àš…V'+û €VŸ&ïJ¸Rê×Z]á§­§:£¥Ï×zC'ýÓ-߆ºžÝÈ@åy ö4¼­Úuó—þ §`VÛ“wö«ÑŠ#÷ýzP@Q˜ N>2/ÿý{¦\o)Žö”ëWøŒ›~a3xLÀw :_QÞ;Œì=pŠÖ¼èdt§Ãî\'8¸º¼ÂÝ~3áSRPÛ¡Ú6Æïõùy+ŸšÏÈÈÈÈXüù€”ÌQ­*¯ÚÞºr üù€”Ì—Ñ­*¯ÚÞºr gÐál™/¤\U^µ½uå$øóüœ|mbÃëVn–ÒÚòw \V½å|ù‡ÞöDËÍŠNVNåæþy‡À7ì¢ÚÙàëk<;œª/ËE}?E*dzgáO ú¨ß~ûègþœ/9¿®6˜Êæê½f c…D}% Š×g$õQî·Gž7öoŽ€)úº¡ÏU J¶ð˜˜o™,O@ú0ß¾Q(íòÀä;žbõ¹¬˜wõ“àÏ:5× úNŒwRÀåþN5ØIòöy'KË?}²¹:9‰mֽ߯®*§±í@fÝ@jU9m‡²ë†Ò«Ê´ÃÉ{öÿÓò$âØ——}öídF€âÿôp¿Ñ|%!DdF¸·>™ýû»}Gö€{ßÜ÷»@FFFFFFƦQÜžH ¹ ªÕºìÿí3 •Ðu øù¾Möo¸½·Ê~êvy»}¡mûwz<Ø7õ•ïnP9ørÆWkÿíñu= ©¯°|«ì_×n½ýëÞz쿳}@ÞþÛãIXÆn÷›‘±çø?Éæs d~8jÁIDATxÚ¤R à #¨ô„ž°€¸`'ì„}´öê ãƒí„}À̤€«ZK(¸`'M ”’9‚©lˆ¨:!œV¬›÷þ.ÏdR*DñÌŸ.0yl2èˆ3>X&±5°JÙ3‹®3_ù¼‚ˆÿ»™È Zñ¯\Ž•Iw ­™žØçlü î:½Q§° ¼ ‡ic´½ÇÁ;gfG©[Á?È &íRÛížUÄ ‹ˆÛ võ`/¬9ˆ¯ÝòhwU…IEND®B`‚freeipa-3.3.4/install/ui/images/spinner-small.gif0000664000175000017500000000671412202434255021314 0ustar mkosekmkosekGIF89aç´  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~€€€‚‚‚ƒƒƒ„„„………†††‡‡‡ˆˆˆ‰‰‰ŠŠŠ‹‹‹ŒŒŒŽŽŽ‘‘‘’’’“““”””•••–––———˜˜˜™™™ššš›››œœœžžžŸŸŸ   ¡¡¡¢¢¢£££¤¤¤¥¥¥¦¦¦§§§¨¨¨©©©ªªª«««¬¬¬­­­®®®¯¯¯°°°±±±²²²³³³´´´µµµ¶¶¶···¸¸¸¹¹¹ººº»»»¼¼¼½½½¾¾¾¿¿¿ÀÀÀÁÁÁÂÂÂÃÃÃÄÄÄÅÅÅÆÆÆÇÇÇÈÈÈÉÉÉÊÊÊËËËÌÌÌÍÍÍÎÎÎÏÏÏÐÐÐÑÑÑÒÒÒÓÓÓÔÔÔÕÕÕÖÖÖ×××ØØØÙÙÙÚÚÚÛÛÛÜÜÜÝÝÝÞÞÞßßßàààáááâââãããäääåååæææçççèèèéééêêêëëëìììíííîîîïïïðððñññòòòóóóôôôõõõööö÷÷÷øøøùùùúúúûûûüüüýýýþþþÿÿÿ!ÿ NETSCAPE2.0!ù ÿ,™ÿ ø/5‚ ¢Ó a[BÍúû×ÌF mÿݱÂÃX8'®¹‹† a11U¬ü#Õꟴ_Î*›#‰ 7eìÎc^BŸòÂSÈOI„ä† ;÷Þ(R²%<7̘9ñÚµËoBxÒ®´¦L]ÂcUÿ‰cº,X³„ÒŒ‰û§ôŸ¹fÒ Ú®ªWŸ¢c¸ðÀ€!ù ÿ,•ÿ ø/Ö%‚ ®»ãZBÖ(Aû'͈mÿM ãÅÙ8#:Â%Ë‘!´Anæü{Eë¢Z“tŠà¢^õºûG/£¼ÑlÕ2—Ü0açJ#¬\ÂsÃŒåéî]Æxó“æp 5eê.f쟸¤Ë‚5K8 ™¸Gÿ™k¦-!½žíÈfí™Q º¤} !ù ÿ,–ÿ øo)‚ ¶sd[ÂÓÌýËFåI·Ç&!ƨ6sR”„+F"Å%‚èTY:©‹×?7 0C8î0‚U¦8{øÐÂnÅ„K8n˜PØ„+—ðÜ0cÿÑs÷Žg¼yáI»FК2u ¡3öOÜÐeÁš%œ†LÜ?£ÿÌ5Ó–½í„Ãz—§@tCý !ù ÿ,”ÿ øOž8‚ ºËÃ¥\„áö˜9Ø,Œ,‚òŠé—ÎŽrÊ„!ƒñ˜°`ÿ’û%‰–iÏ9ËF̘Öû·m ¹aÂÐ%ô$!Â,á†sˆ0W(¯¾{—“=„ð¤]#hM™º„Ñ€û'îÜ¿eÁš%Ävì Ðæši{xµ0cóþ]Í)Y¾€!ù ÿ,•ÿ H° A·Z4˜®Ô"rÿªéáUpÙ±tïPJ Ì”<åÆì_¸iÿÞPs­à¹fÚò9ƒm¡Ázÿ¶½8n˜0tUmH±¡Ý¿sÄ€•3xËò¾Ûy°Û5£áIk9ÐÚ²ƒÑ€û'îÜ¿eÁšÄvLÜ?ŸÿÌÁ ©í1?IDATxÚÄ ’%7n„Ö¼¾‚íû1«°äžWDâX=šØØõ¼~Å"ñ›ÿ‘úöÿ£?úóÿó¯¿çéÕ¿ŽúýcæW¦¯ ¿þ’ó_ÿøðs…‹W=÷øþmßÏ®=¬Å—çü«øý|¾ÈHlž_¾P„Ñ.U¯Síÿñ?Û3Z¿…Ùµ°Ýlàî)F~î— ¥÷ùÄ sÿI#äÕâ…„¬1áÚ÷ñ»Q«ÉÈŒ^ad+¢†`Úظ=Ýnµc;·K^ðÒsÅD–Öjxã—¬ÅvÇn‚¢©c‚¿uÿDî(ÃzÌýÜK=Œá×ÿ}:­’´?Týà|üåùOOÌG°{ü|Ÿý¨tµ~ÿ‚úu—| >7íkþýsÕ¢§M62Ä•¿²ø²ËKû÷,Þ.>S…éKéúþÜ£RG§õ÷s]3gaŽOldþ©,‰÷–È<; ÏÎØ+ÍuÖ/[«’ló«=Ñ Møî±r"xG9|ê¾߬‡¡ønœ… o%*L÷VêŒ|Ö “À´îFÝ÷W¶QßvLvO¼£L¾Ç< ÍnÓˆÁi?–õ»$S^ML„jÅlEEÀŒð½=>zäéòä òñ‚š›²]ü¿î[ Î7¤T^è…~#¡§?øˆA§^*OÖÓlÄè´’éƒ÷@çÆjÈf­)IwÀ›Î†U<ON¤“54KM€`Uûf> “‘J]…cZ·ªÉ¾å*Dk=–ð¾=ãàìòÀ<åÌ$RÏZÕ%ÞêÎåyî <·:O£Â‡ÉjY=‚;óÝŒ“+kOF‚dRh’?køÐ6³‚N¤ ž–YLÇyƘ6VH(·¡L¾C§¯wãþ4Ùƒ´¼d6ГÕò3mHâÃjÝ\‚ä! ‘,Eä(Œ:ÑÍ•0JÖÑŸh¢º!f€T&ks£"´­\‰o²[Ú÷Šf›¤§•ZL…vY»ù6o#WÏÃó D£Žw:%Ç£,ó茳û†À ¤7ÜÉâÍmîB̲ȵøEÁ [¯ úøT@¿$AŠ:ÎSL ¡œÈÞö$F×*e™†#êôÎx¬õ­ ý/éã‹T‘\Ö{˜'[‘6Ïoƒ6³‹'€£&‡Ì¹8‰%‡ôŠ{çUˆgÄæç…¥mïȇÅàB=¢aˆÎf‘˜e ‚@‡˜¸˜Ç;î¼°¹Qÿý_ÿ3ÉGcXy©ë:'S¿ò Ñ. OÉÂ.Ëš¢y}Â1}Ì¡¬À§ŒVxë.Ë^GÅÖÄäåD wÛ›+åòÒ[-,†ª×>%.ªuGÞoiâB¨âUáUî^®ù¦M"f…‹×ѵm¹7ﻪӋ”Qv[oôlLõ÷F,O òÈ­ßo¦æ22€/ !±1\Õ¢Cf¤w£ ½ZY>ù¯2÷á¹j• hóWÙw«îã]'Î}e“T™¥/Iœ~i’ÌU0gR­ ðXÕ´™ߢѬ…°-1‡oÔ í®@pQÅe*XŒ 'U’Ï‹¹ì`!ˆ¡Z•ë¥âÞU“Rò(.ÐbÕN°ÀfŒlW@ƒ€îO=áW(ÚAnT PGvxWõ›µâ„ªÊ@£¸;Õ¤ŠÌÉ:™…g@”Ñè»±Ó3" ȳÜýVÚÎÝèî„Ûã6Õ#˜å´@ö3bÏuqqdª/UFaçi'¿ÇœucVÚÀB“†°‘ÓŠ¢QF«î“6’˺ò,ÒÃ­Ê 5-ïí¯lˆPj" ¡dN*×Ó¾H{Ïݤ)‰ÙuÆDwŽ5azÔ„5OÏÍñÙ³Iì’x¯²H¢r¨)mŸ¥†yo’MÞˆf%ÓÙÊ•óÎZŸÙ>ŠjóHz dm‰HŽåI^£y/¯ÙÒdÒ¢Ug‘ŠøVäЖ¶-YˆzÛúŸek˜pˆïc¦i¶ ®‚1‡á#±´!òMª0*ëåõÆN}%G´ÆéWÿr¼ú%€VQŒ L³«.Í®À?/š  CÕ5ŒOãªêü4´-™ 2ÒÂôy­&eIYÓf·6“Гç•t%ëÂ7xŠôÒnû‘Ç`$x9þUÄ:\qªðö¼’ûávLî4< ìl‚/!%ˆ?ë6Ï7Y.,Œ&øþ8)ÌjÄrìý¯\›ØÆ ·!V³¿2ÊÂò@ˆ”ð1óÑ#Íð†(‡EÏ;³#vIîãά…ªƒsŠìÊ:ˆi[e’*”wê8V5"X ¦n±¥©ðÒHò“<½£¾ÐYd-Éž`gỽÂ)fôGˆA:×ô=•=ò¾¿ºÁ‹q›ÎBrõSaE/¦‰-kEBÌ6Áˆ/Õæ¯ t²ƒÃ7ÁTä$fyÇnݺɂ`ÞÞ "[ž)Y•þ\'ì|Ê™¨a[pNp¯)]CÔIZ«Êr« B[©0yÅÈD/î÷*ê¨'.o ›¢¤U7ÕžBàúÅ÷i=[™Ÿ×­ ¾ÿÕeó·2ùÌQõØðQ :J¸¦|¡Ñ+~PÀ¡˜ 5;ýM`í=fÄ+…Z Æ ¾Ö35É}óñŸ«¦WÂòÂùÖ¾éˆð¦üpX†€œ·Rìc>³_d„ðqõ~äÓGMhË ×瓲3³·C%’ðÖœ½ª\qa¯MPN„Sm“&Œ"ÚZ0]K¦î¤b­Å¦ÛëRw'¤]ÅVh.ºš+øt‹Z2¸×eæž9ØèdÅ¢”+}³iÜ(iµ0rîÚŠ–ÞC‘ÉmÌ+&4é7Ò‰y)þÎÞ[8%_"Žøxôïo4 ZkgC.¶wÍï"^LZÏ…#Ö¦®‘“ÃüÐ4»£$”zJgy£&-gö‚ãÂÌæŒ·É+þA»±{…ÅlQ8pnÊ-3oc«êÆ|O›¦p'~š0«Æ1KÌÅ{z”bã×§3Ýç{Ç4Ó<•r  L3ççxÃìvï'â6’ù«ùº‘RÉÞíò$’/VW{¦ =‹ë쨹Áaä;Éø’ÇùY_í÷@B’#“ )ö"oáiªGû¦­¶ÄªP>îXl[i7y-N|-©N¶Ç·Ðœáù¬Ö˜´å%BÒÞcÉÌ Þöû¢]O$ür5!Uðʘ€¨!†¡9¯óñø`@Ÿ`[LT§ mZ¿»£Ÿ»üs3—›dþ“ÛqJŠÕÏ´ôP7ƒ9F@—çH!ëe†ŸžI£Á@êVH¦+"±ì^9€üÈ-[ü´=A‚+}"л—ÜœŽúLs¢ ¾Fó¨íXoÛÀhäwcèTbÚ®¹âàóœD£‡£_<ª“&6¾Ê׫µ“2£ qø´SbeÎQÃØ”¢ ®˜h¼™R9šßØ­x”û8;Ù9wÕ†SO˜{Û(!+Üuzxø-‡Fuau[|Ãô5=_L:ù*s§¹Œæ•€ê/ç68Ïn>ê Úèä²Þ€(X2;« =O¤Ä@5Òb¨ùàô³ó¸«ô¦öœ.&'YG~dtÙ‚:öýdíáŒSñ LPß{ÂË‘W#ª-†3‘ì¢%{ŽßÅJœä|hëˆóžœìq=ºÓ6cLoÏڦ̜@0аð]Mð»b“‰¡0kÚ«g2”Ñ[$ïì²¾Ž›Î9—ó|Y¼êäHG‹õ¤ež†4äÏrš6]ëU;_Á"¾í•÷áù ÕzÄÐÖ]oÛf³b X;¾ Ä÷Ä¿€Õh·RÀ̬ÂS7$ õ¼TÔ”óm#÷ kô%-v>ê©oc>ÂR¢Zy9GìGÄÛD£~®°å19Û.Ô8&~ÓVÎE¼¨:XypJdd^'…ä‚^ˆV²8/&,д#Á×îÂ$$MÌÐ_¹0ÞKÓÂ=¾I¤d@5P ÅÁÐÇ3Á7l{ìZz”´ÆâØ–' EMOÛj¦9Õ@u]ÐÖT¾AvŸû&ÀÏ?EOÛ5¨!;õ„š<³'UÀÝVöCâÛ;®;Ûë£Q§?Q½ÌV çôv©5ÐYSAñè´á¯&ÊUCÙRBY¨•°˜©@ ¨\'æ4 „„.p=·æÐ{»lÕ¼@yJžsâ%ÃòQˆy‡˜øÙ(²¾8Ý·´£z2T‹øTÙ|yvénlœpNK&¢Uaz ÑIHD u¿Å¤ÞªO2BÏ‘ƒ>¶áŽšÁºjFÀ¡ÚXuøÊ3üd ¨Í:)_m¶Sa³î8!‘¯{ÉIZ¹Ã;w¦È›Iò­¼­Gƒ-!²ëølñ³6ŒÐ7\vþr×¾8ëk”ãéeUáKuˆ ”È„Ó1m¬ÙhûêºEƒ ¹705¦º‹Zào©Èr“ŽÑA×$ñh 9FSÙG†³¨êö~¤-Ê"¤‡ nAw>˜†HMæ83É4å#—®¤6 ±ùÒ5»QëUˆ~êmÕïþVˆÂ㮬 Ã|wþÈk?-p²Þk N (6å=bƒRá<¢¾è|%ž†òmõí“]?™&ÀñcS§•µ“h™Õ§\ýQ7\Ÿ˜,¶ÎZ6ŽŠg@#1­ö£:´b½yúÖ¤òQDpbNÔ[ä7U{·§‡À¼x»BŽWÒrРèz'ªIcÞL“¸YÕõß¿£Çšròpø§-€I‹LÓ×v•ºüY6·vë¡S|n—œCp!'Fcj´ÑañbBAnæJž}«†¿rÏ"Ú{*‚0ÇS ›nHÜPkf÷ÍâG× ¿Ç *žò;ýÿ •‘³îföbsLú|3·’YɘTˆÞ”²µ5…-™KØûî6ƒoë€'yÓiÁŸ®÷<æÀªŸ´[Œ "§XÕel§+% mG¡jvxœ¿]#qf'·VZ²V;ˆ’^튌Œ\Fû™·-%b€ ü÷ý$Z3Ð8#*î©»G[Ϻ)Mo®Ä>î˜z!Ëm%»6Ö\•w˪¹êÁ¥#z±ã7äv¾ÉèW²~ÓC¢ J«èîÉžN`Ú€x=7ðÛëtM„ê²± iÝ?$¾!áÚe”,¿D«ð‹v“ã-³êÏ`„¯©ãt‚O‹œ5t:’RÖú³Êxy¢ß‚º°AÄ”' ^„eÇ#†U§ $Ox̙ێ+!BN¶ëø9g\6Ükâ¹vß²îÉ3,FÓyLêHyÉŒÕè&W gN-óDNîëG«ÂCŸ,`âÌK-HÄ’üІ÷L·’9¡­¼R¥ù¾FMH⢦äkq™Å¸¯WDxÕâÔð]Éä´€*:’±ìŒØ BçŵmåÙûcá³Âq‹î"þDŠì]nÀ†œoæ®xw—ÈÈ­dfWŒ¨áöòU #‚—ãu!Û#o½[ù(©?̱}º¢•I#”ßb¨"1ˆaV¹žp?¦¹$hue[',Eþ¥^9\²ºPí·–“{Ý‘µŸŠ–æõr?±]/Z<8²m7âñuæŠVV>%ß[CUuԚ˛m÷äWi\Q,€+RnøIR«É>G­ú&óû /E6Ó`0f+^ÉšÚi[ÂS'ªÁQqk¹iN Ý::ö)ɧƒa³›”V­¼ªZ“­,ô;p$³#M!‰ñž'ø\/HÍá`HnŽxሳòãÔ’‰4±Bí5‘—„Ö€Àö8—å³Ó=‰XâŒKµl‡½IÆ·@øÅIJÛ†Ä!R҉آÑêTûÆ–NÃ5®ÑSæ o‚T30’ðŽû…"U•¦NåabD¾½•vèÑ·)I|L®S¾ýJÆa@+qFB> 'à‡uW³Á ®Œ’£ƒ;öåc¨ô–¡¹ß[xîºàÛæâqœ6·“(œ ¥PCçÝañ²œ‹Ÿ,5ïbæ¶qÛªÇ “·¸¼…È:`ºÙŽØü1¥^˜>ò1~"!†*°S™ óà_¾}ˆGc¸³¥oyÛʘT]˜YŸµ7€1w4k9ä²Ñž9ÊEܲþ¤†F¯•œ©ÎƵ;&›á|¡¼ä8÷œ£f}GÐÔð¬¢77 h*HÒãÄÇY—Sk4>ýE‰„K5ÅRa‹\oêDeÐÞã7˼¸st"Ü4sfÁ_ž «ã¸NƒÇTe÷­`·×/„Ø+·¼7²àßÓÎd‡æÊBP ºÑsòa®AΪ“‚LÃ~«=þċקh¥9 2µEÅ }dõ 0/Ž›¡âOïWÍ©•´d4µÌq­j­×#Kîý2û[™áT$Ça4Oñ†<ñ„jƒß›yéRí»I?e°ùÕVõꔵſ±VYDÌÜkz;š˜6›$ÀÉN´%~לq¶ùH€Ý”#?{¼Õê§œh¸ç‹7­N’"’[g'] ¸F*‡4¨žt‚»dÂ:6¡Âq\»Ò1бV`8Kãw}ë„ëÆtk™–Äã ’ºpÕ¦ Î@õ#ß}H}ICkøÅ ÇÓ¸Á.sb©ª˜2@}KNòibOè³rÅ/‘¾³À=‘qâ™]ǸF³dS”6'–@V©c­®€Èd4_XIf‹ø´¶•PÀ"˜‚ù íÓ¶üÿÁ(loš-.'4êÕ¯… f5®¿üVß¶²è긌Ñoâž*DKÞÚðßÓâSõ”L¯ž5æÑàÜÅ^¦ù@‘ãƒü.‘ù±ë«á‚lŠ“>"ÒS #ôþž?\NôÃ㼆RV\«Ò{+R½èˇN_wg*€êŸ@MÚ-ÄQ#­½:ÎÚ¥ò(¹UºÝÇ[ú ‡„ïìåäዲ´&niÒŠë·Í®8Æ@ì”S`âa•g ’™#Ì žq'»k4ãòÚd1’ôyÿ` ”Ñ ±€ÆÌ ºl?¯ØÛbóU7.'ñtzhk²»ê!ÐfEDuÓ²™ø.±ùK†±éQ/1â…et†ƒ$o_o=ÈmgµE—K"r•u‡}>@¾£š‹Xo19ÂîGøãà-(Äì‰rqÆØ¬¿ä&0 ,Tmž ¯nà—®+ÕõCÙD—1µÃkb15?<Ïè"Y8ç=Îi»þW€ù?R_bNöIEND®B`‚freeipa-3.3.4/install/ui/images/ipa-logo.png0000664000175000017500000000364712202434255020260 0ustar mkosekmkosek‰PNG  IHDR$žÑŠisRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ--ćzntEXtCommentCreated with GIMPWIDATXÃí˜[lT׆¿}9çÌÅŒÍÅãµ± Åå0n % " ©íC¥DÒŠ¨J©"õ)ªT5iK¤¦ŠŠZH¤4(IÔ)Ò$M‰RHÒ†›Á€1Çã ¶g<žÏ̹õ1u(§R•‡fK[GÚûHßúÿ³ö^KGø¾Ïç1$ŸÓøüø6Äg RäŸ~~zùç„ÆØ£+'4/k ïýðâ·_ùKÏ]‡º~½eë«€ñߺ&îT_ª®µ~ùÒÎ q'òdW,±"›Ë±5…‚¶ªâìs¬«{ÈîÔU,ÆN)-3wìü`cJNý~4_-TW¦( Kâ#´\´÷ßEeé¬ýæpËÏžz|ýÀ¾ýão(|~û¦õôte›ÒÉ6¦G.sïÊRFril;I¤H‘É¥9{!Á»Çª†— Í)Élýç;/o{}ÇÖX^½w'°ä´i3¬í¯ý顬.Ý<˜1›ÃW™¹Ä‚j—¢ˆEß`œ=l¤5‡ª²‹,¨K.ÌqîüüÛ×ÉÉzæ”ÚÇ‹Eß3O?Öt oÿ§Ôßœ\°~»óè|³/¥›´°"Öu 3˜dî¬ ™œË‘–iœhÀñcF†0T%%­½þâ³±©xöõsÛŸýÕŽ»s¼äùÍÈÂ/t>¼n¥9¯f®Ÿµ}市tz;ýjª>avU!º¢)bC.EÅž›áÈɹ\|©Â€‡ãúx>̪£E:ýÊ©ß2ªþf«@IÑ’§/HA¸qY³ö¾F"“JurÄé Äc­L)8LmM;ÅS²Ø¶¦åT/‡›ÈY"•Àó¤„Òws.—;S"žH5Ÿ~yå* ØcÁz4©,S ÏGÜËÞC‹I9u(12î-v,µ…À+¤9x´™€U@0TBØ+¢/–•ûß=ê/_ÏÆýJÕËBjŠBqžXßν)<é“Éz4·]älgZw.‹BYeá ÓÐ<ü@%…Å&霅TV0 *(zú3"ë ƒ–E@¥øá7®r_SŠWßJÐ|¡ŸŒ7D(˜F+’râ`iXx(Ò¹A¾\/ …$¾ €²FÓ´0 å;ž`Em«—'8ÙÇ ™'™Àq\”)ü‰Xmâ#‘©É: ì¬r:Ò ¥D#•– K§))áøq›ÉÓ†hˆäN%±D’ò²côÅ*I$—ÜY±/‚J¨BÒ ç$ɹ)„4‘ùuT©L´†E{¯¦¤D:/H,F««ªÇÊÅ|ŒqŽ•ˆMMM}Šs®³«ÒÒÒ2$‚‘x]pP=R-, 2L!qwm"61D$$?&;ÒÔÑ^rPm|a5F*ÃÅÂ7N(_rR>T/rƒfk|_˜¢’ZnL„“z_e[+~†x2>)&>atTCZ4=U-4K%4pepdqe4N#?W/Nd?^pQ< 0`sSYnLs„g‡–}h{[[mN8Q'`sT8 ¬³§p€dPdA¬®ª“““ÊÍÈfv[(@ÙÝ×€u9N*QVMhhg,;!dvW&4XfN(7xˆnm~a/ .D 3 J`;___®¸§!) w‡l8D/&/\oOª¬¨¢™pƒeÏÔË‘–ŽÉÊȘŸ”3H$ÜÝܨ°£ÅÇÄŒ™ƒª²¤ª´£¬µ¥sƒhs€j;S*ÅÌÀ±±±…”{n|e˜¤3OPNW_QXZWp€e[mMŸª˜k{`buT!9xˆm#8“ Š7788ÿÿÿ!ÿ NETSCAPE2.0!ù ÿ,žý ì7ÐF‚‚ò(%B …÷I¬Öɉ¿jBTèï@92´xø CBƒqÓÄoˆ¶~AP9IÐÄ7pk@q  ‰!ÆéöD’Âs\¼á·êÉ–"!€TRjÇ‚@„ zÊM~’LtPˆNO=v”‘ê‚Ô˜³­,¡òÇkF?^]ÑÏ K'üý *pÀ€³_ !ù ÿ, aÿ øo“!‚ÿñ² BfÃX)T—"¡n%X9¨ KŽÑî¡GÁ¿réþ]hQe 7ØÑa ¿„ ‚²'N….,É õóŸ—YŠ*MXÅRW–®Jò3 !ù ÿ, _ÿ ¨,ÑÀƒOäùðŸ¿6þõâaEÍ?'‚ÞÙb&Á?¾CÑ>p ùgGÈLjKvðzù9lB£2+ž€Y…) *IÊ´©À·1 !ù ÿ,kÿ ÈoÁƒù”°ð_¿‡&DJò¯Ú…4%„ 2 Ä{Õä'Ð óþ­£÷O“WhSƒ`$úUq OŸ‚"DH¢ÔÏËT rÇÏÃÑ+¼<*°†QªUw`͸k@!ù ÿ, bÿ øÏÁƒûuéa!A:&l­ø—`Ú¦„’êØXd"Ë¢@FЬI8#®Ž˜üS€æÌ¯ƒ±^äÄ–C„¡Úø'ÃÀÍ4RD°ááæ¿–,¨Ä(”v˜Œ ôÖo`@!ù ÿ, \ÿ ìÕK ÁƒÚòò/²~ÿY’öF 6î(¦Æ?3"yŒ(PÅ™=$zh˜ ¥@º@Ki‚‡ k\î¹…aD¹üg Ž¡>¶úÏ‹ ƒ!ù ÿ, jÿ x¢ A#æïŸ?„ÿ9 $0™¥U'Å¡ñŠ ÿˆù7c <SVÄÒF¥K”r9t)0 0F†u ù40Îñ˜É 7Cu8*0€> xÂùw#EFC÷Q}60 !ù ÿ, fÿ ü7ãËÀ~ ”!#D „ÿ&)üÄRˆ¨(LÅaÀD…oþÙùñß2 EH°*)ퟞF J¬TÇßGjVNL“æŸ.+œL|áŸ>¢(äWbA‡D>\™8bÄC!ù ÿ, uÿ ü§ÆÆÀƒûMšÃ!ÂÉÞüëÑÁáA*;ZYØÌÒƒWl¸ÑA=i²H:t”\Œ~ Çš%Pԃǎ$8(ÀÜ?A›þå‚A¢šÀ\^ýëƒàŸ8@<Ø Äó¯‚); h؃† Þt8K¤Ã€!ù ÿ, pÿ üG‡ßÀƒU@ÈðŸ ~Àº …0ІkÀ8PAŽ9 Ð…q–9S/:”ñÆ_41#ð‚°&6Ò8ù÷G„Šÿåòó/Ô{v‰P%Ì?V,Œúwe„˜ƒÌ~X¸'°ÃnX!ù ÿ, iÿ HðÁƒIYCÈC†üðÂpÎ$x,1 P Š[¡þÅ‚²Šá¡Y²‚@ ·.tÚˆÂÙ?CÌþÅˆÑÆ†@06üqMä¸Kx$ TÃ#RLBöü!ôĆG¯‡‹"C —ÿPøs .À`ò;ÃRÁ¤vˆÝA/0š$…7ÿd0ô—*Á€!ù ÿ, fÿ ø¯Z5‚«]p"°IV£X¶é_†Iþ‰Z!ð +ÁþPà ¶J´ac‘J|°u“ôÒ€ˆ,Xì½üÂ@+EÚé¯Ç8DÛXB%ð‹Ê½P°tè€;freeipa-3.3.4/install/ui/images/background-right.png0000664000175000017500000000621312270466515022004 0ustar mkosekmkosek‰PNG  IHDR ­/\å_ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF¶IDATxÚì™Á’ƒ0†’Øð}|ßNŸÍ³G&{éfÚnŒv)‘Ìôä7H‘îkÛ¶4ÏsJ)áÕÏᾜsH)á·õ–Vþê½/Âù ÕI¬à'‰û¾×I¬ÞÚ{_Æù‰UGxÊ=¼G .pOIä7†_Çj‰êð0MœsÇ1F¬ëš~îBDÃ0–eô}ÿRl¸Ýn ¢¢~º®Ëú•àBÈP)²ÄíCUé¼÷YZQÇo½·~4 hÌQ¥= ºGýŠAAD°Òl¥ÙJ³´ÃùáSAð¬›JA«ùÝÃM…™ÿ\öšªáŒl¹4t{¢GƒÕ‚B°ùà×QÃÀ/ñšÝž†™‹ß‚­ë5#\C*Îׂy}Í#är5Ü ‚Æð'—`—RýÂ.ø:£¡hèì5ü¡¡hˆ A!Ø>^ †YS ©éC°§¸æÉ4u±7ui >T ÖGÁ (QC˜ixœ4›*ö‚~lêuFÃíj:~jO!èǦ‚¬¶#4ЂÂ@ 4Ð@ 4Ð@ 4Ð@ß¿áä?A)IEND®B`‚freeipa-3.3.4/install/ui/images/ui-bg_flat_65_ffffff_40x100.png0000664000175000017500000000026212202434255023301 0ustar mkosekmkosek‰PNG  IHDR(dôdrzyIDAThíÎ1À ±Rÿž 7À(Èš™ùößœV‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X V‚•`%X Vj‹Ä)2×NIEND®B`‚freeipa-3.3.4/install/ui/images/facet-tab-on.png0000664000175000017500000000030012202434255020770 0ustar mkosekmkosek‰PNG  IHDRa˜ƒ\„sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÛ T¿}@IDATÓc`pÌeè:õ‘aÑ&†/_¾0100Ð3ðù10,¿ÕÅÌ`ûtÀÜÀ äÀà¾ðó]yoz»É¬gfîIEND®B`‚freeipa-3.3.4/install/ui/images/hover-tab.png0000664000175000017500000000167412202434255020436 0ustar mkosekmkosek‰PNG  IHDR)ôêCÒtEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp &JŒ0IDATxÚbøLÿþýc`b‚ÁB€&€ÎCæ~þü™içÎ ` TmÍ1+Ã¥IEND®B`‚freeipa-3.3.4/install/ui/images/search-background.png0000664000175000017500000000247612202434255022132 0ustar mkosekmkosek‰PNG  IHDR,¸A—VtEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp (:©²IDATxÚìZ[ƒ ÷? wÑ:m‡qDcLQÙý«•lXhÃ8ŽMe˜ç™~!„Ð@)ô žXµ§3žú,DfÙF«ô2—üIØu2x—}ㆹtiUœ0wçµk7Ž–ŸEàŽçNh”-ÂìÚÚ®å8–iäÅTh×L–úï‡a0ê[ô¨µßt ©¦å«fí¶eÉ:ò“nU%iÏ/˜«öí–—Ùyû¶míòG;qCE¤Ì‡Kuš–ÎnDѱšôV;Í¥YÞÅ2¿w’¹dÊ6Od+›æø(Î’Šˆ£LèŽFdë´a•Ä:Š]¯¦i² ¡× ‚Fx3ÇYø“#GõåžúªÙít‹ò(hQXâ"ÈpÚÝhŒÔgW¡ãµ87Ñ{ {n¦[>².fŒ‚§ù¹~¾‰ó÷•xëVÊ—î.Ó<šÛ ì÷¤Šþøsil|x)ïéË,*Sbw®+ÄÊ®²P—&¡L†4Oû™'ûu.SRÍ_h& Qߎ-ܱ%=k)^¹¡Â?(À­Ðb $@B@B   :|t)8A&áYRIEND®B`‚freeipa-3.3.4/install/ui/images/ui-icons_4ca300_256x240.png0000664000175000017500000001042112202434255022247 0ustar mkosekmkosek‰PNG  IHDRðØIJùíPLTEL¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢L¢™/g0NtRNS2P¿ƒ™."Tp@f`Í <BHJZ&0R,…4‡ÃjÉÏÇ8D½¹|«µ¥©­³(ýŸ$ï £b•¡¯lßF>n~‘hhÒHý…IDATxœí]bÛ¶ÉHªå„’-{iìZK:gó’lk×n­š-©ÓtI×õÞÿq€q? E²$ÛødK>$î>Á;”•ÊÈÈØPìZ…¢ØsÖV¯€h!˜Sy»„0E·0}H¹)-ðàæt k€íoÿܪKp”\RÎÏ  €ï.•E‹7¡¿ š)— *V;~ôPeÞâ Bx°*ò,=$z†¥Dؾ„í¢¬ úÅJ±½ÛïÒ¸Ù»¿„¶Ø9î{ ”‘‘‘‘‘‘±Ç¸ñHpÇqW@Äò"2'ðŸÛBúè[¥$ € @TàÕiºHÕ/äábÙ¥9ú6“!¡XãHq`DE¤Ç*RΖ€­ HV!Ÿ%ÙÚã…¢;ÐòÔðÁîÓá"¢ñúãò ÙiÆ]¿ ddddddddìëþÉÐ4yüµ5 ôô ‰Rb¹@(”8šÜÛCd‡öŪÐÝ¡¯,Ü@T@i¼ýÐb‰rq0alX!ô¶”ú° ¯p‰öeº, ëß=4bW ¼{¤ 5°­ÍƬhu~À(ÁQŠ^@ãó3Ú=î¢é"…bÿä5XC@J‘ޏC‡ª¤ú€Té®ï7¼ú6™‘‘‘‘‘‘q_±þ²Ô5à ©@,r šɩªDó«)°Tñ|žOœ…@å ON-Õ™ÊýÉ §÷¥’âýíò[n@ìØR¼¡™XôIm‹Ý‹(‰µá¡F Ê@”?±ð=0Þ puL‘˜;g$Òá@6η„ô „K`Êý>п» @h Õ£åüKV€nÅ"a¦"« ù%l‚@.v‰$/ðU^ôÖ GÈ:#`` ’ €u‚¬TtK©Þ~àÅ‹ÃZ Ýù5T¼¿‰%ÖkìõxÀ®ŸÉÈÈÈÈÈØkÜì]\*ìQÙÀ› ,Ò‡‹ÒëB†ª44 ÚOXKÍ|Šy‚Îgƒ¹Á+_M¤(ûlоEžO„ú V$ûT1BXõõ’b¢-Š|?@ ÔfóÕBßXràö%'@Ò¹A\ºI´á¹J,}†€BBcáó\V ñÊrÁ§£h(Ò]tIÈì^ªó¡}ÜÇÅoÎצo ¾S3ƒ ";£Ï÷Ê™ºìÑÁb}Ü"ß° —Ù){b$‘½¦¥ÆâãGwwݾŒŒŒŒŒ»ò–ßÈa‡œÞb"Þð)öïÓT@pš…F_er6JvШ¨áöÁ"mèÞ­¬M-ÁŸd7óê6”Ðx€¯¯„˰6Ó¥;Èì…/¯×ö“ìŒ`>KrP\Äö°_¸Ùë^uŒ1%“ÛOúT‚M²­è.±}¹–ðQ3æêñ€¶.Nسäã}«¡)½—ð>€÷ûäþ-âw`—ê—aƒø—ÿ+sy$ã€äÊt‡ø—)ÜN¬bFFFFÆýBeâ„jùúnNŠ¡Vn4ŒÕø,¹ÁA*õ™Xñâ*ÎÇ5«¤>ÙãP‹‡ªGæ…êa ¶ƒ3 Õõ{öoBˆ ‹&<ô”L[ §ÄÞNc.‹™­Ã¶Üi=Ã`ãQ@‰d‚¯µ ͆I¨Å.I«ëºlÀ`\tà[< èCit¡48Àù4É-rÀ Ž+ÀÌf³Øì‘±‚B€CB ÓÑMH i¤„Ÿôy }˜†Û>ÀÉÍrx¤ñ‰ÝýÄp|zø;BÀãÇ;áb±u¯‹rŒýŸc¨K¶Ÿú4t ôzÀ‘1†G~ ²þß`Ž†ØšÃùêKàÉ| Ì”>ú½Û¡²¯O$ÀØÿðìó~ ¶Ao)Š£¥0pzz ½}i´ý˜ûÓ`;ADÀ¹ÙûüÜm8n:ÁcfÚA@s7ºÁðŸ˜Lê÷ºÞ Z /..À»¨ð€êh8Ôoþ°r? Ú ÅNÇã9Œñ3BèÒ~o_ØÞ'`Àâo„€îpO-˜Ë :¸TGî L;ôÇ7ÇÝ]`ìÚ°B’€Ô%€Ë›>°î*wT´½îpMŸ©0HÝ}&t ¦ò·îÎ^1ˆÖ'Oqór'À2P«Í¡ª¦+Äz,tIW''|enÔþŒŒŒŒŒ=dzgñòRÌm˜[Nò¶Sùt÷K{›úÒ‰m²Ý娓Vžtû6¡ÉáÒ²R`úÔÑûšÎ¶NØ&}ÛöB Uå™(òr<ôqÈVyrÐrA**¿Ýدzg6ÓD#›± —–›óÑYP›`®ìîí¥áv‚Ïés€çÌ~(zûMlÞe¿|u¸ÌüQ¿a…*}ž+TŸÌ ²€ú“ºRÆùíX c"+*Ÿ NlôŸNûhc¿Ft‡ÀÛ—&àÅù‡ú¶¿Ô1%ØQ''ßê×?œlÚÃ׸•+&£r{ýj¸N‘಻® æ4ü) ÚËÃ`¨N狌€.½ Ûß­ˆ  ùüëÇ£Çÿü®•Üá—“§ôì)q ´2Ÿ?÷²ñýn¼3H€bÐÌø`ï}Ø ÷—­Âþ.`–ñõú§ìpqY1ûe_bûÕËïu÷7ùþe+NÍõ_Fö†¶Ý(êDTƒü,àÃÞL}LLžrûùmP5‹º|±x芥1Œc…ûŠx DAb ŒŒŒŒŒ`ˆ¦M(±ê7¼´ÐNEDï~žÏMzé Ðö+4ÆçÉBXd.ŽÃMzþËv͈ë¾µÓÏð¶«P×d8‰p¬ÿ<6?®Ø8ØN‘ý*xõêèÕ.»¾6Ú6G÷€­ìFåZû½ã…Å)ÝݦOéÉÉ ! ùlÅSsýÓÐh³èíæssàNðõp8Ú`'´0ö/<Æþš¤£s£ï©ß}ñ.æ@ǨÛsƒ7ξ§OÛŸVîDúú€a5ŸÏaŽvÜô]๘õúðÔm1™ø+ÝêŸÒ3äÃýyè6ðÛ õ‹ž>@ßu50ëÀPÚsÿÜÅ5‚¤1=Æë=§pý¢ *ÂKV•Ò«Ü‚Õã€ÝãøÝ»c$N®4(úX¹r2###c- ñê賟LóÓÙδÙ>޼]¯ûó5Ú.žsŸ´ÂYsÇ1ïÞf0Ã;ü'̨¦˜Yþg銛Â{“@9øà øÐÕ`aC(ލ=%bêoà2ÌÌ=­†Þnœò¤1ø jœ‡BŸ’o¨½S$nùãà#Ím“ݘú=iœê0ÁcÊÚï§ÝÈþÐÒÝi9Åö}ÔoI…Ù ¨Ýù®qãT‡š]òW%.Ãö‡(‰ËØ…æ]zÛ\ðx f³Ùö"]o°×'uÐ䫵tŠk{Àv;AëÍC3Ö†wž€w¨R_#÷±X» Þ(x§÷Ò‹/q%¶èùW¸ ¨þÅ›ÇÌÜhpíÄk_IöXŠùÇ'b§Éú/fXÞþ²Köi´"#####ã†QCL¼iÀˆ2téè àà€Ê5¬¶L0 ¶¬ÄêQiÞH“2;yÒTêOok;×¢ì Ù¶`õÃRš²Ng{z´y¼!—Kx²¢²·çmì?A(vø£UÒ~Œ°ÎmLÀ(`o/!nòÿ¤°mXŠ€-{ÀvûŽ÷[¾ € dÇw=Àn「ŒŒŒŒûøsdwåüzŽÖnê(åò}O®yŽ~­Ñó ãúmà ›ðï?XUÞ;,àš…V'+û €VŸ&ïJ¸Rê×Z]á§­§:£¥Ï×zC'ýÓ-߆ºžÝÈ@åy ö4¼­Úuó—þ §`VÛ“wö«ÑŠ#÷ýzP@Q˜ N>2/ÿý{¦\o)Žö”ëWøŒ›~a3xLÀw :_QÞ;Œì=pŠÖ¼èdt§Ãî\'8¸º¼ÂÝ~3áSRPÛ¡Ú6Æïõùy+ŸšÏÈÈÈÈXüù€”ÌQ­*¯ÚÞºr üù€”Ì—Ñ­*¯ÚÞºr gÐál™/¤\U^µ½uå$øóüœ|mbÃëVn–ÒÚòw \V½å|ù‡ÞöDËÍŠNVNåæþy‡À7ì¢ÚÙàëk<;œª/ËE}?E*dzgáO ú¨ß~ûègþœ/9¿®6˜Êæê½f c…D}% Š×g$õQî·Gž7öoŽ€)úº¡ÏU J¶ð˜˜o™,O@ú0ß¾Q(íòÀä;žbõ¹¬˜wõ“àÏ:5× úNŒwRÀåþN5ØIòöy'KË?}²¹:9‰mֽ߯®*§±í@fÝ@jU9m‡²ë†Ò«Ê´ÃÉ{öÿÓò$âØ——}öídF€âÿôp¿Ñ|%!DdF¸·>™ýû»}Gö€{ßÜ÷»@FFFFFFƦQÜžH ¹ ªÕºìÿí3 •Ðu øù¾Möo¸½·Ê~êvy»}¡mûwz<Ø7õ•ïnP9ørÆWkÿíñu= ©¯°|«ì_×n½ýëÞz쿳}@ÞþÛãIXÆn÷›‘±çø?Éæs&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = ui/images DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../version.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(appdir)" DATA = $(app_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ GETTEXT_DOMAIN = @GETTEXT_DOMAIN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ IPA_DATA_DIR = @IPA_DATA_DIR@ IPA_SYSCONF_DIR = @IPA_SYSCONF_DIR@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ MSGATTRIB = @MSGATTRIB@ MSGCMP = @MSGCMP@ MSGFMT = @MSGFMT@ MSGINIT = @MSGINIT@ MSGMERGE = @MSGMERGE@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ TX = @TX@ VERSION = @VERSION@ XGETTEXT = @XGETTEXT@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ am__leading_dot = @am__leading_dot@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ NULL = appdir = $(IPA_DATA_DIR)/ui/images app_DATA = \ add-icon.png \ arrow-collapsed.png \ arrow-expanded.png \ background-center.png \ background-left.png \ background-right.png \ caution-icon.png \ centered-background.png \ check-icon.png \ combobox-open.png \ facet-tab-off.png \ facet-tab-on.png \ firefox-icon.png \ hover-tab.png \ ie-icon.png \ ipa-banner.png \ ipa-logo.png \ mainnav-background.png \ mainnav-tab-off.png \ mainnav-tab-on.png \ modal-background.png \ nav-arrow.png \ outer-background.png \ panel-background.png \ remove-icon.png \ reset-icon.png \ search-background.png \ search-icon.png \ spinner-header.gif \ spinner-small.gif \ static-background.png \ subnav-background.png \ top-background.png \ ui-bg_flat_65_ffffff_40x100.png \ ui-bg_flat_8_225314_40x100.png \ ui-bg_glass_40_5e5e5e_1x400.png \ ui-bg_glass_55_1c1c1c_1x400.png \ ui-bg_highlight-hard_100_f9f9f9_1x100.png \ ui-bg_highlight-hard_40_aaaaaa_1x100.png \ ui-bg_highlight-soft_50_aaaaaa_1x100.png \ ui-bg_inset-hard_45_cd0a0a_1x100.png \ ui-bg_inset-hard_55_ffeb80_1x100.png \ ui-icons_222222_256x240.png \ ui-icons_4ca300_256x240.png \ ui-icons_bbbbbb_256x240.png \ ui-icons_ededed_256x240.png \ ui-icons_ffcf29_256x240.png \ ui-icons_ffffff_256x240.png \ update-icon.png \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ui/images/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign ui/images/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-appDATA: $(app_DATA) @$(NORMAL_INSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(appdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(appdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(appdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(appdir)" || exit $$?; \ done uninstall-appDATA: @$(NORMAL_UNINSTALL) @list='$(app_DATA)'; test -n "$(appdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(appdir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(DATA) installdirs: for dir in "$(DESTDIR)$(appdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-appDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-appDATA .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-appDATA \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am \ uninstall-appDATA # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: freeipa-3.3.4/install/ui/images/outer-background.png0000664000175000017500000000211212202434255022006 0ustar mkosekmkosek‰PNG  IHDR¡|4ptEXtSoftwareAdobe ImageReadyqÉe<"iTXtXML:com.adobe.xmp 9#nû¾IDATxÚÌTAƒ LÀ>¥¿èk}‡žJºH´È´Ž©ía'›@6!‚DWrDà*6Ç[b{5fÜ€»æIaIyí—¹®ÒæŠóºÇÀXÄtØëÊÜ¿8ƒGí#ùø V´~Òõº'ª¾¯Î*œëŒê§ý1fý)`Y4©ï{‘%?„ðyŽSŸ¼¹n‰£µ,{=óÜÿ2ƒw¹é®´jZï³Ìýuo-sn~‘hhÒHý_IDATxœí] cÛ¶ÉJZ¨˜¢ü˜gvÓ,Ù²&{?:-[3»éÒ®ëýÿŸ3âqÀáÔÓJŒO–¡Ãópî…tŸBý» €}6x9‰µs Sm–CÈÕXȸåñã”âÒÖäR<QήFæ ?SõûÊïœHf+&¹y÷tßSE-Gñàø8ë>ëA¦›mÙªdŠ¥ùì ~Z#îæ½sÝÕ¯6Ï'ìаfN›©„ Ô( ± 0%¸Ä#r(DXXK¦QƒL³^J›*´K•ÀÄʱzT˜²AÁ´°¶é~ÿyd-TLieóS«S(K€êň”< ëëbüÛœÖÌãE%NºÎÝÉS~×._¸òcØ$¿ÍQUb=+C±5¯®ì>W-»¬Z¨8BHÐÚŒŠØ—+$~ïªÇ«º+e¤ð¬ù9*9ÆÿJ*åVDúŸáoó•ÎãÇÈq—@º.ƒÖøiÿÎÌ ÀªÙo«Ãâv¦R~S˜ŠH¥6wß_vÁ cUË‚5–y—@~÷RתÍ#ÑJ9ìì"þ!ꎾùJË:Îd•$‡. Ä3@nVewä%™wã>#—ÐvÀåçÎSÆçvó ᤵ§ Ê»#,eõ¶]T qý/Éà–|¿cßÛä÷˜€Õ©bžfppëß‹bH1F—ÀS Ês¬” L…Õ(?"ƒ£ºªÛ#Y¯‹‹ÐP£)óüC6C\$V-šA´Î$ÒÖÒbœ ö߀3ÀR4˜×mô˜ñ¸`G\›°¸“¾~¯ c:C.Ðå—Uèaž¤çsýuC]7<e7,¼¼4 §ÚÒÉßʯÖUÕÄWœ§-™úÍC¿ôÈv7¢ÃuT{%*¿´9ùÒ"Ïå¿V„ìÓzþáOÄFœ‡U¹8áÑŒ)Y~¼+à%âX­4ïSTaWDÝSWÓÈeju•^ÓÑ“IïÍMg/_M½oe"Ù&ª~m ƒ'â súO“ˆÓW’7ô-…³à×;…3áxõfö’7y£rˆÔ#C¹ä+9ckM].õ8qYŒd#R½ñ`ý¿¯Ù÷ªçkaU^k¦„ö#ü/P?*u®$Æ~²Ïã÷HY‚å¶ê‹52ƒÖŸ·æà€ß^|æÚ‚ùÐðbÛ{|aÁ,?k¾€E/vÅÀƒ…kL¶Ì?Ù£o=;d×xlØÀEÎ{¿øA:?aM2¿$Gq†B+•h‡C>te_O8Á±ðÀdø¨0wPl¶E`À õAAÉ‚ÇÃ[é.ŸÀš‘zdµaVÄ€Ó#Oä4&óêÓkô?ÓèüÆV¶€ýâ Œòø`]€Ù’Pª#N†J7YbeÇ7Ž,H[èF¨2¶4eYª»éS¹Û‰|¡B&µ]KîRë‹Ë¥Ŷ ATôSãÍ6?šîh{ëýÁ´9³Ç ÷"Á\®ïv¸¾ÊÀr9U{„qívªk±¾¨ï‹/¾0‚WàÂ+?£ëçÚq°"GW˨ššå`wͤûëW¿Aãá»ççFæ-Í`aÓë«e«]n"ЙbMB]¼p+5¥Þ¿œý 3œG]SÃŽ.1Yax©Ë)ñÞÈÕ[üå»<¢¾¤+è>òÇ sm¿ßèTÖ؆*³sÉ´òÄ,KÛ¶°\ªˆõÛij`eàßrY¾ÂÊ9yaÚЩ ¨L£|Ïž)L[° T7G£¦êÿÀ·÷RüÀõP¾PºŽ$ä­/0Ý£ù*vSûÜtWF¦¼CEÃÛæ»/2:Ñ•htðL”Ð?Õ8;>l ôfYd„Þüà6É©ØÜ}{Zi÷ìŒuk ÑÞDŸ›òJÓŸüÑñ£S\^z L,uFºüt¼ËKyh‚õ}jãÙdrf$åÍ3ÜŸëˆ×:Cd š.—ÆUÁ•Ù½{ÝA¥¯ojRN„ ¥ç°„”ÑŸQ ìSŒ¿€±/]¾ÍVT—Ÿq _×G•Êã9ÀsE$Zw¸Ïóa×ÎÍÛFUŠH#¿úÕ e GÔæ1üZw¢ÝV7>–naÓO[ÛÍ+Ê€ÁÉï¿4ŠHFª›^® ׆–ôûÆO¯Nf½°½ÃTpzaúð Æ€V@O//¿òÐSíÏ]SÝÏ«wx¿TnÛÚªZGã#Nþ"ÙÀ¿Ía]sµŠÕœè¶öX7 Ë`Æý£ÖñúG{vìøÂ´…é?¾V®é´W_ÁÎFYÍ©i+ÊU'‘óÞ4 V³â ¤Ð7âÐ%yT`뇪rãí¡Xùf©OŸÝÎoå¤@Ao>Wû ãn2¥K*ÝfǦM÷æÉh:«7 5ÅMú+иy„Nöì<ÊP LonØÉ> h:Ç™vÞI~…9é畺K 5fº d˜çÄ·cÎöß=ž8£¥983«¹K4jðv°îÿ¦yÀi¥|@v0cN…ƒÌöûïÙ›µ©Æv+Ì©1†WšÒå»rJÛÍ<=Qm´ã[=áÑî(–A3LÀ¦ÝJÕàLá…X ÌÈH˦ÉÁ6:Õ­¡ziJýc¦'”ÿf&‰éLÛÝt™œÍÌv}1Ãî5Ó Ì|…ÃÆ%›Û¶%à2ÐñïoCÀ–m ãÞñ_xª\€íÞc´)VÿaF³3p[›‘<ºo'ý av}fµPKœ‡“ @täâxfjÄ8 ~?|hØpPŒÀ'Þ222:¶^vß2ƒ`vÜ{'`ƒÛý ð ‚^}9@#pŠÇïÏ=ò,'°@Hš C~XHÆÊƒU0|ËbO∀|cÉû¯Ðp =‘ôkcÛ ö›¾w*##ã¡£à“7ÑK>‰ÜoǽÐ$\ÐùØ…ÆÏFåF‹OÎ"v™—½ „Ãÿp”30ì€F§z8L€&2pG‡>½ã0V~XƒQÁÁƒO²ø¬~‚¯!Eð ´°› 0t$ÚÈ{Š ‚Ãüü F0Ž{FÎ「Œ{íÁ™bZ),\¦(<»`€ãÀ0óéo°ŒÞ¾%Œ•JÞÀVA=÷ÿ#J֟߆ ÷™L 4‚ˆ»”žlO /Ü«b· õ‰(X€‰´&€°…ìÜ®ù™`žÝXÇZòwô›222Žá»Ö>*Dg¾â)ƒ Ÿÿñç0‡ݱÜ…Ø*²ouJ(=³äÙMé–^ 8IV },­f„‚øþ…>­+!¾>•?š †º@´½“øeüjBä—D8òþpOÏagd|PÇT®qòÎgò$ÑÏöÇ8iš)Ñsö0,C~\ :UÖVš6‡çU¸ \Åé`ò77áæ`V1©å„õÄc@f„N/ƒÉªÇ¿fž—ˆPʃV]*hš¢ÔÀ ºëá—w.‘è—¢ƒ{7ºiHëu}Âñ¹Jn3œÀéÅüç@ veõåõì±b¾dõ?wáPú…‚yÈWáË‚¬ÁÅÅEºÀrÙµ¢©yI¼*¸RV2~EðT¦~ú=Nåéµ8eÕ! *{è,Fð-¹ï¡ð :.Y´Ág (øÄ^!.€j©€4È^6ïŠÔµí5–o úB}|~ú[ ×]®;CUµ [¼RÚ)€‘Ña«ÑT>ó7ã¡áË/{ƒKy&©ÍϤÍ{QOÎyÔ)‘Å#«Ã¢½¯rþÏ~Žéa!Á&W¾«ëz ZÏÔ졽Tä¥í×¥çºRôÊÒ¥_»s›ü]4"À‰€oEäÀDçAwUºTÝ8ŒHª¾¹‘vÕÒo%sn\Hœy$È´þ­h‹•zàå4q½R¸ð“;yu5:??÷@§V'.žvlc•l77Ýìœ^ÏÚçWì¾ ¼”£Qg÷¹ÍZ-&…5Ý_éDžƒ?çè1Eù›‘©ˆB¢ÀT¢ç ÞNïîN ÙžÈqJ‰/ { ^Ùbý!#ÃÇ{ çÌ~‡Mî»{äè°x/-Jàƒînòÿƒ)Á˜Qlœjk=%ñà4¨¸×6ôÝ} »þÒt¾÷ ÷yX°“»è3KÈŠ7D·:««mÙÒõï»ß{쇀«0-¼Ÿ2ÛTU÷LÛÖPĆïñX@ é׎|M#±D„ð«/vÐzäXÞýpŸ<Ñ %#ãÓÌØìÄ_%Ý=òéÆ/­9ä(@C@…à À„YM¯¸kfÀ#Ø-rÌ@ÃC›Ê­d8äaG‡@ªÆŒ< Üø@éÞ»@Fƃǃ~?lÙÍládžÜ/¬›wl‘TõÒÂL•ÒdžR¾nñÇF¼¢·“WbæßA%‹ª“óI÷gשáÎ齤Á§'ò39RÍ^ê÷MRèV±òÖ¡‰¾ÖÀUÙué£C ðêÅ+ÚæÕ0 iÈ=§ÈYSŸø}€!úéÛÍèuËÛ–¿ð,V/B»5ôНÂï, œÉð.üC²|½árù”…û´ÎÂÝ×è»¶ Z^;ûÒ0p&ã“h"âñÁ?ÈÀo‚–7~olÂap,l¹r_UšáaÚÏÏFH\¬´€zhýŽ»±à÷†è+G_mB¯[Þ¶ôðûCôÕ·’þöjSzÝò¶¥322`tÆÞ裇œ«Óé:øûò„žÏ{ýô¹ÀãGÀCïû@ÿ{EŽ …:­\ÓåÕý¨^œâ ü?*;Û¢9€/€B½Ao_üîÛ @Ç”þˆ[@ ý] Qýµl u§ùf;þúŠs èåIEND®B`‚freeipa-3.3.4/install/ui/images/caution-icon.png0000664000175000017500000000076012202434255021132 0ustar mkosekmkosek‰PNG  IHDR&/œŠtEXtSoftwareAdobe ImageReadyqÉe<’IDATxÚœR¿OÂ@¾k¯-7'cŒÆÕ †ÝÁ¸éÂà` “3‹#îNÆÿ@âì@4N‚QHˆ(PÚm½^½; ¢¾äë{y?¾÷îKëº`Z•Tb\adwòa­0_Ó_¢É¥SK›tm=ŒõâfôO¶ž£›1ÁÈe0J³e³q‰~MÐ|ZÏÒÍ®c8X¬b‡?õ `ÈÌ÷L\Pž—¡ˆÁ‹‘ZNv^"Ãý¿IVã"-…š€|(@A>íê|,Y=Ù•ê´ëˆtHË!µ¾Ú*ï-ùg ‚šQ¿"µÄ£ÔB4 F™m„oÂ3w+€Ëçi!íZ:% ;D°üí|?DÉŽå®×é˜ÈfûäïψÙ2~ ‡þLNw«,ï“i¨ Ê (Þm’Èq®¸-¶;m@á`Y€E‚Е‹ù U°{Ð×€>UeŠ€çïĞȌÕñ¼Ív2OgI€“y>?l®Ïs?š;‚£HžûIEND®B`‚freeipa-3.3.4/install/ui/images/background-center.png0000664000175000017500000000542712270466515022155 0ustar mkosekmkosek‰PNG  IHDR­×¼¨ pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅFBIDATxÚìÏÁ 1ÁÅ@ÿ5¤8ê £ˆHÇg´~šîn¼Â9ªª•™|Dr÷A2³)`æK?–eY–åÇÜ« 2ž‡ÝøIEND®B`‚freeipa-3.3.4/install/ui/images/ie-icon.png0000664000175000017500000001222112202434255020060 0ustar mkosekmkosek‰PNG  IHDR22?ˆ±tEXtSoftwareAdobe ImageReadyqÉe<3IDATxÚÜZi”UÕ™Ýw|sÍUTS1ˆ¨…(¢DTD!†à8Ûfa4¦W;“ØvLLÌ Yj§í¨I/cM4ΊšÑh$ ˆUÌUÔüæáŽ½Ï½·Ê—bÓù‘î·ÖWï¾;œûíóMû;§$×uñÿᣊ?’$ý_ÐU‘$HŽ‹<ÛùGýT…¥±Ÿ9A[¼è$}î¨:yLuDª$)YpÓËÖš¯ßù\á»E }ž1„kýƒYDš1Z9÷k‹Â×ÛªQפTB¥~4ƒg 4 žx¡ðÆÅ÷åóWòï D’«åpb¤¯ž ÄkRc•MªŠˆ+Žmf>ÝmgûÛ­\ÿv;—Þ ÇìT£Ç tÖTmñ-‹#_s¬z’V)+0yIHšú)&@®ïhÇèXüýìMÏ®1îRÿÊ«UM³cã¦_Z;iúܪšºZ5U-ÄKòÐ$‰œâ:6Û„]*:™Ô@ºkûæ5É­ë~=Aß¾û/Åî<ëäÐ,è¼±èP¨øjžµ}Åù1ó.r%"Á¢ñž6`Æ8eî³kðÈßDÑFEƶ^Û4㜥ÕÍcõp”~êÀqï²C¥©y0ßþ”ó¾ 5•ÃZuÕñ#ÇÌ»êmÞåã3®– b›÷g¨ü6j›á±ì ÏÃ5{œÂoÖÛ›_ßmoN–Щʨ¼¡U9óÛgH[4wG®Vÿ DZZoh>yÑWkF«UÄû©€ešp©$èßBsig,GBÁP1¯e ¾9sš+;9)tø¼P:‹¼µ„ý˜O¼Ž{Þ6_nOº/p€Õ”žAW¼õ-ëœÏ—_Êä%1sö'"ÅëÎqê÷œ6kšL­lË‚- Å)rˆ! Åž8Ê*õ"nšó.9î  NFضfhÆ" Z Ëúfã[OïÜøáÖ-_àcë¡Î©äXÛûåNìG D­ÍØùKﯮbÜúd>.Q”ŒøÆ Ù`I˜ָw.| SÆlJ ?ˆ7õ2 "bá½þ)¸»c!>(4£îŒôô”ô‡Ë»¶ü…7£0\Ÿ0PYQ!ém[ÝÍüÙ{D@ÂãgÞÙrÖe·„ÔJVË@h¾%Ĺ!J` %[ ãÊSÖâ¦/ Mùf`ÓÅÍa@­Á½;?gz§3,L$ä,ºŒYç^tã‡ÕÕÇl^ùÒel \§qqŒË…eü¹Í|ëˆ ¢>¦õö–y—ߢiLŒƒ$@ó“ËD‚騌o·Ÿ¿WÍ~Í¿§ØlÞKoïây¬ê<ßÙöylÉÖ£ZNB.ËçL& Õ6pÜÌ9 d£ôëMk_ûÕÉ êuÚX¹õ•îž¾Œ³öcÈ5c—Žž{ù¿Êt„¢ûÊÈÚHâ;°Hµ"àE4æ õ ?]ò NŸ$ÞUÇLÄ+Û™3‹p¢*þcë5xpÏÙ`uFEˆ:::Ó³bˆ©d‰œ‹iSN\XìïþiÛŽ× {ëDuæ²6ç9vˆ;¥ñÌ+îÑCaɲBÕƒ VºçV.ERüó¦+!R¡‡+°à(_<é8ºA¸ðxÆóèî |&…œÖŒ¯¿÷Ox®ûdT(„儽âç0þ¬‚ ¥Àoº±C«È0pÂñ³¯M&»×ö t?V1!ïH£^ÞlÝ64釀¯œ¹äçñºÆ¨!2oãÐp¨¬C®‚£†¼o—VçЖæjHÕõ9¦wÌÿ9AìäP³‚©µû}†§‰•ɰdݱI?uqËKŽ¤Ã²˜–ó6ò¬#…¼…1BpU”èr<†SgŸ}Ëáäs&)ó×îs66þ|XÒ¨ÔŒýBÕ„Öã,ÀëYÀŸqaI¸—â[c0ÐE1¬p xsc'¦LJãù/ ª°`݈rëO½Xc\¹öR-'ËR•¾“j* Á¤ûSp²œ’Ë`W Hâ=ŽÇB\º­«Z(JjGK=µõ°V•žßè<$êîPz?×jªšwýڪѓšÁ+8ë’fhÐô:Y´&¦’ª±–EPܱ »VnÄÂó€GoÛ‡ ] s>_ó3Ô2/1üø;»Û¿uwç¶šˆK£YâN<ûTÉŒê uÕˆŽžLÚÂI³Š­TÙ„®Yt9 JÐíú¤(÷cïŸÎÁîW^ɰéŽ6h uÐj«¡ Ø´¼Eo0)E‰B·.Òå2œßÊQ“iniÊ¡-¢èÓJ±S{ûÇ¢bª—™c#á@ ¦ØKbîc÷èaE‹sR. @1a­á@¤¡fˆ"ózn ì8nœó®šNÅ¥¹ÙOt3¸Õ4~²ùkxp×gQcÁbŠtÍ ­•}+xciÑlK¾›‰ëCʉíYÇõ$v‘X„‹Ã+¾µ¼{<ËHòÁ‚]L‹5D"‚Ùã÷àÇóçãuÉdw“ *Ýxx×q{ûõHÄèØs?Ó!ùs]ß²ÏÔ©XÄ'ÎC=|àr®íƒplÛAû©-c’c°Â;žud¯¯q½þ†— L€¦5̃)ÀÈeøò¦!‰~œ¤­6jâá%ÿŪ.5öúíŒâüeß|kÃEhn*¢¶JcÝ¡—Q¹_¡c´~”Æ«¨dza2¬âõ˜„ƒŸÈHáe ˜”’ f|¤(É’ƒ\ÁB6[@.C>A!É¢˜Ž¢Ô‚±/œ¶w;`»$Lw}c>êP™MtÜîã˜XßÎ_õÀ^ÞØoÂ…×öttvÍÛ§77ÈûX@e‘R…[(~Њø’5Qkü­òš¢ˆ\, 0"ÝŠÉVa¼ˆß–ëŸw±°âzçEFq礒²³¯-ƒ|ÇÏùø‡â çFæ¿3¼î?MÎÒeǯÃÅSß&ƒ¥oˆÒ¼­.ûR÷ý؇[ÛP|g‰ÑÞÆ6è-Á‘|¬ƒõå‡ùˆ90MQr}+Ù‘}YÒª8K9Ü5÷f'Û§ìëw³Jeñ{±2ÜŠú«¿yZÏ÷– §¸â·<­Õª-']+«‘Êòà÷³šãU×_'#¯aAhšz¶ˆY\…tW·«i€)á®9¯¢1ÒK?cÝÆÞ /ËàaóÏßõ9³aœóÏRÏ|Wð“οu­2¾èúyã½—H¢è³,Ù´ ,Fºf’’ê…•îƒKyœËÙðÒ|÷ƒ—Ï+·ÊpwhîÕ+`(X0v®8ŽýD‰–Hòþ­ûÑaµàÆìˆ0i—§›®¾}JÝy7=éWÇO¾­Q{þµLºõîKÄ ±¬(‰XSHU9@f>‘Û%‘6YÔCãžj…Në§¿-zMoÕïõ ÚŠ›“7£Ç®`V2üPŽ[Ê2-ýÑ)Gýó®P‹q„±"%êg{˽œö£Ÿ-õÒ¿pkÄ®Yôh‰GO 3¯{î%ÎulZ6|yèÀV×1_]zfMëw–—øÛ¨iÏ;gãÅÒ‰¨RÈ«¬j¸´”•<r U\7éŒç=[ö«W6<ÿø#¹Ý¬ Åè*oGÉ 5Ž?yÒ¹‹??þêë/²¦MŒíïµ$Xsƒåbº§¼Qð€8TÞôYT÷öUîÀÞǘ˜á­nD“Ƽ_嚉GGê‘ ·ÓH“ÌÏî¾ݱñˆVV@‹ˆ£ÕÙÓÏD±S+HÖÆ-‚ÆõäQ³wko¶½mOa ?É™v¤DE¼v¸‘-ÇŒ”š*¤.zL6Mó1_Ù%߃ÌõÎ’ù¦ú)}Œ‹^Ö›6{';kùÏnC®ÿ{Ýz+ÿÌ?^½jâ­Þ³óû¹TÀØàµ™Ô©IÈEaVÙ¢Á’SÁ:Q!è¢d,:j .'¢è;az]å©Óë*Ô`ݗõqR Âå³>ÁàEQtÛå5¶ätW6NŬ'•·K9Ï­EpÖ¿ðAüÄÇnO6V矬τ Þ]>©|a‹Ý±?àÝe¿o72¿œ:÷¢Éµœ}Kû" >Nµâ²‹K9þ´–È#q²Æ(A°UÖÄüN¾;‰X° a `À2³)*Ÿa|d&Ù GÉ¢KzV=ŸJ-ÿå7ˆþ#Úg÷³FnPÁFû-ïÍ¿Zo-ç%‘B»z7¾yá{}û~8å¤ù ›šÇI²î2S…¡ê´#¶”+À2©T½Ž'ˆ(¢0[SÍ[VÛ€–h¶ØÓ:†pS¦Wv—²‘G˜Ç¢m“H÷]>“ܳ½¯ÿv}aãkßæ»_<âE,¢K 1]ŠøÔHç\¼»ß}½ìÞM©Îö+V/ûÅW¦wÚõSgÌÑÐLe pfÙO›ô‹9¿ÄJiXrˆLG‡I³ˆõc¯}TW´¯‚jð[,R‹íZ±óœÏfÑ»nEn`Åú™ÞŸðÔ¶OôŸ¾'‹e ø{tèdÁ5³†»}ØýIÛ2nßðîò—·o[wõ”O[ÐzÂñ#k›G©6éDnQd“ØÛËJ˜TƒÝ³Xºa°XŽìYElOضä]xÛw¹Þ.$7¯Ê ¬~îMkÏÆ_¯†¿O ÄÌÜdªèkjä0b2ŽÆÆ(\,p?[%ìªuûÿдóÙÚ÷·½:+S=Y{ô1õÍŽÑCµÃ ƈXre×'‰xÒ=æâ0êmÓF‰]žD0³c£“Ù¶6•ûpÕfg CXÿOboÒÐzñ¯Å”UÖ_âp•½òŽ Ão|{iüxtñ™ E<ù®ùΦíöJ›“ɉ ×TJ5ÍuJ£‘G½×çV¾¾Óé|c§½Vl*óù‘¡H´¹fĨ†hu]¥cO­Ð=*‹- Æ‘kä³›P£˜êÍ];úœtO÷` ŠÊUÖ—dƒeU±ÔÓH28oÿ?”(Š®àÒGoˆßÁÜP%˜ÑÃgöŠrìxmÕý]››þýVûýõÝ®XVÜ  È¢êïSzÌ4œWwÙÚ](«¬Q²ƒßæ°ûA‰­i23oÒ°Î\‹­öüZ”¥³&j“›âR¸'í”6uؽ»ܶ¶ç=ÓrÛ‚…â‘2eÕàœT¶#]~|°S&Ö0 ¥2÷Ê€òGd‘¿ZãòtïÛ f!¼Pf]÷„@ ÀûÓC2PÙÊœ2k”ƒ1ËbÃ.{Æý¸ùÄÝ0E¥#´B9 w˜rîá”=Ü甽¤ÔÜþIEND®B`‚freeipa-3.3.4/install/ui/ie.css0000664000175000017500000000060512202434255015674 0ustar mkosekmkosek/* Authors: * Petr Vobornik * * 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; }freeipa-3.3.4/install/ui/ipa.css0000664000175000017500000007367312271663206016075 0ustar mkosekmkosek /* Authors: * Pavel Zuna * Adam Young * Endi Sukma Dewata * Kyle Baker * Petr Vobornik * * Copyright (C) 2010 Red Hat */ @font-face { font-family: 'Overpass'; src: url('overpass_regular-web.eot'); src: url('overpass_regular-web.eot?#iefix') format('eot'), url('overpass_regular-web.woff') format('woff'), url('overpass_regular-web.ttf') format('truetype'), url('overpass_regular-web.svg#webfontLTZe4IYH') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'Overpass Bold'; src: url('overpass_bold-web.eot'); src: url('overpass_bold-web.eot?#iefix') format('eot'), url('overpass_bold-web.woff') format('woff'), url('overpass_bold-web.ttf') format('truetype'), url('overpass_bold-web.svg#webfontzAU82Ltw') format('svg'); font-weight: bold; font-style: normal; } html { height: 100%; } body { overflow: auto; position: relative; background: url(images/outer-background.png); background-repeat: repeat-x; background-position: left top; background-color: #FFFFFF; border-width: 0; font-family: "Liberation Sans",Arial,Sans; font-size: 11px; margin: 0; padding: 0; height: 100%; } .network-activity-indicator { visibility: hidden; width: 16px; height: 16px; line-height: 16px; margin: 5px 3px; display: inline-block; } /* ---- Container ---- */ .app-container { position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 960px; margin: 0 auto 0; } /* ---- Background ---- */ .background-header { position: absolute; top: 0; left: 0; right: 0; height: 34px; background: url(images/top-background.png) #0C3B00; } .background-navigation { position: absolute; top: 34px; left: 0; right: 0; height: 72px; background: url(images/mainnav-background.png); } .background-left { position: absolute; top: 106px; left: 0; width: 10px; bottom: 0; background: url(images/background-left.png); background-repeat: no-repeat; } .background-center { position: absolute; top: 106px; left: 10px; right: 10px; bottom: 0; background: url(images/background-center.png); background-repeat: repeat-x; } .background-right { position: absolute; top: 106px; right: 0; width: 10px; bottom: 0; background: url(images/background-right.png); background-repeat: no-repeat; } .icon { display: inline-block; height: 16px; width: 16px; vertical-align: middle; } .combobox-icon { background: url(images/combobox-open.png); } .expanded-icon { background: url(images/arrow-expanded.png); } .collapsed-icon { background: url(images/arrow-collapsed.png); } .search-icon { background: url(images/search-icon.png) no-repeat; } .add-icon { background: url(images/add-icon.png); margin: -4px 0 0 1px; } .remove-icon { background: url(images/remove-icon.png); margin: -4px 0 0 1px; } .update-icon { background: url(images/update-icon.png); margin: -4px 0 0 1px; } .reset-icon { background: url(images/reset-icon.png); margin: -4px 0 0 1px; } .enabled-icon { background-image: url(images/ui-icons_222222_256x240.png); background-position: -64px -144px; margin: -4px 0 0 1px; } .disabled-icon { background-image: url(images/ui-icons_bbbbbb_256x240.png); background-position: -64px -128px; margin: -4px 0 0 1px; } .ipa-icon { font-size: 0.7em; padding-right: 0.3em; } .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error { font-weight: bold; padding: 0.2em; } /* ---- Header ---- */ .header { position: absolute; top: 0; left: 6px; right: 6px; height: 34px; background: transparent; } .header a { text-decoration: none; } .header a:link { text-decoration: none; color: white; } .header a:visited { text-decoration: none; color: white; } .header span.header-logo { padding-left: 2em; } .header span.header-logo a img { border: 0; } /* ---- Password expiration */ .header-passwordexpires { margin-right: 30px; color: red; font-weight: bold; } .header-passwordexpires a { font-weight: bold; } /* ---- Logged-in As ---- */ .header-right { float: right; } .header-loggedinas { line-height: 34px; color: #fff; } .header-loggedinas .login { font-weight: bold; } /* ---- Notification area ---- */ .notification-area { position: absolute; top: 40px; left: 380px; right: 380px; line-height: 1.5em; z-index: 20; padding: 4px; font-weight: bold; text-align: center; word-wrap: break-word; } /* ---- Navigation ---- */ .navigation { position: absolute; top: 34px; left: 6px; right: 6px; height: 102px; } .navigation ul { list-style-type: none; } .navigation .submenu li { float: left; position: relative; list-style: none; white-space:nowrap; } /* .navigation.tabs-3 { height: 150px; }*/ .submenu { width: 100%; /* min-height: 4em; background: transparent;*/ } /* ---- Navigation level 1 ---- */ .menu-level-1 > ul { height: 38px; padding: 34px 0 0; margin: 0; /* border: none;*/ } .menu-level-1 > ul > li { height: 36px; padding: 0 18px; border: 1px solid #A0A0A0; border-bottom:none; background-image: url(images/mainnav-tab-off.png); margin: 0 0.4em 0 0; text-align: center; vertical-align:baseline; } .menu-level-1 > ul > li.ui-state-hover, .menu-level-1 > ul > li:hover { background: url(images/hover-tab.png); } .menu-level-1 > ul > li.selected { padding-bottom: 1px; background-image: url(images/mainnav-tab-on.png); } .menu-level-1 > ul > li > a { font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif; min-width: 5em; line-height: 38px; color: #858585; margin: 0 auto; text-align:center; font-size:1.5em; text-shadow: 1px 1px 0 #FFFFFF; } .menu-level-1 > ul > li.selected > a { color: #1e5e05; } /* ---- Navigation level 2 ---- */ .menu-level-2 { display: block; border-width: 0; padding: 0 0 0 0; background-color: transparent; } .menu-level-2 > ul { padding: 5px 24px 1px; margin: 0; height: 25px; } .menu-level-2 > ul > li { width: auto; margin: 0; color: white; padding-top: 3px; } .menu-level-2 > ul > li.selected { background: url(images/nav-arrow.png) no-repeat scroll center 2.1em transparent !important; height: 31px; border: none; margin: 0; } .menu-level-2 > ul > li > a { width:auto; padding: 0.3em 0.8em ; -moz-border-radius: 2em !important; -webkit-border-radius: 2em !important; border-radius: 2em !important; color: #333333; font-size: 1em; font-family: "Liberation Sans", Arial, Sans; margin: 0 0.3em; } .menu-level-2 > ul > li.selected > a, .menu-level-2 > ul > li > a:hover { background-color:#EEEEEE; color: #164304; text-shadow: 1px 1px 0 #FFFFFF; } /* ---- Navigation level 3 ---- */ .menu-level-3 { height: 28px; } .menu-level-3 > ul { padding: 0 22px 0.1em; } .menu-level-3 > ul > li { margin: 0 2.4em 1px 0; } .menu-level-3 > ul > li > a { width: auto; margin: 0; padding: 0.3em 0 0.3em 0; font-family: "Overpass", "Liberation Sans", Arial, sans-serif; font-size: 1.2em; text-transform: uppercase; color: #858585; } .menu-level-3 > ul > li.selected > a { font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif; color: #1e5e05; } /* ---- Content ---- */ .content { position: absolute; top: 151px; left: 6px; right: 6px; bottom: 10px; } .content.nav-space-3 { top: 175px; } /* ---- Entity ---- */ .entity { position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .entity h1 { margin: 0 0 10px; } .entity-content { position: absolute; top: 0; left: 0; right: 0; bottom: 0; font-size: 10px; margin: 0 0 0; } .entity-content div.content-buttons { float: right; margin-right: 1.5em; } .entity-content div.content-buttons img { border: 0; } /* ---- Facet ---- */ .facet { position: absolute; top: 5px; left: 10px; right: 10px; bottom: 0; display: none; } .active-facet { display: block; } .facet-header { position: absolute; top: 0; left: 0; right: 0; height: 130px; margin: 0 12px 0; } .facet-title { position: absolute; top: 15px; left: 0; color: gray; display: block; } .facet-title h3 { margin: 0; } .facet-title span { display: inline; } .facet-pkey { color:black; text-transform: none; } .breadcrumb { position: absolute; top: 0; left: 0; } .breadcrumb a { cursor: pointer; } /* ---- Facet Tabs ---- */ .facet-tabs { position: absolute; left: 0; right: 0; bottom: 30px; z-index: 1; /* need to be above facet header */ border-bottom: 1px solid #C9C3BA; } .facet-group { float: left; margin-right: 1em; position: relative; height: 100%; } .facet-group-label { height: 20px; } .facet-tab { height: 31px; list-style-type: none; margin: 0; padding: 0; cursor: pointer; } .facet-tab li { display: inline-block; position: relative; padding-right: 1px; } .facet-tab li a { background-color: #dedbde; border-left: 1px solid #c9c3ba; border-right: 1px solid #c9c3ba; margin: 0 0 0; padding: 8px 16px 4px 16px; text-decoration: none; display: inline-block; line-height: 19px; color: #666666; } .facet-tab li a.selected { color: #6C6F73; background-color: #f1f0ee; font-weight: bold; height: 20px; } .facet-tab li.settings { margin-left:1em; margin-right:1em; } /* Facet tabs coloring */ .facet-group li a { background-image: url(images/facet-tab-off.png); background-repeat: repeat-x; background-position: 0px -33px; } .facet-group li a.selected { background-image: url(images/facet-tab-on.png); } div[name=settings].facet-group li a { background-position: 0px -66px; } .facet-group li[name^=member] a, .facet-group li[name^=managedby] a { background-position: 0px 0px; } .facet-group li[name^=memberof] a { background-position: 0px -33px; } /* ---- Facet Controls ---- */ .facet-controls { position: absolute; left: 0; right: 0; bottom: 0; height: 30px; line-height: 30px; padding: 0 6px 0 6px; } .right-aligned-facet-controls { position: absolute; top: 0; right: 0; bottom: 0; } .facet-controls a { font-size: 1.3em !important; margin: 0 6px 0 0; } /* ---- Facet Content ---- */ .facet-content { position: absolute; top: 130px; left: 0; right: 0; bottom: 0; margin: 0 12px; padding: 0; } /* ---- Facet Customization ---- */ .no-facet-tabs .facet-header { height: 70px; } .no-facet-tabs .facet-content { top: 70px; } /* --- Facet error --- */ .facet-error { padding: 2em 15em; } .facet-error h1 { text-align: center; } .facet-error .error-details { margin-top: 2em; font-family: monospace; } /* ---- Search Facet ---- */ .content-table { position: relative; width: 100%; height: 100%; } .content-table thead { position: absolute; top: 0px; left: 3px; right: 3px; } .content-table tbody { position: absolute; top: 31px; left: 3px; right: 3px; bottom: 35px; } .content-table tbody tr.disabled { color: gray; } .search-option { border: 1px solid #9f9e9e; background: url(images/search-background.png); border-radius: 15px !important; height: 22px; line-height: 22px; padding: 0 8px 0; } .search-filter { width: 215px; -moz-border-radius: 15px !important; -webkit-border-radius: 15px !important; border-radius: 15px !important; border: 1px solid #9f9e9e; background: url(images/search-background.png); height: 20px; line-height: 20px; padding: 0 8px 0; margin: 5px; display: inline-block; } .search-filter input { width: 193px; border: none; background: transparent; height: 18px; } .search-filter a { float: right; margin: 0; } .search-controls { -moz-border-radius: .7em .7em 0 0; -webkit-border-radius: .7em .7em 0 0; height:2.5em; background: -moz-linear-gradient(top, #eeeeee, #dfdfdf); background: -webkit-gradient(linear, left top, left bottom, from(#eeeeee), to(#dfdfdf)); position: relative; padding: 1em 1.5em; margin-top: .8em; } .search-table { padding: 0; width: 100%; border: none; } .search-table > a:link, a:visted { color:black; } .search-table thead tr th { padding: 0 6px; background-color:#f6f6f6; color:#333333; text-align: left; border: 1px solid #dfdfdf; height: 25px; } .search-table thead tr th .action-button { margin: 0 0 0 6px; } .search-table tbody td { padding: 0 0 0 7px; } .search-table thead th div, .search-table tbody td div { word-wrap: break-word; } .search-table tfoot td { padding: 0.5em 0 0 1em; border-top: 1px solid #dfdfdf; height: 25px; line-height: 25px; margin-top: 1em; } .search-table span[name=summary] { float: left; margin-right: 4em; } .search-table .pagination-control { float: right; } .search-table .pagination-control a { cursor:pointer; } .search-table .pagination-control input[name=current_page] { width: 22px; } ul#viewtype { padding-left: 2em; } ul#viewtype li { color: #656565; display: inline; font-weight: bold; list-style-type: none; padding-right: 2em; } ul#viewtype li img { vertical-align: middle; } ul#viewtype li a { font-weight: normal; } h1 { font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif; font-size: 1.5em; color: #555555; text-transform: uppercase; text-shadow: 1px 1px 0 #FFFFFF; } h2 { font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif; font-size: 1.5em; color: #333333; text-transform: uppercase; margin-left: 1em; margin-bottom: 0; text-align: left; } h3 { font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif; font-size: 1.8em; color: #3c3c3c; text-transform: uppercase; text-shadow: 1px 1px 0 #FFFFFF; } .section-expand{ } hr { background-color: #EEEEEE; clear: both; color: #FFFFFF; height: 0.1em; margin-left: 1.5em; margin-right: 1.5em; margin-top: 1em; } /* ---- Details Facet ---- */ .details-content { position: absolute; top: 0; left: 0; right: 0; bottom: 32px; overflow: auto; border: none; border-top: 1px solid #DFDFDF; } .details-summary { position: absolute; left: 0; right: 0; bottom: 0; height: 29px; border-top: 1px solid #DFDFDF; padding-left: 0.5em; line-height: 25px; } .dialog-section { margin-bottom: 10px; } .section-table { width: 100%; } .section-cell-label { vertical-align: top; width: 120px; max-width: 120px; } .section-cell-field { max-width: 650px; } .details-section { position: relative; margin-top: 1em; margin-left: 4.5em; margin-right: 3.3em; margin-bottom: 1em; } .details-section .section-table { width: 100%; border-spacing: 12px; } .details-section .section-cell-label { text-align: right; vertical-align: top; width: 120px; word-wrap: break-word; } .details-section .section-cell-field { font-weight: bold; word-wrap: break-word; } .undo { cursor:pointer; padding: 0.2em; } span.attrhint { font-size: 8pt; left: 5em; margin-left: 12.5em; position: absolute; overflow-x: hidden; } a, .ui-widget-content a { text-decoration: none; color: #1d85d5; font-weight: normal; text-transform: none; } /* ---- Dialog ---- */ .ui-dialog { -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); } .ui-dialog .ui-dialog-content { word-wrap: break-word; } .dialog-message { margin: 5px 5px 10px; padding: 10px; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; text-align: center; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { margin-right: .1em; } span.sub-nav-off > a:link, span.sub-nav-off > a:visited{ color:white; } span.main-nav-off > a:link, span.main-nav-off > a:visited{ color:white; } span.main-separator{ background: #333339; padding:0.1em; } .button { text-decoration: none; cursor: pointer; display: inline-block; height: 18px; } .button-label { padding: 0 0.2em; display: inline-block; height: 16px; line-height: 16px; } .action-button { background: none; background-image: none; font-family: "Liberation Sans", Arial, sans-serif; font-size: 0.9em; } .action-button-disabled { color: gray; cursor: default; } .button-disabled { color: gray; cursor: default; } .aci-attribute-table tbody { border-bottom: 1px solid #8a8a8a; 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; } .entity-views li { display:inline; cursor: pointer; padding: 0.4em; } .strikethrough { text-decoration: line-through; } textarea.certificate { font-family: "Courier New"; width: 100%; height: 250px; } table.certificate-status { line-height: 2; } table.kerberos-key-status { line-height: 2; } .status-icon { vertical-align: bottom; } .status-valid { background-image: url(images/check-icon.png); border: 0.2em solid #008000; } .status-valid-active { background-color: #008000; } .status-revoked { border: 0.2em solid #ff0000; } .status-revoked-active { background-color: #ff0000; } .status-missing { border: 0.2em solid #daa520; } .status-missing-active { background-color: #daa520; } .error-message-hinted { color: red; padding-top: 0.5em; padding-bottom: 0.5em; font-family: monospace; } /* ---- Table ---- */ table.scrollable thead { display: block; } table.scrollable tbody { display: block; overflow: auto; } .adder-dialog { position: relative; width: 100%; height: 100%; } .adder-dialog-top { position: absolute; top: 0; left: 0; right: 0; height: 3em; line-height: 18px; } .adder-dialog-top input[name=filter] { width: 244px; } .adder-dialog-left { position: absolute; top: 3.5em; left: 0; right: 50%; bottom: 0; } .adder-dialog-right { position: absolute; top: 3.5em; left: 50%; right: 0; bottom: 0; } .adder-dialog .search-table { width: 100%; height: 100%; } .adder-dialog tbody { position: absolute; bottom: 32px; left: 3px; right: 4px; top: 31px; } .adder-dialog-header { position: absolute; top: 0; left: 0; right: 0; height: 1.5em; line-height: 1.5em; padding: 0.2em 1em; } .adder-dialog-content { position: absolute; top: 1.9em; left: 0; right: 0; bottom: 0; } .adder-dialog-available { background-color: #ffffff; border: none; position: absolute; top: 0; left: 0; bottom: 0; right: 3em; } .adder-dialog-with-external .adder-dialog-available { bottom: 4em; } .adder-dialog-selected { background-color: #ffffff; border: none; position: absolute; top: 0; right: 0; bottom: 0; left: 3em; } .adder-dialog-buttons { padding-top: 10em; width: 100%; text-align: center; } .adder-dialog-buttons .button { position: relative; } .adder-dialog-internal { background-color: #ffffff; border: none; position: absolute; top: 0; left: 0; bottom: 0; width: 23em; padding-top: 1em; } .adder-dialog-external { border: none; position: absolute; left: 0; bottom: 0; right: 3em; height: 4em; } .adder-dialog-external .adder-dialog-content { top: 2.1em; } .adder-dialog-external input { width: 98%; } .adder-dialog-buttons > div:first-child{ margin-bottom: 0.5em; } /* ---- Widgets ---- */ .text-widget input { width: 250px; } .multivalued-widget [name=value] { margin-bottom: 1em; } .multivalued-widget input { width: 250px; } .textarea-widget textarea { width: 250px; } .facet-content .textarea-widget textarea { width: 400px; } .option_widget { list-style-type: none; margin: 0; padding: 0; } .option_widget.nested { padding-left: 40px; } .option_widget.inline, .option_widget.inline > li { display: inline; } .combobox-widget-input { display: inline-block; position: relative; } .combobox-widget-input input { width: 250px; } .combobox-widget-input .combobox-icon { display: inline-block; position: absolute; top: 0; bottom: 0; right: 0; margin-top: 2px; margin-right: 4px; } .combobox-widget-list { visibility: hidden; border: 1px solid #A0A0A0; background: #EEEEEE; padding: 5px; position: absolute; left: 0; right: 0; } .combobox-widget-list input { width: 238px; } .combobox-widget-list .search-icon { position: absolute; top: 0; bottom: 0; right: 0; margin-top: 6px; margin-right: 3px; } .host-adder-dialog table.fqdn { width: 100%; } .host-adder-dialog th.hostname { width: 200px; } .host-adder-dialog td.hostname { vertical-align: top; } .host-adder-dialog td.dnszone { vertical-align: top; } .host-adder-dialog input[name=hostname] { width: 100%; } .dnszone-adder-dialog .section-cell-label { width: 180px; } /* Info and simple pages (not main app) */ body.info-page { background: url(images/static-background.png) repeat-x scroll left top #EDEDED; } .info-page p { margin: 0.5em 0em 1em 0em; } .info-page h1, .info-page h2, .info-page h3 { font-family: "Overpass", "Liberation Sans", Arial, sans-serif; margin-left: 0px; font-weight: normal; color: #555555; } .info-page h1 { font-size: 2em; } .info-page h2 { margin-top: 2em; } .info-page .container_1 { margin-left: auto; margin-right: auto; width: 960px; background: url(images/centered-background.png) no-repeat scroll 0 7em transparent; min-height: 40em; } .info-page .textblock { text-align: center; margin-top: 6em; font-size: 1.1em; } .info-page .textblockkrb { text-align: left; margin-top: 5em; font-size: 1.1em; padding-left: 3em; padding-right: 3em; } .info-page .textblockkrb ul li { list-style-type: none; padding: .15em; } .required-indicator { color: red; font-weight: bold; font-size: 120%; } .section-cell-label .required-indicator { float: right; margin-right: -10px; } .dialog-section .section-cell-label .required-indicator { margin-right: 0px; } /* Browser config page */ .info-page .browser-config h1, .info-page .browser-config h2, .info-page .browser-config h3, .info-page .browser-config.textblockkrb { text-align: center; } .browser-config h2 { margin-left: 0em; margin-top: 2em; } /* ---- HBAC Test ---- */ .hbac-test-header { position: absolute; top: 0; left: 0; right: 0; height: 30px; } .hbac-test-content { position: absolute; top: 30px; left: 0; right: 0; bottom: 30px; } .hbac-test-footer { position: absolute; height: 25px; left: 0; right: 0; bottom: 0; } .hbac-test-title { font-family: 'Overpass Bold', 'Liberation Sans', Arial, Sans-Serif; font-size: 1.8em; color: #3c3c3c; text-transform: uppercase; text-shadow: 1px 1px 0 #FFFFFF; margin: 0; } div.facet[data-entity=hbactest] .content-table tbody { bottom: 68px; } div.facet[data-entity=hbactest] .content-table tfoot td[name=external] { background-color: #F6F6F6; border: 1px solid #DFDFDF; color: #333333; height: 30px; padding: 0 0.5em; text-align: left; } div.facet[data-name=run_test][data-entity=hbactest] .hbac-test-header { height: 100px; } div.facet[data-name=run_test][data-entity=hbactest] .hbac-test-content { top: 100px; } .hbac-test-top-panel { position: relative; width: 100%; height: 50px; margin-bottom: 20px; } .hbac-test-button-panel { position: absolute; top: 0; left: 0; bottom: 0; width: 130px; padding: 10px; border: 1px solid #C9C3BA; border-top-left-radius: 5px; border-bottom-left-radius: 5px; background-color: #F6F6F6; } .hbac-test-result-panel { position: absolute; top: 0; right: 0; bottom: 0; left: 151px; padding: 10px; border: 1px solid #C9C3BA; border-top-right-radius: 5px; border-bottom-right-radius: 5px; background-color: #F6F6F6; } .hbac-test-navigation-buttons { float: right; } /* ---- DNS ---- */ .dnstype-table div[name=position] { padding-right: 9px; } .dnstype-table td { font-weight: normal; } /* --- SSH key store --- */ span.sshkey-status, a.sshkey-set { padding-right: 5px; } /* --- Automember --- */ .automember-header { position: absolute; top: 0; left: 3px; right: 3px; height: 52px; } .automember-content { position: absolute; top: 52px; left: 0; right: 0; bottom: 0px; } .automember-header .default_group { border-bottom: 1px solid #DFDFDF; border-top: 1px solid #DFDFDF; padding-bottom: 5px; padding-top: 8px; } .automember-header .default_group h2 { display: inline-block; margin: 0 15px 0 20px; } .automember-header .default_group label { margin-right: 20px; } /* --- Stand alone forms --- */ #formwindow { -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); background: none repeat scroll 0 0 #FFFFFF; border-color: #FFFFFF #F0F0F0 #F0F0F0; border-right: 1px solid #F0F0F0; border-style: solid; border-width: 1px; color: #3F3F3F; margin: 40px auto 100px; width: 450px; } .form-box { padding: 1em 2em; } #error-box, .error-box { -moz-border-radius: 0.3em 0.3em 0.3em 0.3em; -webkit-border-radius: 0.3em 0.3em 0.3em 0.3em; background-color: #FFEBE8; border: 1px solid #DD3C10; margin: 0 2em 1em 2em; padding: 1em 2em; } #success-box, .success-box { -moz-border-radius: 0.3em 0.3em 0.3em 0.3em; -webkit-border-radius: 0.3em 0.3em 0.3em 0.3em; background-color: #FFEB80; border: 1px solid #FFDE2E; margin: 0 2em 1em 2em; padding: 1em 2em; } #formwindow h2 { background-color: #F0F0F0; font-size: 1.6em; padding: 18px 15px 14px 22px; text-transform: uppercase; margin: 0 0 1em 0; font-weight: bold; } .formbutton input { float: right; margin: 1em 1em 1em 0; -moz-border-radius: 0.3em 0.3em 0.3em 0.3em; -webkit-border-radius: 0.3em 0.3em 0.3em 0.3em; border-radius: 0.3em 0.3em 0.3em 0.3em; background: -moz-linear-gradient(center top, #959595, #5e5e5e) repeat scroll 0 0 transparent; background: -webkit-radial-gradient(center top, #959595, #5e5e5e) repeat scroll 0 0 transparent; border: 1px solid #777777; color: #ffffff; font-weight: normal; padding: 0.5em 0.8em; } .formcontent { padding: 0em 1em 1em; } /* --- Login form --- */ #login li { padding-bottom: 15px; text-align: right; width: 370px; list-style-type: none; } #login li input { -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.2); margin-left: 15px; padding: 2px 10px; width: 210px; } #login li label, #modal li label { font-weight: bold; font-size: 1.2em; list-style-type: none; } form#login { display: inline-block; padding-bottom: 15px; width: 418px; } /* --- Login page --- */ .login-page #formwindow { margin-top: 100px; } /* --- Unauthorized dialog --- */ .auth-dialog { padding: 0 2em; } .auth-dialog h3 { margin: 0.5em; } /* --- Action list --- */ .facet-action-list { position: absolute; left: 200px; top: 15px; height: 24px; vertical-align: top; } .facet-action-list div { display: inline-block; vertical-align: top; } .facet-action-list div[name=apply] { margin-left: 10px; } .facet-action-list select { font-size: 11px; padding-left: 4px; padding-right: 4px; height: 24px; } .facet-action-list .separator { width: 1px; height: 24px; margin-left: 10px; margin-right: 15px; background-color: #a1a1a1; } /* --- Facet title states --- */ .facet-title h3 { display: inline-block; } .facet-title .header-icon { display: none; width: 17px; height: 17px; } .facet-title.enabled .header-icon { background-image: url(images/ui-icons_222222_256x240.png); background-position: -64px -144px; display: inline-block; } .facet-title.disabled .header-icon { background-image: url(images/ui-icons_bbbbbb_256x240.png); background-position: -64px -128px; display: inline-block; } .facet-title.disabled h3, .facet-title.disabled h3 .facet-pkey{ color: gray; } .action-panel { position: absolute; right: 0; top: -30px; width: 150px; -moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); box-shadow: 0 1px 5px rgba(0, 0, 0, 0.6); } .action-panel-list { list-style: none; padding-left: 15px; } .action-title { font-size: 1em; font-weight: bold; margin-left: 15px; } .disabled { color: gray; cursor: default; } /* --- Multiple choice widget --- */ .multiple-choice-section-header { font-weight: bold; font-size: 1.1em; } .choice-header { font-weight: bold; } freeipa-3.3.4/install/ui/Makefile.am0000664000175000017500000000140012271663206016621 0ustar mkosekmkosekAUTOMAKE_OPTIONS = 1.7 NULL = SUBDIRS = \ build \ images \ src \ $(NULL) appdir = $(IPA_DATA_DIR)/ui app_DATA = \ config.js \ favicon.ico \ index.html \ jquery-ui.css \ ie.css \ ipa.css \ login.html \ login.js \ logout.html \ overpass_bold-web.eot \ overpass_bold-web.svg \ overpass_bold-web.ttf \ overpass_bold-web.woff \ overpass_regular-web.eot \ overpass_regular-web.svg \ overpass_regular-web.ttf \ overpass_regular-web.woff \ reset_password.js \ reset_password.html \ $(NULL) EXTRA_DIST = \ $(app_DATA) \ $(NULL) MAINTAINERCLEANFILES = \ *~ \ Makefile.in $(NULL) freeipa-3.3.4/install/ui/reset_password.js0000664000175000017500000001022512202434255020166 0ustar mkosekmkosek/* Authors: * Petr Vobornik * * Copyright (C) 2010 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 . */ var RP = {}; //Reset Password Page RP.reset_password = function(username, old_password, new_password) { //possible results: 'ok', 'invalid-password', 'policy-error' var status, result, reason, invalid, failure, data, request; status = 'invalid'; result = { status: status, message: "Password reset was not successful." }; function success_handler(data, text_status, xhr) { result.status = xhr.getResponseHeader("X-IPA-Pwchange-Result") || status; if (result.status === 'policy-error') { result.message = xhr.getResponseHeader("X-IPA-Pwchange-Policy-Error"); } else if (result.status === 'invalid-password') { result.message = "The password or username you entered is incorrect."; } return result; } function error_handler(xhr, text_status, error_thrown) { return result; } data = { user: username, old_password: old_password, new_password: new_password }; request = { url: '/ipa/session/change_password', data: data, contentType: 'application/x-www-form-urlencoded', processData: true, dataType: 'html', async: false, type: 'POST', success: success_handler, error: error_handler }; $.ajax(request); return result; }; RP.verify_required = function(field, value) { var valid = true; if (!value || value === '') { valid = false; RP.show_error(field +" is required"); } return valid; }; RP.on_submit = function() { var username = $('#username').val(); var current_password = $('#password').val(); var new_password = $('#new_password').val(); var verify_password = $('#verify_password').val(); if (!RP.verify_required('Username', username)) return; if (!RP.verify_required('Current Password', current_password)) return; if (!RP.verify_required('New Password', new_password)) return; if (!RP.verify_required('Verify Password', verify_password)) return; if (new_password !== verify_password) { RP.show_error("Passwords must match"); return; } var result = RP.reset_password(username, current_password, new_password); if (result.status !== 'ok') { RP.show_error(result.message); } else { RP.reset_form(); $('#success').css('display', 'block'); $('#login-link').focus(); RP.hide_reset_form(); } }; RP.reset_form = function() { $('#invalid').css('display', 'none'); $('#success').css('display', 'none'); $('#password').val(''); $('#new_password').val(''); $('#verify_password').val(''); }; RP.show_error = function(message) { $('#error-msg').text(message); $('#invalid').css('display', 'block'); $('#success').css('display', 'none'); }; RP.hide_reset_form = function() { RP.form.hide(); RP.reset_link.show(); }; RP.show_reset_form = function() { RP.reset_form(); RP.form.show(); RP.reset_link.hide(); }; RP.init = function() { RP.form = $('#login'); RP.reset_link = $('#reset_pwd_link'); RP.reset_link.click(function() { RP.show_reset_form(); return false; }); $('input[name=submit]', RP.form).click(function() { RP.on_submit(); return false; }); }; /* main (document onready event handler) */ $(function() { RP.init(); }); freeipa-3.3.4/install/ui/overpass_regular-web.eot0000775000175000017500000007446612270466515021470 0ustar mkosekmkosek6ybx îLP‡ ޤìOverpassRegularVersion 1.000 Overpass RegularBSGPä ¼Som¢L ÍéŒÉcÚg i9¼©CÀGU¿ƒPR€î<1ôîð¾8aLuí£±éÐpPÉ'£:Ã5Í;WK±”‰k'Ã™ÈøUW Ÿ u*“£¼0Wʉ͞Ú;òà+$U£ØS-Ôî‡dz†ž ¹ÁÏKÅñ}e÷ƒ¶³mª©+'î°š%!×Ç®oÍ|Ÿ¤½Â,àN“ç°ÉägxNN‹‚(G.PÈÏà™µ; ÌÉܤ÷”[víÊrlGáÈ”Óiâ¡HÇÔ)ÜH!ôä–ƒX!€±:c ÖAGaçÀL›óùiˆŸ ”À)Ž¡XG•^"`£ÑØŎܾÍ©™?Ci¨K~½=nY}2ÒV©ÐÑÂ-‘عh.Ä1RÁêÙ‚ô° †8I?„‹ -U§rŒÉÏ•#ÉÂ6i¤ù.è9[Qòi9X£÷ª>ÍŽñã|¶ÐFÔ†ʸ:ÚFÑÛ߮͜D£ä.ú[A1+1»‰ Ö°?å8m'ýdŒÂ3Òa¨6WѨ¶üEôˆªæ´ P*2Á®×0u[uÛ>ò“jmóÕú.°>B”<Ænp¾EËÒ½ǯ‰zë°¢Éă$Û N„ ( «€Ø9’ü×¢°kx%’üŒß¼báO|÷‡uðgBwú™(ºø‰$(s(¨nxÅ@4·.)Ueý)tItV­/¡Z:ŠË!:VL4éåÃ#— vã]À;‘†Nò þw¡Wçîüö±ÛÏ7›&œ’oô}j·¥‰»¤¯—ЉB›*܈.A©ÝÈPêäKo©†KD} a.üS]]6ùÏ>fà¿à`ì„ìšjI1q/3ûѾoBÍò ÍE €hϸ1ÃÛð:Ï nbô5V—åŒÔ#ÜÅ‹¹Š >c—s !¸! -¤!ÒÝà„Œîú*Eß0t×…ùWQTÃbØ6)FÊž ¥‡UÑ!s‰H²‘#$q \“cš›Õãb\LÀD ûØ¢,:ðB\ Є¢£ëzŸšá¼& ô¼oRhG…ÖaŒW•x_²²_HrÆÃB°ÆðC õŽ£ŠuÂÚA‹j?ŽE6ò£q ÔåD÷³ÑÜ2Ý/>¤“hüµFqÿ'ãD!ÛÉõ2‹OÁäݨ F¨{pÞq§;Ô9=CÆ?%­ýà@mïÀƒCÂy’G}QeœÇH7àÆwKÅ434…'Wåâ)ƒž ®/ò²yko¹¬R@¢%5úíð¼ó?¯’+Ñ(SÙ”%·mý:Ú_Òõ)B¡q¯ô¸ft€m¹m‚X‰Jwjy†öJ‘¨ rB䳋¸{½Ã‹Õ’Že†ÝêÓÙÉI³Æ›Eî˜{8¸ò¶cŠÒ«,VÂët7fX0§/Z-ËìbÔ4KîHÞi£;e­HW¡{L~Ÿ7Ü£ ÈÌxå,öGÞM]3m¥ó®FuR„‚‹t²Ns|‡kú@kðùÄÛRÓËâÑaC£<ÅP>‡I-ý±\ö°í,²5E.¢èY)2Bz*)B «I©IÄ(Úh¤p#g'cÍŠ :‡_Ùj@j ìx²c[îKÞJÌ,QVÚ(˜L3DD]X1]”I_yTÖ trÇ0˜×H[~zòýJ]o+¢—4ewhÛ)Ñí>™äfr{¥‚á£ìرԼ$ñâ’—Xæ[9:ÓŠ÷£DÔ›n8厔mäà5€¦Î‰ÓÈ‘kh”ÄÈòͳjˆfÏÐîÌ©k‹[¨;@Aƒ¦5“f[Ô;…WÖ[uC $vƲèË…™g„E…ÖE…Œ˜ò“’_ Å qºŒ&àOïYÒ^’õ­ƒ÷_ ™óçꎗë5 …¶?@ˆà–O0Á €fì;¨ ß^ÍÏ–gØÖ=†NUB ½ÆÿùœÜ©àU“l9aBG¢á²UªzÉŽ#”–ˆ]ë:Ž ¿Ãá³.×Èbm©]Þ ráìMTç8,Ÿf´Ã#©f5¼NË7Y«Ì·“‘–QBf‘€$ñ-ˆŒ„©|CÉô¿ïn/y?×Ã~nëî¢fÜî|ï 8SêøfTãüÝg ÷5²žX£Á΀(A,v…ÆR%+Ã(h ö*pdd?54DÕÅŽ¥·>œÕðã^‹'~-ÿ]òü÷¢–"ˆIÒZ¯”Ö‹,#:[`‹ÕA `S—NdW)~¤,eÙ8‘NËÎû”}6—´Ôœ-Ò•™YUˆ²ÔM]-ÔÂî„4Ç@TÇC¬A(Ë)ÐíâÉP‘1ß ’‹ ð 2PfVçÚ$*ä®§ïBA8© $¾¦¬Q—ÑK¤- 4ü`þÄ ]ÿ 0~„ÄV‚«åþ+#B× “äl¹L±²ç1Q ’å#Ü?ï†ê¨©Ér3æXY¸`FXÚ§iI™{w•™f};ÁL2^¤TÖZPDÉ1–ó¤µA’0Ó.+wŽúÞ­ÍôP aU¤NÁ¸Ótî@hnÖBkç»e¬P.~«±3ØŽ-™ã@Ø€0Å-zƒãZ|ÞûX±ùάWƒ`/Y¶üFP§²},CýHëšž4 L±‰ôP6÷ºØK-èßçâRéGà‚ê¢hø·S¶ôÃãõ5œùòÙLŸÛ¸E)bs«˜ÖcÑÕŠažäħ¿»n³ïߨ)6 J£Ž•–pÂZ¹’3pLx`íÌÕmÌÿºc9Cðy(W…LUÈŠ2%°1…ŠW)JKaåÇæçĨ¤iU‘Äkö"r­ØlààW$RàÀ¥ ¼ ñ¶ôj$ÜuÅÁã=¾@H$tÿ‚^›îù€ÀÙèºdoƒÙ—œG€k“þ¹I¥±s[S ±l‰Œ®Pãi›ÆˆŽâ`ˆ¸…8£4ÑEÔhHÐý¦S­³÷Šý[Q½u*úí”:²D¥Ñçkx$Y*©³a"£¡Š¾øìûy°(“³†Á®”kƒÿ4»YË"ßcðãÑ[Ñ 2Þ>ÃqV«´®x±÷%Z$H:J3€eÀäHÁ~ä–PÄ“¯±üÚS s|énõ B'µ‡Àƒ{ÁwŠ7EíÆ Wî¶–‹€"ÃHËFÃu&÷|70¢¦‘ ¸é”ñT™ãÖâ®*"J~SÞìVIƒ²X{6ÂÚ˜/gìÓ—$5ŽEtТÓ@å ÞC#‹Fcp³Ã,ÂÒ˜ZÑ |¯©v'‚"Ïч¥ñž+؇‰,Á\Ö§æÄ©·8êR•D]æ$nºtRépÐ<Ö»póc+[îüfÞ˜œžé Á^hó\§dìŽÏ@y¬–õäë¼!¶r~kkJÖLñVh_ÕÁ \ßÕÛR´›§ÅS3–"ôñ­{º&ĦƒGÖÖðw¸¸ÚrÝö ¿ÇÂDÐ1êoÛB=¨®ÄÀªçóX¿DceFØÖÕ†ÌQ†B÷Nû7Œõˆ]û>¡P¼B4E•"*¸ßq4c&‡ÑÜnÓ6~yÇ»äÀ{¡Â¿D­´oV%Z“|ŠÞ?ˆ(ÄL¢AO݇„`“|ñoãt8UJ0‚‡ ù4ð…X2¤È°à Ïc Ãp$•ÌB:5tÕèr0æóòÕ”o`d±±—¡§ ¬Y‚ä$aÊ×n²+'+âTÖS§d%I~– „á#9PQ¼ªÌ.¢1(I6©ÜN»˜*€k *.9M^kþÃÀ”G–C‘)hg©²F.¬²%qÄ)^’º1˜QÙDR‹C Ú-•ã„¶MVåSå„rËGä­PM¡™SL7ÁS5R(ú?÷…UŠMè¯&@}x³Ï–ШNt )ˆá6­Ä[#I<œ†ä0\SÒì¡7*/h/BX¢g4 „‡÷Hp „<×ÏÏ©31§%e;'Á;{ì]}A~Õ F¡ˆKú¡¯Ñb%Íei3‹,!hÞ@’Ž)@b « Üž %}£åwÅ’èú€9ì€I??OŸd@…\.м ©OS–B7A’uþNzБr· ‰/l„1nÄøQf„°Õ|‚ Ëж%ü¼’ñ&pÊFø^$·'T⃠*ÁÍ@õ=AÊ#Xñ ~‰ã“²ÕfNþ¦g–Ìß ]üš¼´Á€W„"ô“˜¾€€vEøÕß„T¬ K`®•ZÜt‹–¹B™ãj±ßð¤r,ˆO; Õ®+4,º„mÊ«¶I¨™·G#o‹IQç÷ Ì^%½ˆ¿éT6úYÄ̾±i¬ " GÇ‚r¼·Ún³îD¥ãu:ÃyàºéXèV•¸sQ ž53-/èx?\[åGmì ú¡ŠD^ã&Ôc26ú²BÓåE°3–D\ÃÙ!t"* /52\v¡ªÏ“Ço$¶e ›sÓÅ>/±®¨=æbLÕÏkÄR,Ä_·¢ÈÀ†Õ{ˆqpa5†Ó`éaÓB`úq~]x h1[öj‹‹3n”ŠEèk‹Õpí õ§»n )<’„þYÛè<´š—&<³á'+,â1‡˜ÖG”z¶ØöØz[Üq5ë“Ý)E¿JNN_*7y{a¥¤ò)гj£ApY‘.{Ë\¾ç.Ûí>ýÅD&™? ÛM0œWÇ]$RJ&Qn3´K…YQ~gËšPíÝïJ,ùd戫J¹¤¹Š×QgË!T` H“-´˜f?€_q¼Ý’oöJs»6¢tUÄ!Œa^­$G¹Ô8L½î—OÿŒÞ•(µmK(´žÀìä—ö—Ëç$Ÿï9îŽôáo^.…>ÑJi˜TU ♊HB9æ~Gš2¹Ešäô[i'QºÖ~ΘԞÇrHuÓ« &2ÂD˜àë«I Ô耀êcÒØ §ÄätT¡) s„õä°ü[Žm|‘­ý|™-ŠeZ–2CÙê0–PA† @›ˆ/'¡‚pK8;ÁV#c¤îª¶Aåë÷:Œ™ÀèDᓨ¸¨²„TkJÆ?ÎH ZáH ÖT+Ûx/0\©Âpy*½•Éôe$!20‰òzç6IA3"8µ\ƒ¨býNa'løŠi†‹ì¾ÊŠò©,,@HszA®­ &E@ò„äÂòŒœlÿÑÕIJT@5WDm6ópüDºóBþ¹™—"iˆÈi"Ü‚Ìßz@T˜Âæ-±\=šO#½y”à-ø‡TC·˜<ÃAC£Õ5©ðY×–¸P³œæ9êí¶'Ô=`«2(ˆyŽe¿óQÊž?÷©’ ׇ}1YÇg‡Uh,—‘htÃiÇçm 6hAÝ:ùêx'‡Ù,Ø›|{–€YÔuÀËã+IΊ$ržc” 1Hx¤E—†«Ât׌ ½OIž¦{[ÌØÇ8Þ-"ÐKÔA¥8—½Œ¤ÁQ9À¹}B@õìÛƒ~v$¼¯–Ó“ùl«TaD&WXu°4š(Uù0L×ðÒ Dú>Æ÷9íiÕkÈÆ›þ”¢©„m+ÛWƒckß 1 zSÁÏÚ7G­ìlÂÜ<ÃÆEDü+险˜âÅ9jîÜÄ^¾àС “¬ÀÒ¬0 bG£…©„9JDYg†˜b>À‡ÉwYWÚ=µTø@$Ô—™­N´P1l5¾±B8ÊÚ‘ œy­ÐœB‰&Ï ËüÞÞ çÉ¿®ÍìVgP‚’´˜5‚Y(Rç-|šPÈBò÷dÿà:fˆ:@$d© IêF©ØÓêc›djêèÇÏL¡ÜÀ ?œbÑËð¥×‡Ö¥¦©- ìÅÒ"¼< .| ð%ï A+.‚ìÅ'GQµÙù~ü R£9ærP²ò¬ÊÚ×–‚S2.þV)ôq×}zÝœ\ AlS#*m–Ö@1ÉÐþ Â?³)M-âΜúV£òÝž±‰‡6µ‘N?.‰]Þa€ãT!aWÎáY;¢ëçµ$ƒMâ?fè‚Áë8žílsš‹\vžáÐçû\ SV¦Œú¶kÕ(´ò2Õk ïÙ~L¨ï¯Æ|K-Ô|M†ÍkË ?¢J–«U»ýQT ñÆ:RuS1€Nòɧxj¼Ž\‘Ì6žÍ+åõuîVsƒ…§˜ÍT¼ÅüÇN<6“²v^©­[…HŒë‰ã) C)½q[ðlP¸¢ ú´Ô¶·Ø¬šïÎ<ÄT¶¤B FûJ&¤NªQo•[u4 i+© –Örh3ÏÂ0yj†Èƒ E0ÔÂoN{Múéûó\„у, a¬Ò pÊeÄ‹&â\c“¾%ç RjicOÌú¨àÀ'(6viÛc¤.jß "³¥ƒbý @DË·u;ukZHHçœþ„ÒÙ ˜‹9¥j/GÉeHš}ÑúArïH–sD‹^À'|lwJ‹,a&ç0Üá ˆäÛ¿EFІGý#Àüh×Wuˆx¤ÂD$qíØŽq¤¢FýqPs-”…JHШëæpsnÓÝãR¸S¨\éÌ;vôr–x½e w¾e1Â1 !¿¨°V&5'WÛ0;ÕÀRÀ¨9Ù±J÷ yÅ\[T;=F–À²¦g?ãâx²¹¤HÏœšýA2´Ÿ8(3ƒ"ÀÒÑH­÷È–̉CÒÖ˜ò??ïµ(h^D†e {K‘‡hKðZO""À° £¢Äà ƒËö^ǽØvÇA©\O ͺ{®ìp´à¿\/ð:ÀÒÙ…¢ôT͆„6"ÙSƒ'Q Hï!ýìJâzð~YB'Ø7¼ßÛD&~C ºÿµ3 ã×ËX¬Šwƒ¢y© p Àñxµ˜HXÎgè „¢B%ª½ NÍÔ#î¡ø€sÐøkÈl!ø%¦£!ç­|ìnLuÚLÆQ˜/YyÑ*Ò„¢‘Ò5†f¿é­’­ X±\•GŸž zÚ{" '¢¶œ" ;¿@ \`ˆ©–DâT[Ì£”3ô]Ž„BS-ƒ˜¹peÛïÉ'“oî Xć¤` (tÊ…_ˆžoÆÈé­uÆiÄI®žÆó›Ü_ˆá©fª#’›‹Ÿ˶Ir"YH¾$t¼C•éžšL''X!Ǧ|føV‰î}]ä–\©m÷Lj?{ ¥Ð1XG}#¢õÁ!™éF¶]òSõ˜[%PA‘shMs%ÍŒ˜›¤pZ[˜žLjƒêt£p´1ñ=T×Äh•ÎÌ|û\î-}KîTõûCû€}ÂS`&ƒV¾“@V„m`ÚÆT”UÀT-üÐ<|íu¶47sU›¬[,]n‚H¬G : 65#ipÏFkrdleAa²ÇÏJÃ('Î÷€P¾z«q„?SÂc½²jÐKG‚i)‚"r=Q9 COw\_BNÏ‚Æm–µ|‘[Ȍʲ+ƒIË¥OwËå=Ëu±zx±z)—«ï{Œ™ð6§º¢U¯gò¼’LFâd|)ËbLììbÈ À» 4ñ Q‡b…Ë®GÓ³¼”æ­ ´œÓdÝfœû$Õµ.ø»w/U–Ï]º4Ó`¤Ô½þ¹˜§eøŸ%–oÀ4˜uvt©ûŠ¡ASLÑ[¬8 |1ÙΣß;IÁ×lÑD(u6XÖ%p6XÂI=Ëä6‚‘8ð†xÄæªƒ? iÍC<]ÁU…ÏÿÞèídFg=Qø1rxªÇÌx¢kÊ¢`XŠV ès õ×^3ßZB]ÄõDîÇ7•íò¨ÄÛÞכNò¿ŒQ(Iaè˜hyäõèXM­RlÐPœHI¿Ø–OâØ›.ÐtjUi‰ÿIÒP|Y¤ë-öRÏh ¯_gÇÌc°±.Wê9• 3WŠ1¹¤M%¨"|‹Š¼`•ìož*ˆ|'ª€DM|gÂZ×À…¡@ª½&6Š'GΫuÁ‹AEFöEõ|À@Ä#¿æÍ¬@n†)Á5ÝÜ;â~¬‰§,E3dšÌ>õAe· vÈ)Á$©”u‘ »Iùfø*jA?ãsëóÊÏ]¥^]ù×S¶ðj:äŽãgäÊŠéT)dõ8؇½$¨ål¤:ˆ\æ¿f?ï÷}~R„+’@&ThoQicÇ¥ çF ë­áÕNŠí4dB  QŠ@Rä·¶'m7>뀀—rLœY$xO`\°I®òëÜ~p=x|ëV§wÕ+$‹§QÈmpºëü— ä^‡’*YA;ý£ÃüD¦û¯íß9QdÜ3ÿE8ÏÏ\’§y¬JŠGˆ$æÏÒ+“xÿr }ž®9^›ñïû9A6 Å”¥Áø6ÜÎLtíá2vI"4ïþbyWß]¤ÖNÆõbÝø{D=ñg¼Naxr¡ðó ‚­Š=¬rÚ&ÅS˜ZÜ\#äZZãÐ1Šðùò ƒÎ[‚Öo>„AÿSev.ò¹Ÿ«¤)fŒyBøg'$4~ºùôçB¦2ÖbÙq ÎÖH^V–µ°z;›¤à(QL—øüî6PÇqD3¾TSY§Ê…w;Å£úºm.Òš÷tÕJÈ)ÐÁvßî¨f#877V-ðüг—wü÷A}À°…‡iñ¨ôÐ)N\H¢”®ë”°GÙûâ(q1ê_dIÁø™Cšøý±”¯Î0ý˜4‚ÁJ»2¢©=t°9{É Ìª9JyvÒi_éA AÈ׸Ð>š¬àUTÜ^ žH‹œÎëzûÂì4Ÿý‰™8²„¿âý˜H³M»æj"R¦sCE˜Ùò~Š®iò9ì­ÒrbÐÛOÿ[IeñsÃÔ$<‘Abqš‰¥9¨Uôs¤8®D;‰§…p"%2vU¯WŒ2)° $Þ{>(™‡“íN5¸«õ,[ Ôé­s੼²þ·l?Æ.($›œ཭rHŠ ’|{µâì M$Êâ3k'•ƒu` «%:ÄÁÁÖ¨K~#3!pTíì &L ”ê¾ËT‚O©_ H±aT/“`ý šëBùPI¡ŸuÒ¨õwgÚ$¼^° –Dñjò ÌhÍv±ã?’PÁbéXošn”#f¸ˆ¥xÍ ³þä›ô)Ê̤þéŠ*ÓJKb¡¦ÇQpPĹkÁäøê¡ùš,^tLW Oϱ•Åk¾T}1‚DÔM@jà Ý÷Ú Á hA‘>w.ƒ„H{ÑŽÚ¸r6mâ?sÂXA!Ïäxtå29è•ßéë3Uûã„ ¤àÑUt}[A(¾“ŸÝ"f/¾QO ðâ8f@5©wE W“#žö¼=?MÞ†+!ƒÆœHh%ôÒÄ5à©ä­KQ l²ôyð`{j6.»@¹èZü­y‚$óÙ~¾|*ã [Ê´j[”6&Úb«Ù~Äñåfòz‚&¸ÙêÊI)-zÌ .·}EjǤ?š?Œ RÜÊ|v{»îÝÍ7œ>@ÆebïäNÙ3€·*l[Pí«Œ6ë_ÅU·ùqmïÃ(PÃÌAläüàIK²÷I¸C©Sê”ðàzc‹,’ÀZe“„~e¯Í„JÉsJ¯˜D#šx8]`ÿ.+ã ì—]IŸÄZ…è'Zd¥RÕIBRtðó² i,g<±€ÿ¼˜˜Î‘Pi ¹ ï™ÈLõ(Ÿˆþ‘kîUÞ€|@H~$ödÛ>õÅÓqàÿ2PÚ‘DkcrëYÐ×4äüÖ@XÀC’ X‡ç™w~ñ2ÕÈû ø„ëëáRüaÿþ¶.…Ÿ2U¢ =*“ÀÜŒ¦Fuˆ3xj– ÒH‚E¤PDf•”ʨ·¯>~ºb ²aÝã,àEcý”94»‡RHQêC´ÌuF2_y{¬jt¼´œ“l®Ã-[Sà=š!ÿ‹˜È/5c­0ŠxÖÈ›¾-NbW{4l.:þ|’Ò¼ Ô¸ ÷A¨BµVýV‘ ‚õÙÌDP)¡?b"ƒÇŽp™ÒJ(y6#ªY¯*tˆ9d|É‘“ñ‡ Ü ­J T +]¯¦=¾¤¿¿z´¡Þ·@ŒÛÕƒX§&Óy×ÐßmŒ‹ÑÂŒqrЩ⎷»jTG‚“åŠÊÛìüOR˜í¡¯έ ø¥˜Ø‚ MçàÃÁ½Æ’H/¿›E*«‚ÐÒµ‰4ø!&Æ­–°'0¬F‘°¦³ý0܌җöcru¡Uïñ‰Y:gC¾ÛÉgÀiéiz–Å œZ“ÆõIH3Ù`\çi7³)L––êŠ$Ú²%^fÖ[R»)äÛ{Tp¥J $üps•­….CdÒ샡hŒºÀÐ75Ô¢¬dïð ÕàdÖò6¡2kzƒª.5¼ ßÊa¹K0Q¾µÜ+F]*³,b™Œ5üùX´\i!Úé1î-?0%Jk²SÊüú€'%ò¯Ðb¤§Û’‹R-Ù&i‡ 0Ìv×KIQgV\¼L•9 ÔÉ„RË\¿mÓyl¯¥ŒØFf&Î: ¶·±vn#¹„ÆØ( ¿Š€ÑÎwî<‘\Ë%êÇϱËþT¶®m)|ëUÛÚj¸CÝzÖÆìÕÅ÷ppÎ?*çÄ.TŽjŸ‹X-[."ŸÆu1 ¬!‡Z«V7jãøç°r#Dg¡—¿ŠW:”¹çíJØ^ˆTcÅÏÍè£8‘üñ²Ñº=õËAô Æ1Ím¦‘ÞŠ‚w(lŽ £¨-’oEo²õôc˜ì.šlŠ$1)Ø“<«Œ½ávÞúz¬5H¬(*Ö‘Xϵ«5Œ#²œÖ¤ƒýñ=n»W1CT‘„¨*Ÿ<¤0†Á‰#îÇ0‰ äÒŒk—L‚Pk_[ÎD_ܲBq»wuˆÊ·­œ÷†©w4ˆ§B¥‚ùQÔG‰`‘…v”Ÿâ*„‡uêjD‚jò(Å»'P’FZ9=#P‘+ÖÎ'" "¾¨ƒìß\ ,QH;b~òíÏÁ*ýÇR“¦A²ˆØAÔ™u¢1‚{5±…¤¾<<ãË ­ñ’…SæY.…Û‰Ó[‹t‡&y׺Èü{Wðšj Q`&¨ `-žTÿI%C‡Lª›–”Pwà/Às"¡æ#òô@¬¦sÁÚo …ª¦YˆÞc¤v´KŠDiR˜ÖîmÒpü„{2à…06nÔ ’.Z›¾¯*P4»Î¸\=×HÒš$‘$UÚSd@Ë÷(@¶¡Œå“'ØJ§‰ëÄù?ðŽÁæTDAVàĈ ?¦Ÿ™[û09m|ŽðoÖb<Š*é|Ü4zƒ{ e*zGLߌX2ÞÜÚ´­+™jòƒ•ÁÏíNÁG[ Ÿ…À«=qrƒSÐTÿä1DÖ‰k%u !€ÌiGÇÍȶùeÊoxðÝ ±…y†iN—nUÅ©ÍA{' jÿt{Ä]ÛÿQ¤if-¼kkµÉ$õv“Ïý§ºî oHÒÌ}¶Pt†Vþ/ì³7ªaI×)cµ°Ñ#Àd­†;|7Älh¸´÷$éÃãÛv‰F&zœÆ©X]Íëp%fôƑ̉å|‰E\>†Vçè à |ÊEàKª“…š9Á:õšFöp w¥¸¾Ì6ä¡,“k>óìC{Ž_ÚGÉ몊A`Ð{kÓõJ2d![ ÞÜ"iKžvÑܵ±Üþ¾ªG%Àóø40ºÄÐ!³ñ·5»Î»RüW^AΤ…Ð5 Ž"%¨Ü`ל]²÷÷g5kjíø,yƒ6árbU¶ =Jã@ zzU@«h0éNCx¥å.ëÊa8¾ÑkßJMXÁ—hÁ ÿµ~à½i³Ö¿-JXš¼Ëæs˜x1‡#‹&–c9<Îû¿frÖO+ˆ“¾ ô¬†äÛœ¡í>Pm:ÿrß“ò¡ Y4}D¯Ø/ÅÞ˜9wMæIšË¤]NˆýeB3XëÐý=2¹€ ­Œƒmu@¬3ªƒ§³IªžÖ¦t›Ù˜ÐQvJ°dDgô ©LÀEæÜŠšD¤$`˜(Pÿ=¬``]söýz»€n¦ˆ‰Ü­fˆˆët»RIOÚŸ³gíõ„4ýy£–rý²ü`«,PkE˜Ãé@Ãiâ tX•݇”PKA.é{¡çðHhB…‡¹WÀë:e½6Ê;ë5òFó–q²}TÿvÝ_U‡ÒRðeLO¡:(¶&ÔïðÔY!Qd2ªòˆ«$ü¥þ,´`ÃØ}°)Œ6@h8. ,“žïAJGÃjº‡Ž5¢|y¬^„~YáëúBÌB¯ZŽ0ÁQ•nÿ¸xÅPì!,½[ø+’ËIÚ,º]Âä?ÿ!±´bd…B‘÷u¢$(¦F?Ïäâ(|DÏ’ûŒO¯«•n9Œw!Œ§›>R«pÇ’úFýkšg–‘GGD’ ³¸=k»¼%Çwx~‚ƒ¹YŽ0HOQõÂË޾ŋÓÚ`:Ü4ìPg`FÙ™\쎾¸Žjz¾$²ïc\†Ø„…€)ä@­ ù$‹Æ²)Õ<“Â#g†7fý ÒàØÚXÀb‹È2× ç9h'Œm0ͬ'-Wq桎 ág#°×x˜‚'n–TB݈&úÈP¿Û{œ/QbIw$?”Ì:W•ZoÀ'CGà€O¶%ÈŠ_ƒ2*ËÒÕ=ƒ-Ø3$„·Nx¬ËÏ ËÈnýc_÷ô&7µ<%¹H{IÔï×ÉȤæ{·]…+ÏˉÿŽ•Oˆvɨ¤ôIjP²´/зêBrƒ'rW×-¢±A(Ô6Ülhân8cÓ'8½þ‰®¶?Še,”¦ˆ+;¯ ´H‚¶¢E c €­àâþÿÍX¤È¼ì# è3³’`0Ü]–öQÏùÚöÐÔ€ ÌÀ&ý”- îÚõ"yvŽÄáùFGm®†ÏCP —h†ñ…ÝšÂAlÑLS  H©€âv}‘ÍçD¹?†"’£É9˜^ó®«àÙiÚM+&5›êŠš@ IÚJ0cäšöädÚ0ŽVie)HÀ75ÊãN+ÈVw¢¦aú1…âÉŒLê¿ÄˆNa€Š¬„ê2A?Ä@:æ#·ùÛÞÊÑ‚`#^@´ ‹¤°üqf)µÄ¶‰1(µÆ›úª+°?Fö¶þê@l¤bsÈp¦@,(% ÄŠØA×}<ÄÈ k©i%¾q.‡ë:1.gñÅ C7yÀß^ ) r›¨P ´ "G žg.âPÕ.Q³VQc`ÉÙ¿Ý<ØæÚ\ì)¾aH2¿ô9ôù3 VXô—¢†d‚¸Ð-áñ¨”ä»±vIê„ûè§£l7‡âh/U¨I=¯yÝ3*\‹¨lÞs²r}pC êÒ%Ì­A-wg/;ê² N»ÈùƒPÁ¹ÄQõF6Ý¡"˜ùíìÐ(Ž—£Ü’fä„ {}?÷{K@l¨ô”†Õ  —‘(Ñ?ZÄÍ âü:r §H$‰Ž…Ç–ï^UëÒ›àèÝ•\ìÏnJ:ÓR…X\DÉ' '0ÝM&‚Aì¥D‡·’Sl¤ ÛÓÊtM4†bi»¥çÁyÜ*™ýÃRkþVÖuòÁO-ä%j½­csSµ—7–ƒ5·µ kuaês~¨/< @-®&-éòRÐúèƒéh‚r%Ähæ®I“yL/+ ¨›·H†üáß³¾T®‡@2>5“BÉq_:‹ #0«ƒ£Lª’py 쟻-€<äØ_ðä,9…©i˜“7¥ 3Z°›Ò¨ ‘ïõÈÏÕt ñ» X¨B³âÃ6Ó*jvÐ4Îê¶áSX4’´5”V`—»ÃÔÄNðþ‡Öç —*>úÏ ”¡ìž¥,-Nˆšyâ:é¹¢þïCi–jý|°€+A¾´¹«\>^Ì„øi00_~È¢[gâ6Žc2º®b$2EtãzrnRª K¿>7¬{¶×kpêÖ8m.O "Ez@볉;.Iµ¦,Éœá_;ò¢£Ä;°«u ù›îâg©Ó-†Ÿ£KF;w6’+`Ià‹°d©èîà³áŸM¸ýVÈ"›ÜÀw¥,ªwŠlÏpjUL˜$ãABIαEê ý}sÝQR¯æÛ´#Ï8¨Àæ¥-©+ÁmZ´#ÐÙ;kOµPnQi‹Ƶv¢!x5¶Ð°K] Ÿ‰Y¦•;ûÄÐZq¡T×#pXÆ$Rk¤Á£“]xa\Ê™Eçu¸0*³5eÖ‚HÛµ—4#´(‚+¼†IÀFÍE±âFÂR6ÊгBi¼Ä¡Úh6HñÅÜFþо³r "d#—F» õ~Á{äŒù)I3ó`Þywª~Š)6ÕÃQu‹’fXJ£å¡ “NYl—xl==€mh“kˆÊWì=†vI[rrÉJO†¤ÚmïÖ’nQÅÀB ©…¢úYh¨U°ã0 ‘rCq6akBs‹!2‰©˜ýœÌµCr¡Þ,Fl¦b>UÄleŠ+¬àn½¥Šäx¨‡Nà6…(¤†‘ÿ-ž@ÇKñä;ŸÙðñ¤x(…;7÷´‡c™?gêÉvÅZç,ìʈèÀ]B·Ž§-ØL–×BY<÷4ÀShÜöÔÀhÜöÔÕcнX3S1°ÊlÃX¥`¹šYk áeœã׊CØŠkCá¼a çT¦dÊRD[EÑY†×ÊŒdþDNY¡}ùš<ª'7^˜UÁ8‡zŽR#Ù²ý¬ Éq¬š ?›ø¨'#ã_tûÈ瘮™^WÖûA|áEJ'íùø·4A±§8‘›Ty •)Y²!ò¶5qž|0"l¡ž IÓVnÁ†ü`’aòyiGQQKs`+JÀK"É©$kû4•¢·Êµ Ê3ÿ%_åÀÕöl­lm€-YE‡8Ç"„PÇË‹lSR-¬£“h­ƒö=¸«Kµ)ö£ûƒ:»GÊZD8Êʵkžßãè銥•sÎÙ¬j‘²Ô‰fÚ/öp<ö¥¤Ê¼½9 ¾¿oòm©÷ù4ðàjº7D“Yµ!‰/©G,\««åmà ^£Q¯¼¡nøé_nåä~OÈß3‹b4>4tjF´dÐõÆ$WÔÉ"äM6AVkÊš7çáã:¬GYd–Zº«ƒ|˜9h§qU2·:ôR¯š U%K>ßφº-/ßï1…ZKtÄÊ ä70sÖÿŽ]kç+IAJÊÊsD¾§Å-PÌ\Yz]ŠË`¹pV6£üþPfܯÄÝc }ŒñUÔb<¡vÂ6p·¿‘¥‹¥%:×E8xÛÂÖqŒ7ÓYº‡z[ÁK4¹VU !â?Û@ýêPqi<0%e¡Ìp1à,6zjƒÇ$ = q®®Å €ì´FÄE\Nóp­û3*ö%$³vpôâóÑÐdð0~/c¼×)çy•EÆêú¸Ä#n%7q!êY8¸·£«mLšÚ®†“GÒû!C¦“-„Û@…7ÐyrI‡ÊTÁÕr!ΰA&éÁV}…jÍ0d3Óõ‡¸r"{#ÐxZìŠXuŠxƒÆ–˜ì¹Ît(€kTB¹dÖÀÊŠTîÞÅŠ»»ærtz~fJ¼v3È8N$€n¾‰ ¿ eù "på3<‘ q§ÆšÍè±YAiHj bÿLlOoDÊbÆÍê 4gæÀÖ.-ü5”–'4t¨6É›Þ=1)o /–š8ñd¸?d^++žY.zŸÛùYBò-È›#E‘q§Å«Ÿ2Þ†à3óJ`hœbè9"XSl†'ñÑ‹LC„x]D‰¤6ÞBâ6GtÓèrC&ÃHGiÐ[PÐÉ€u^d¾¡i‰([xCG¤pH Ô€a,X\M/%‹KXü@ «2ÿ {˵ÀØ– V _€ ňy¤g-÷ ¬Ø í¹_;¡È5ÐféÞLvo€<ÆNNá.~ö!ˆ‰ÃtÎHv ÝDŠÉ¤æUx݇˃ó¾ZõNÚ/iyp³]Ö“Õ‘n´l›x‹~póØRD‚IÖ˜Øôƒ^ ÑQ~ì…÷ȸ&6Jí |–ãÁÄj™Ä:rb-$ÕG@òîo¡ ‚¶ª–@1ìêlyéu½ä…—’…€1§¹y™-`sYú êç®IJHGEGÕ¡þÁ]Ð×’é,j%N 9[;䨕^­BÓ䳯ÉÙ`ªÿU,ßûERsDºì‚ë¶ZÌâ4ü½Åœ­3q²Òñšw |¡ßß`ÜÞj†O Gš”SÁ;ú©þ“J<§šé.Óñ/†µÄñ@Î$sOľŒÚ²êæ)½õÐηÓ]‡®,½®O&#±þ¸36UQÓÈ}ô‰ˆÄo€TVCšÌÒ|wdÓÊJ# 1í´`qzô°´­h@mgZ±Óu€ÇØ:ë:ôÑéHyfèQ l­©K}H´Àd¬/4‡o¨Ä6‹ú¯AN…–;}’Ó± =ºõ£ì?¢ªÓét;kR4jŽÆì”rÛ‚*¯hx½±…ß>k‡_Ã+EØBˆÇ)°¨ÂtHÑ€f‰awH 4ˆø>˜X’O´NÐX¾’ƒÞ<éÄP!ýƒžiØœCÌñÅv8;è( $jGé/áÉœ*ñ&P„ U)ŠCnÇãqÇø•ÃRnÁ@ŠòÐí¬Ñ+(‚8¬vwýh¦68½ï¨‰_vùñ£o€ØHôÞÇ-¿D›–!F@<œ,Ç]¨,¬|À_41{D0߀¹¼A™€ê±Ù;-ˆafùA…¸8Æ7) * ^Í‘Œö‚Œ¾2ŒÃÃäÎfÉlæâ(" %†ŠVœ²3sã 0ŒÈdA6 ~9~ácˆ%ï³Ñ59wôDr¼Xxj$ÀÊÏÑ=Ïíp@ПSL ƒ8ÎÄ‘…FñàG3ÀäùÉýˆ ¼\C“‹$ëì>t€Ÿ»D±þk^8i…íÆ:Ìàì¸6j8ná[ª8!>˜C>×Q" p¸£ZXÇ|‡õT¨?*;kËnT6^@HTPÂÕò)c+šÏd·+€rÎHåh`Å{3§FO¬P;jqð/ ËÓ0íá"²Ý(YI<§õ€wIÉЉ,ú 9áfÞA#ŒgQ ©›DÆdF !©Ñ"¹út…DX ©JÇI‘Œ¶}J 6Ÿà‘…âG®VžÍ€]J”‰!N"·Pãöà’#!ã:ßomú­@Ô¸!Þ n€O%&X.sUgüŽ/Q%‡ d=Êò˜ÃëLDÈæáÁ)N±6±Âõt³&dìüòâv1ц¥HcÿÆ[wkÓßéKâ"5Zd-[/ëp Šúã JFZøucÒh,|Ïâ'Û¥›1]qÀ#"A„+Ô7;×ú(ñí?âË¿>†WêWïsT±&¼µ´G³±A±ClCh‚×§žxŠŒÉãÿ"&¤¼¤JOÕ60w¶§ù(,hKwûwt"$I®Ê÷Þ ÕK`Šy·šJb7¢»½špÉ"ÒïÙ2Dê¼zKÉL°lʵ,q§ yÖα;©EmLôËr7ßä ðvê–Æ$Ê®<ðb^ôßÊË ù|@lC•„k‘Å¼Ê ` Ðg‹…!ê1å>ñòçðxÀNM¾1ê§=¬kB†ø¹V,{0!k,&cök\l†T¸Vå¢ i@½šu3»ÃËRîÔ} ŸËÛÈɼ˜Ñ4W,Lé&¸ÈäøäN¢Lj¼"è DgOõõK~!î"FÞôä’B(Œ\•?á* ùÓyüI””ŸÞ0[°–·âXXÉÍ1*4äg È,ÎÝ+›¢-¥ iu2G!1ìç_y†Æ4ùßÖ.PÅ? Z‡ÑP¿#» KßeÇç™(*kÅñû›± *œýÏ…8¬)ÐP;O°RÁòÜ£*§÷=ÈGû …„pŸíØN5ŠU‡¼ §"„2<ä£öÅæ·¡|¼i}AKà«Q4o S„}I ZLcWѸü­RETböA|ÄtH3‡ýÒ´w b# ó䑚qÈ‘>2Dùéiâ@µß4S-üj-§ÉÏìgA?Tó¬ñdøõÖñ!3tY9)(>#†E(U"ª¶r|Sd æ ê¥6´qÀóÕ\³(«Ö[$•w+zå†P¯–!Ä cÐ%-„þÎë '莚‡2`ÙL€‚W²¶"4JÞÀqGÉ[HL“›G_õ@EžEÄÒc/ªc†@™X²ÃÆ«#,Ã-¬`~&Ž£¶ÿOH ‡®  É*š†ÆD*¶,n-Àà®ð½$ð2²v+y¨JÚ\øU0‘I)Ûˆ ¡þw †gq;ªHRR2ô¯µ¨Ê¤3¯ .s0:B¨ÂœÓFyzÄâ],–„yéug&× ‘¢JÒ;„uè @díx@|Æó¿ª‚<)À4®é¥ófÓúÂê (×Z|¬üúPX0 ý!–&…°àŠ.Ó3²èsŒÈ–Å·ˆ`öx'z¥O(Q`÷#‰rÜõI§“Z°­4£fW,Á•€©‚ÂÕ‚8U£˜ÊwÿÀ¾ŠOaæ1$L-®™›~ëÎdJЧÊR'F‘*Í| ôðB¼þ&_ÃaÍe®„ߢå |ÚqÁß\,.}Œ»ˆXO|ÅaM‹Bpÿ‹`¦69ÍP? ‰ÂÎ!‡áà`ãnÎN=K"†R)çuÝÙFMÈ™ %_nI™Ž©Î€b3ÖÉðLrªà 0ÊÊ î¼ì½ «mUL–_~}°²§)ÈùL%K9 Ž?J’`AšÔfìj#R¶ÿ¬‡(ĉ`Þ¶|£+»ŸvºëÕ ¸¶\IÿTé(ò <ÚIDåÅ)ÒšŽxwáÛ¸öÚ†ð1‰çÈÄšÇˈÐ+A‰¯Ùíàlñ„ù8:$,bëjÂé#u8.Y0màëlD6Z§uY°%ìaBô9DZZÂÛT7ߤ¤—@ÁË›× }†+¥£ÕˉOzûJa0x@éš×í¢"Âí¼ÉL¡†üÓ¨‚K’úàí§ ¡Ì^шdY߯ØDrÆi²ÀþèŒm­æ$#4…z Lߥê,ŠXõœð5ÉPÊ¢C¬TzÂ:S~€Ñc ùrØÕóë& ²)àöF k"âddJ ÆLX³H8qXÌ\Ï¥°rbǬ+“RÀ¬Á‘r¢U‘½r÷yÛs åSlì&ÁXÈ^}1]@.múÈžÉ^þ´sõ‘~ÈH¶>ß$ØšÕ:PÅþŸïD~É™=dÛ®Þ¬+=3Ýðƒd9Cë+,8Xè'¬ž£Õ’hÙ ¡ÀõÕÜ_DÔeΙîÚ1²G¬˜°ee6‹¬­HÛµ’«¥’„ Í l†2¡2Â[ _²$dõ– ¬Ž_bßdÁBÇä΄â]¨Ù#p@ÚÉîÙ]sk%8—b}h²Fq b]aØõºÝ3ÀePÉ]²/¡ˆÌ`Xö¦Ä!÷Ùglˆ0² öY Ak|¾~/‚Áí9€+ÂÀa©í úñy°¦òóÏ—žNJ-S@¢ï±bĵ±¿µGHA ©†›ž¢ÒMÜX‡è~û1趃fÄ–ÃàX#?„>M°þÁË龞äˆÃUƒæp •൰$‡¿Aì'œ$Â8‡+®–Ûv¡ ÀìúìõƇy–ãE\°È ( ôæQUàZ0ºÆ¹%¬LC$ÆgЙL‘Ñ×*(_w`Ï$Öè*Ì!½A©„/dM®>® Âä¾N)Ù"[  :iõŒ”Lf?ië ™V†Üœô¯Ž‹%ݘwÈÙ_4‰0u;Ê€KTØ‹åÓ¯vW:0ñ½Ó'yW¿›òaF…|Š…E¬µŠt“6“ ½ï­¼qŽ‘}¶SdÙ=H‚›{D ˜Á¯±h:·¤Ød©Ì‰ðiÃh˜ÕâCì©ÍÈ!,•4Rç I0²ä¾Q³”IIª% Ê{Q™–94A†…1þ벸Åb\Ú;`sG#áÀN¢ƒOàË&vèk6£ð|&Ä¡˜r´ë°F›Î’‚ËðÄËPȪõ΋–‘):.D¨×ª·nÑQ¼VÙ$åbüQúû×EniB Žt“Y•¿@Tyã!¬Qcž‚E F´:~/d»Äë}äÄ„ká1”?眈äÁ(t΋Üç@³æìËpÀXÖ¹v 6£}-¿·ªÐÖJ·µ‚p¶†±Œ€ºCnÑë5òÓgXþ›(9ÿdbbOƒR $2åã2FqdÐ^๣É*Ã~ø”ÜäPo’b!"üËe•Œ¦T»¸©™°÷c$u¢(sØ(xÝôbr<è®yL7 d«ñíG•ÔiˆÑ±kn§+Þž· Žeuýx¿°xW8+pÿªŒ£|u­d§ZhgiF´¼<–ÐïÉ29ox²0ŒS*xl‘ð¨ø{ÑØcÄn¢oÊÆ}ná»Ì;}$šF©I¹ªô0óüÔè_v²,ãŒ_Ÿø/‘ºdI¢³3d¦(\_‚Dʤk+r–I( ˜'‘ldGdÆAAÁ¿ØâE0˜¢S§›µ¡³t9æ‡nÎÁ$äHˆ‚ú»i‹Eî{ R¸PöåÜReXk§#0iC¦¥¹87KyjÝËT)Š­8r ¥v ¯5U’jÛÏKHÇ=±(HÝIµUÁ°¹?‰… ›6M¥Tøä½Y,™N¨ ßÓFª© ð E€6„Tˆ~}"". µ" ‹µÞ¡f"‡]5PñÃÜrÏÈ2àhÄ 2•ƒã´=€%µ³Â$æ-üKÅ%%µÜ9Bήã½Æ§ô$9(ý£dÔf- MR5læ¬6N¿˜ˆñº©hSd¹ìSd¨cŒë4•ÀÚº :è¡— Úè Þp ½d®þ"$”¸nNZñ)oˇ¶äú9Ò$Æž÷úG쪨‘GÅGm$ä º‡AÃÙ˜ÝÐ2€ß«–tŒ¯³ (Ž^¾©MU PÜ=Ê9¨ð¾¦5u¼|O=ÂBúóc‹¾Â‡Ë¯½uZÓjîpÀ!bU|ªÆ ¼8è|ÕÒwß”œêê"~©ºÑ©~ú”ž£¼°=è£ÿzãBn‰–ž3ºÞ õßnòÆp]ðYº»£†£¾á,£ví®¸¯s¸NË@—ŸGõÈ;_Ø_39ð¾P},¼z‹bâ„‚0•ÅŠ•»ÔýÍÚ—¿2e¼Rü9Ù;•~Iøïa{²lÿI2ãpí«ñ’âñ)⺴§·#fM)8j.bBÁ^lÈï‰g+#t8×SƒÜw@ÝYs*ŠN˜‹d¡fås†)‰aàžAþ^"óR¹J^¦î^ ¡”†ÒœIÁ;BPÔÖi-¤1ŒÓ_ÒR“íó3šƒå l‰ÝœíÈÂżˆî+éª#à}j«ÁËÏëèSëOY>ióóøxÍ7sQ&øœ¿Ž7Æy¤22&.Ñþ"¬œâ\ÇvM·|†ïÔ›|ûB@%¶ufÝ0:™dëÇ–É{¥X!Â,ŒXYÍ0¶ CFn¤©\Ä ÑŠdb»~ˆå~±VÈz±K,@€ÀÕ³ C?U¤í—&@²·Ø±Ýˆ/½yw2VÒ˜&¼DèzN“Ü©d³# ?Dj¾8QÇ|iâ+ŽóÌZ=1¾Ï+¨ÉwÜFxŠl_Øß¡_±´#d+ìT¥öµüTBeàÚ. àš\¸YP°°ïA¨t+ v/™a"ý§”¢ì>~þ«ðÑ|ˇ¿ÔíÓºŽí8¤é“·"ì‹~º‹5h:¬ä0ìÆÖšŽ aì˜z‡ø¾ÑÀB34'aßÿ/Vh­îÎøv“^ìû®íOGvÞÓh­4?g­ÖM‘„yF2F~XÞw¶_©Âœhi·C¶ñ™Ë Z1¼Ä‰ƒ–±˜•†ÖCZ5ÕÀgiPÕ—K×#9ŠT5«1]yGÓ¤:OHÏǼA›ÖæEàëaˆ”³0 E}jþðqX% Ÿ§s¾7ȉ‚ÃÆ2¨Xˆ蚃Œ`ÒLªAæ9Äè¬Ä3à¡5)]Ny­\~‰0k£ÍúT«:/ØžA ƒú2º÷ŠÚOñ׬G¦d‹¦dCšir“è=~‚®×)íqæ ŒœÈ Ɉ»*bv¯ v8Ö§¾®ϧ2 î-DaHV„5ôÕ]F¤0U=Nü(U' á¼ÐílÚ¥¹¾‘`@–ÆÌt¦ÊÆÀG4(˜ÔUÀˆ„ÅHj9‰RáH&”#ŠƒÎ5Ž: Œº^˜“Ci6äXDHïuÐŒ{B Œ®ç)]ÎIˆX8-\¯I¤cl=P¢Œ¼a0лQ m(=¶fŠÚIo’–: Í¿/Ÿ€L7“Ⱥ³¢@§3¯™×ÓfâC7<ëä9Túk±ôåž<{c„8[1<Ë00›yÐÃ<à‚Ì_¸²Ü;Ï»+Ì%_¯%\ÏŒôT€ŸÆÙ=×G¯¤§$'WîÁ£Â9ÀˆÞÏt †m"Ĉ ½ò ¬K?Ç+W`)Ï7•š¼¯@1 Œ­“õÄ<ÇS/S2ga\Í-¬ _YÀ•Ó%ŸMËÆ{EûY¥ã26\”ŦƾÅ(€M“§¢'gÿø@¾áÿeºÿuöæ$ž©QBÛB/ojÑ?…ÓÌÈ uØo[ ¡Q…j4¥¢Àš e=¯¦µtÖ—+˜Ý¼ÿ"œÂ2üC‘w^Ø@¸·o—•íNh«rUa^Z“Í­7𚟔D£ªéQ·ŒH—$¶áà×½Ñ!_ü Vò‰´ª’¡Hk£Ñfý× ­¸°òâyLÔ¥¼Ô´£»^<ÛÄ,Á£2oÅ»"Î[#T˜•¬ò‰ôÒá LôµKl颢¤sfá‘[+çœùúQ.K>•Ü´ÀË)ñ¤û:¡xýäÕá×°Ün¨²f|‰ ¶Luño#›¸!w-Ÿ€c‰Q"xýðjÿ K ˜ý?7‘ÏŽL^ Qª/§ca¥Xô2XäDSs¯«êPxP¤ÁÌ@KU‘P*(Q°ÀJ9¡Öðæ…ö:zrøèѤ#SÆhŽ™œb‡©Ã¹hÐqA^ÃwHN|6;yJx7`8\úL,0¿2}‰ÎOÒrH ÙÈ»Œq1ÁGs0Ž–¡ûÈ¿3¯¬-ÈæB]x!åÆ5šs”<ÖÖÁ¿edÓ, 2\x.²ÖÜ&–› 50\wÃoš¤„åi¢˜.pÙÐ_ imË©¨ãŒ^c5’5.u;Vm1ØØóuˆ~—ÌÆSÑlµ2,›ç‹¨%5Sr°JÖy<æU=D*‹ªÂ2ˈc\Š”KhpÑÜ–UUÐ’-äÉÃ&‘Ó¼XLM‡Í¸Ž¡   ç™`Ëë#¿q¼NTŠº³+…šµö˵¡)í‹K‚["c­ªézƨ­ Å4]IÕÙuÈk‰%T²b˜oÎL–T‡¾ÇæÓtÖŸ§€¨ªÕ+[SJS6‰Ñ•1MœpµìLŸ+;TEÎõîè™ø(öEÒqä-­¯åoø Zi}“Ñiɱ6÷åûɱúТîç熲ßåñБžC[NÖ˜¡+”w–(;Øö¾ïœ®øX À„¬ (SôD„……fì… .N’"ÊW˜©“lüHS)’``æ× ë&B H<0ƒDz'ˆ]à8-lBMnÚw€r§I3¦K”,E|Xi•!ô´œÉ<°¡RåÂ.ˆh–Þ$qÁiW¢­£¹í?hŽ`íÒàÌFÜ7R“š2@„@Ä·y6¬s˜7)–Q±±4.2е5o‰zèˆèÔƒXñ ÆŠ4fµZŸ2$C]<…–À|q`˜öþ&»|I½#àE\‘(mU­½êÿØXvÂôiʰ–Sî-ÿkfϘæM°¶Æ•[8ØŠæP ”/«ôøZô¤U6³õ—ýé~2É6x6X ÷‘N!õYzV wÐMÝ·ú w5É©ÞQPL”ë€.‘|m¤Z¢™†1r·u5 0B3ob¥¾rJÚZ¯%kö‹ýµ¾kš;;õSC nèzA‡Â•ˆþ̲-/GEÉzqI]¦X3‹ä»ƒMÏúM‰&ìwTì0Rö¢åº«x,=& t× “PQÍÆ¯étdËY‡. HULÀÂÀÙŸ 8¥kލC|EEÄJçÇ»‚O§^£K_-> ‹zòvF°®‚RÀ(+€•½Ø{¨Ò¬j¤£gî‹$Þˆæ·æ¬ ãlq›¼¾m|ø£°výå²ìP»³OýbÚ^ÒÓ4rHÆñûë%°e¸ ?|LD×9¿§„x|¹ïN|jÅæªyÑ'4—¡–Ú‰ cÕS'ZVò8ü]Rg¢xFA(xˆFé†ýº¢†R›Gˆ2œHÇÎ8Ë{Þ¿@/Ì8âÙð©?Å[ÔQ háê7ô?ïH¥Øà/Âè¬AðБĔqë–aÅáp«!LˆôL,ÀÆò+`ˆŽ´­©X¢™@cׄ‚“”`\Ó(Qb>ûæ÷ -«˜#'Äó²H(€”G˜T„YQ•…Í;9# eàŒ¶ƒÆ=g KpžÈÜ”³„B5Ž?4‰Ø¶Â¥ÊF' ²ÕÈôvzL=‚4Ú¥ÏScŽøg%rßµf*Áz=b3ß“×ÀQ›”¬Ь,“¶+¥UZz»¤#Ö:QC»“Þ°Òè?ú­?ÒÅ~h© Åû~à È^y;ø‡`ëbIî]ì‹ûøèw,°ðv¶Z¼× z·d÷©ä¾/jßÎÉ,©¶AyZÖ|4SiÝà’¿ rÍߪY/ÐeϺhf4eÑ·éï©Å9„ïð~.)ŽÐ ^܃êÌVÌ<ʉ¯¿ÍVµ€d âW!Z‘ µ0Ž»Í ej’wFºÉΘOškš†óô`ÎÃ0Êùj5f…¶6CÙÒ?aâë¤E3ÅܬȘm’éèyŒҮ¤ò^Ó’-9 Íe|;Ÿ€„’ÌA˜Ö$`=>ãP¥ÀõŠÅ my3@x­à±Ps†ÄÌ~Ñ”‡°óCžˆ˜„O>Üé…P1!"%cYaòWÜTO¼¦]§,=GíAl#‰€½†»× =Áºþ:~@EBÔZߪ¶ušVtÝž"bæ²Ã®ÌĦh@Â@%Åâ^/2 mŸë-„ì+¢Í–Ç#XµØ÷xŠZýËJ•“Tnê¥w¨D@"6¨ @ë{Zµ5s­[º'.}ø¡¦Uä#jڜ⋛'.'¨ˆ¦:k©hï!üï'…ê¤ÙIòc“™9Jɮ̒]臨©…º ÉsŽqšq¢oL{’™_¹SDa¢È`*¥0r*¦Ð‹Î(aBò+3C(xŒG[OlT ,ó‹i´Ž®d¢¯À°^î(¡Ö7ÏCÝê­6§ÉÈàAáL¥Z4!) ÖqÝ?N¨Tí'í‘/àHÎK$èLVÉÿ•Ålœ+„„œG޳Å÷”Ø ²ÉMG´« [\J 5ÄxtìDïËÅ;¾{uÔÕѸXúa@aÃ84Ù¤E^¡àͬÈr‘Caÿ¥µÕN‚yvfÙù%»QW–áÀU»TA0Ï¥æk̘J|g*oc8‘mвºDbQ`íÿR´ÄPEpZÕÃåÖî $ùSƒ¸Þ 6†5‡Õ38¶,¯\ØWŒP+±Œæ2  Ÿ‚ˆåp¢¦8²t¸uÐ%!„åµA)סû=6ÿÖ±’‘à7¥¸â²70$ÏãÏòbr—ðø©‘HkWÜå þFôø6†óô“ª=_7r uÑ ^D+xÁ:x“§S™jr}÷°ƒ’„’kI,ö ޵Pü¹îÐJ–Ô`Aü-pÈ”Cjâ1~URŽs¸ƒõæòù§à“”Ff—¦ÓR:å¼8àQHÙÐM @i"Ž˜@¦ ì£ðdîî^l¢ïÙ–H +ßd3ƒ „ô#7?ó¢º:çžu§³e( oŠhgaw\…µ&èížØæŽAèãù’*àá·ËvÊd¾¥=š`±l8­7à#'Ö'9ìt!þ=lþäªåý½_vFm«¢8¹Œ¬uP™5󺚀Ís©<sV `Žè{9ãs“‚á–ØÕ w̵Ða¯ð?umïœÛ®‘ÓŒ|b­©¸ÅEcÎ]š ÆÞ5¦%Ø€qòÛÙaÜ£¢ d„}h© D¡5 :mÉ”8ÀXÇ.Ô0¬›'¬ˆ Ý Û‹Àô«"·ίË^Nk˜ØLðć&~ùíY„ã¿b“!¹qsã 0“)º~[)”€LX —ÜÒ-ºiýþ| h&^[fw¼žR¬X€”€Õ½± Ðýx0— ؾ˜X~l7]“¬¤F,ÉYD¤zãhA/ºþ»Èi¤Bƒ‰ˆ\ÐrèAÌì’¢œ 'ŸV'=¤äx0\íLWf®Bó aÎyì¢rïÜÆáiˆ“¤x°;øl@ì'Óû€ ¾qÛ"#l„[]Ž© €­U7¬+_»B¤!ŸçJ)‘øZ#Äüd€'¿ÃL–º `ÉâØÁÑ¥řެ”gbÃo0±ÅÚw×ÜÄA ZRdp•Lþh×Sl•7Ä8óë'Ó•p ð¬ üº ÑÇëKT\4¢ÓI” ¸û&’ÊΙÊ\1¸¾ù,ÃÆ…Ì9€ÑfwÑ*ônFÄ©ÁÌpÝðωý*‹nuv\ß@—•¨`*>¶º€Èm"x2x!Y÷Çu¿?‰Þ”íë&@$SÅ4Æ›­È˜"“ã•¡˜ÇÓ™2ò¾-7¯ŸàZ м~ó4ÁxÜ K€±`Œ€ñ,Wl¨r†e²ã0€ b0l?ŽƒÖÅúú•¤B]ý 5ޝD=D…”ÐdÕpdly#)ÿ8À¼¦8§`Yž(ÆÄ°õ½ |€õnH—‘×`m ÄŵNOs#‚»ãˆO=Eù-bfœotÂ~˳ˆP™óºÖòGô”!KÉß>a_Ò!xÜÇ.ÃòMqÅSLˈf4“ ^R ä“XE ]Œp½JšНSvœþ>؉°lÓzX¦fr8<¶ œ6p"”…q”£¾4®Çã`¢qÄo$26=åUÂpJÃ{t“Øî Ïc ƒ‡qj4ó÷P"ŠY¦‘å`q$ÇxÐK>Ùègj\…GÁ³‚ÛØ X ‘YìÓ¨!Œ™A…òàó"¯ß’hs½30ˆ¸¯)w˜½ ûôý)•e%s–÷PÞõê+`ï\Ò¢jýƒOç…ðð)ŸÉ•/Ò@ðŽ,O™¢£å¾nlÛ¶ü3˜a¬ AΪçvÙÜàø  «³¬¼%éü‘V[§ƒYÉ"]_^žÈƒA~T!éÙÇ0ƒ,û‡qº(ß¾I[Ù±!GO3eL1Á°?1 P1v;o4ü‡x-æ,œ¨-‡@J-³º1Fdî¥m êDŒà#ÐÏÁÏ£Nyr^ôÅ–.3b®! úSµ INí$â @r(s+MM‹ ™[â,.á“Ø’“i?â ‚ Bš F ` ·aD?9<ݳ÷Ÿ#ÈS&#ymÂA–h+üÝ­~¾r‚üÂV±øa2õ`†¸£`¡C'áÖLã|ÆβýSÿ¿ðSëm³/•<`/ã?û<|•Œsb¥Ñ“FŸZXq¡fáE…˜e º?űÑËÕz ^}l£ÿTléÎåÿ€ýá¨}N0L˜ jfÇÈDý™8Ùåò¼X¸“Bsí¨á…ˆÂÑ Ôt ÁÙ•H*Y*øv M¸£%ÎáR‘³°‚3ÑSvºá ý¸ï›ŒT­©¿> îBâõŠk¯AüÂB­jVB­‰©õ[ÖŒŽ#¬vŠŠ~TÙ̸í%œL$Ï5¹à‚.R£a 㵂qq^rሩñû sÌ.¡¾\¹N•Ûå”” ¿öøá8ðùà²î“±P›i®AÂÏ ÄÂu`̤']0QPbQ…*Ü(@ó‹&øÉµØó²}*¢Õ(€!ÐŽÜœ:}Å£ëv„Mqéºì$Y npÖ™‘9³jFŸ«<̹™nŠkš¢,M#IÉohì@1ªŠˆ5±`¥;Ê„j ‡Ô¬'Š¥…5t…Ë==ßi9µâ†iä‚5[O)Å)Jµöd"íJ5Ïdȶß4¹,á?‹’ˆ3t‚¡‰ä›ZE•[Ý>j€ ¹%.!eÉDÜžå9û„s®µÁ§ÂÑa Lðo³!^]y!Pñ0XW‹%Éa_ï` Q„º»Ág¹ ,’o†'¾uFÂyý~0V†1¤yÔ—{DÙ¬²+~C‹æá ëNp‚ÎS½«/¨§ÉŒ'2J~üë˜k(wÞk^ ðåut PÎÃÉ_K’„h|¼çàˆ£gÆG›ZË­4dd`=$‡hÉ)ù· ¶¬j\ˆ‰zóÅ3ãJ?X*7 9PCöi—õk& T–jB¬£iŠˆm™ÊÄÅÚ£ «Û£™ÒX J¹)fCZzºÜ,©?96iw ÉnâEd‹çå@ÀØ…}µÅßGE3¯i>$ãÉölVo; ò ²:c$AŽ-=iuB—&Ì&ý• !¨6‡ºî©ØLÕæ[’¾"¯Y„âÒV!ì` œ6©QeH)Y±$ÅÔ+$*Ÿå‚oøD×pIQL$'›ÿ¢’©Wš Œ}€å©×߈ õ£žˆ¯¢ŸÜÕ ]lNo6½:D #Ó>…v€ðØ7^€x ®Øè6ÀvÄÚ]æµ÷&äÍv™:4§ÀÞ¹ Nœ>„ÿêë¤ïˆ¬ÑTÀÌ.¹‡Â³Î ²˜xEÞ!-ÐCnXP¤³FY6.N„Ø=EšóÙ"Ê“£‡Œ£¶¬¥àÆš¶iŒÌ/lrìbCŒ â&U«±G;vHGÝ5€¾Ô4@¥4ì…‰0—F|ÿ’ÅÓàŒ`{†»ÂWÍ-[ó•¥Õ#çP36e˜ã“iã7ª'Í $sG<2G~_†‚Šy¥ÿɯ@Ÿ•C•8pµ˜¾0XmE"h/iK›¥ù"Žâï$êünBÜÑ?q?º´n>Ñn¸ó€+ /^ãi`Þr.,ÚŸ×èÆ0 áÌyÉNiºˆ†‰e—s^E¤‹_ ÿS^õœ$,ëk¿Ç†FGT¬ m¥åëyˆóóUï¾€”Íè V (:Ô½éñÕÐeÇDÊ;÷9d®«)Lžœv#÷žÇ«ñ¥Ê²ö?Ã#2(zœŸFÇÆâ€pÊdõÛÏÎJJ2cWÇØo©7öWQ{A* 4Õ£Ö3—ÉW(ì—LWzee—ÎA‰/“é잦ö= èô¯ÑL{)þèöˆ-ÒÛ©ú‡Põ÷Žð½KZVöÂÒ®Ú¾™Û "tÉÕúaßè‡È¥éj@îî`xtæjúf8,Ö–Äì@‚:À×É‘?¯ñaf¢PV°¤TúS¾ƒRÅÛõ0'ÖX$)Ë´˜d² p0i4oººô9ÏDˆ¼V€ÎwScWÓ,%Ðúë‹Ó ;àq' #Œ¨.Ò"=ma –Mš,&Atß‘¹IP¬{f×èÀ,RÉ?YÐ#šÚ§ÃÄ­Ä\ŸæÏKá…a!ß‚dØ"²@NWÚ9'»"¤È»lRÚž=.<2PûefD$5ûëüñ·cSY­–uûWôœªÜ€Õ,sHh}Ä1:hpÈÀ®êÑetN è×o…m’á„>ì¾;'Ñ ÆÂÆú;`‰úSƒb”]ô5E‚Ž ´¡ ³ÀªÇà-%¡ág¶lÛJKnS¸u‘’b_Y¢©H»ãÀÒ'`4¹k0Á›G1_Y§ÚÃC¦47|˰FÀC¾Ù% [áAœþ Pùp¿Ðbl­$ƒ¾BÛ0°S^}^¤k‡PAék ™8DôÔˆÞÁëû½¹á²¨Ñ£ãz( S§–Za¤_ºÆÀº£@)È x Ú‘"Å ÁX+ÙÍÑ®ü$íH!yx% ± •I!§Y넼Π`£lc$~)±*§+´-¹WÅ΢È{îcZPbƒˆQò£XʰڨIö’~•cð oJ}LCE×þ¼!w@ð»y¸êTÞáG{™Wh2ã;n-«'¢Ûðó½Óï&½Ù¹5ÛÅG{½Ê¶”gsP‹F²8ºŸ„´Õïúü•¶>ŒÝà9Þw{<Ën•óÄì=ЀMàuXPƒFÐÙ®ˆy°ˆ¸`þÙZ.ŸÒÞ´´MÀvüà ±Kx Öš°€îI}D) „ÆkÑá0Bä_°yiRí"‚9€7EG–sgYcûƒ[)ŽVçÖÊl3ì…G=O9zÀBVN¸ânÄZâc¿ NŸCäl®UÕT9 Â@÷!~7è½lyðB§Á©ì%šà!Z•jò’Q‰l^ÅQ(2€bu%i“þÁ‡•YAdÔ˜;#æ¬ÅX½ecÈ™]ÔEñŽ=’ƒQ¢‡—CzùÄ6ó0òQ-œ‰=,ØßâÓKxE掟Áelë²hYÎ % åÉ:ù¥C~¦@3àà33§rED¸CÕZò­PŽÖ‹3‚ñ³(â¬/|MR¨Õ-¦=¡)ÍF`Ò2ÈGÕޤ3ÖË"íÒˆpÕy¶»ÀàCÌR˜1LÕÀÄC«GK3úå=‚±ÈŸ˜:V„PH蹌D»•š©*u&:î%f"ÅëM#a©”ˇì—qæÅâ?é]KM—BÃy6Dm~Ä£Ñ+m-æÍ«äÂÇŸÜ=%6bÍ2ú1Ê"Q¿4 êa_^ê¿lÖ¢¼Œ™@tÆCËY_‰Ù¯Ý²ì lÊ‹¼2.jÓK®ÔÁ*Ä›þžM`Gëá±£j'êþT’N… óÌ À…øõÔ·ô]a;e•y`ƒÐ\>¿*Hðw3÷‚ÜÙÄ`=„çgÖ?I_µD*`1!bfvãæV¾fÓþÝm— Ñk_GçPðuXT5"ÃVîɸު\îhL…“¢¬t•G$.ô®äM¾ 6ôØŠ_Lwd¡j!ˆÙ_QvÅ Ñ tÇDÖ¸5†’l¿‘Ø0~Šˆoдa— îÀl".© ¸(.'%ÆŠ<ïePœS‘ð?à"Ê¥çáa)®€Œ?q^ªIÞ·T¾¹†M"á·/PÑ À»ÙlD2žÉ„Ñà9|ÑÀúÉ™zÓ)Ìp±$­`VÄ"m äÚ3–ÝüB|U™ÑGHcƒ· :'_|ZBá}ï\† dûLf¦G´ƒ¹’´Kl1mŵ¤7}x჎9ç%§Lô#„PVq¯;ñ&¤ª`ië5+>i„‚ +þ ö?ª,dÁ£hL°Ô2|M _|:2ˆqcwUÄýdCÛ–RõR¢¨7(p!ÐÓ‰PÛ)\‘Æ:‚¦y½?þ#` `JŸ­ï1•Е²‘W½ç Î’HÇTñݺÈ…£%çÿaÎÁ*k‘D0߀'P¨Îýô9ä9®½žqé #žâL¢u°äÌ6¼ÁoK‡éAG79CÉdÏ¢š¢0í@…a[²¼rˆ¸H®aß$rK¹L‹1„oí£p~¡‡T !¤;Ì ZTÖp­x aðEÌ6Õ™Ú!Î;ʸMÞ@z‚Eâ©Ó§&¢’ÔE†f) )ˆ¨àù »ÒDîdmë¼2é…ÉïÂû™˜ áiT38ªÂ}An5•² 1>KRÌ ·ƒAQDH1iYË™ZËO”Zb'¦¹0« µXÈ3yĸV¦1$*ÿÌ>DÉ> ÊxÓ=s.¡Ñ¤¶çaxI3LTx mûeU¡gL½æ4QT(Yô,þÐ %…,Ðf3HSñ¤K+G›Opì è)ûâ=8džrÉ6 ApÇQ‰RŽÈj1&ÏDÇF‹¥@à¨TÅÄ¡ÈÔ©¥7švm~6P<2ÍA‡SZM¬Ô–©s}À ±pÙÞd…mb*³gƒL9X‡Ny½ÈƒXÌi“öc÷ßàlüœ“8Ü">¶Íî[|H—öusv {†å„ëÊNË2GÇ*ì ·€yA|àÍ|„»‘K@²q!þA¿-Ëš®å¶Ê·¬ýì]} 2ÜÃ#¨P¤B;P DÁ?Z IØmúIJÙá,§œ(ùaÿ"¾õ©q4sÏp2‡ݥʫk>Ò¦kÛŽãx¨€W”sÊÚÝ`¶H&¡ OÑ)@HÆ E?h|‰@#?uB‚¶jš@àÓ®AD5Ø ï´÷å5…€“£‰UÙ»;&A¥zGÖÌpLJ%:1šÝ:Z¶º\´ùr®0Ч° E€K•3Žyd§ó刵 0É`°š¯ @Åö¸Õ0µ´Úðvú]´ƒºìDô¯ ôÝL!q.Ykí‹ ªtÏê¿×nú^Ômå aWÁ)ß”» š°ŒPøTŠw’¥äI p$(àcަöV]òGC"Zé-ר€¼0fñŠPÆÔwGp½ ™Qx@Q+Ðh²¤æ¿¬ç,TÃPå‚égá§P‚KNsv@åÒMíˆ5B‘¬k:Tƒ:ãºà4'µ) aa0"ÃAr,Ú-ÃÝ´•Ѻ\'G(¢þ'dJ´Ð¸Ðüž,.Çb–éS§Ç #°Ð-Õ&MR 5‹~;Y"éÍ”äUgW*!äÙ³äš,¦¿œŒòl›yçPƒ«3çU¡+e¨7÷é‘´dáp…¼Œ¾ÔŠW;¶ðLØ¢ó9â:(¸S-r§Î«Å&ðy éYãE†n‚»x2Îz'åâÐøö*ù®ÂÎ'ÀÚ3+ÿ‚P(D*X0D0ø$KúàÄ{Šš ñ©é: <ð@u›QÄðP§Ùgµ yLô¦Žò´gíW€ /‰:Ql-6R“òKÂ(ËÈ3Ø…¶åÀÅÛqÎödäóuº8¸×åhŠnqpE«CS(^Ý»åÝ4™¨aq<¼YZ„fOpKd„¤¾uŒÊ$†¼²(=Øîäxn1/Ó®Û·‘®””»L»`˜Ÿ€sž¹ ¤Ý æ% ü•µÃÎDDL{ÈÀa¶p\úÅhÀE烌@š 1"9³¡×Øë0ëÞ!õè´èÓÀÑÕház'2¯x•‚*úÏkœX¿”cÃß-í„ψv@• GR§ µj:˜!s)ÍÎÆ% €3Ћçî€{ýʆýßûsÊ €§R¶M 82i•.Ì}Àø¾ßî²x;…låˆ-àc*Ì'˜·! 0ˆhòdܪù3î/ÀÒK¹*y¯¥HÁÚð£»s*‘ª¼D™Åïðö ÍŒNØ!©c ÄMcoÓ4ßÇ1 Fi“ÀÀx¾ÄÌbß\!à¶³Ëå/•|ŒI÷d¨$²sÄîFñ {#Þg Du1œ²˜Ä¢*v8òDëvqÄ0õsÒ‘:AiàÀfreeipa-3.3.4/install/ui/overpass_bold-web.svg0000775000175000017500000046543012270466515020752 0ustar mkosekmkosek This is a custom SVG webfont generated by Font Squirrel. Copyright : Copyright c 2011 by Red Hat Inc All rights reserved Designer : Delve Withrington Foundry : Delve Fonts Foundry URL : httpwwwredhatcom freeipa-3.3.4/install/ui/src/0000775000175000017500000000000012271707664015370 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/src/build.profile.js0000664000175000017500000000675012271663206020465 0ustar mkosekmkosek// // BUILDER profile // var profile = (function(){ return { basePath: ".", releaseDir: "../release", releaseName: "build", action: "release", layerOptimize: "comments", optimize: "comments", cssOptimize: "comments", mini: true, stripConsole: "warn", selectorEngine: "lite", staticHasFeatures: { "host-rhino":1, "host-browser":0, "host-node":0, "dom":0, "dojo-has-api":1, "dojo-xhr-factory":0, "dojo-inject-api":1, "dojo-timeout-api":0, "dojo-trace-api":1, "dojo-loader-catches":0, "dojo-dom-ready-api":0, "dojo-dom-ready-plugin":0, "dojo-ready-api":1, "dojo-error-api":1, "dojo-publish-privates":1, "dojo-gettext-api":1, "dojo-sniff":0, "dojo-loader":1, "dojo-test-xd":0, "dojo-test-sniff":0 }, packages:[{ name: "dojo", location: "dojo" },{ name: "build", location: "build" }], layers: { "build/build": { include: [ 'dojo/dojo', 'build/buildControlBase', 'build/argv', 'build/build.profile', 'build/discover', 'build/messages', 'build/removeComments', 'build/fs', 'build/main', 'build/fileUtils', 'build/process', 'build/v1xProfiles', 'build/replace', 'build/fileHandleThrottle', 'build/buildControl', 'build/commandLineArgs', 'build/stringify', 'build/buildControlDefault', 'build/version', 'build/plugins/querySelector', 'build/plugins/domReady', 'build/plugins/has', 'build/plugins/text', 'build/plugins/loadInit', 'build/plugins/require', 'build/plugins/i18n', 'build/transforms/depsDump', 'build/transforms/copy', 'build/transforms/trace', 'build/transforms/read', 'build/transforms/writeAmd', 'build/transforms/dojoPragmas', 'build/transforms/report', 'build/transforms/hasFindAll', 'build/transforms/hasFixup', 'build/transforms/writeDojo', 'build/transforms/depsScan', 'build/transforms/write', 'build/transforms/dojoReport', 'build/transforms/writeOptimized', 'build/transforms/insertSymbols', 'build/transforms/hasReport', 'build/transforms/writeCss', 'build/transforms/depsDeclarative', 'build/transforms/optimizeCss', 'build/node/fs', 'build/node/process', 'build/rhino/fs', 'build/rhino/process' ], customBase: true, boot: true } } }; })();freeipa-3.3.4/install/ui/src/freeipa/0000775000175000017500000000000012271663206016774 5ustar mkosekmkosekfreeipa-3.3.4/install/ui/src/freeipa/search.js0000664000175000017500000003704212271663206020605 0ustar mkosekmkosek/* Authors: * Pavel Zuna * Adam Young * Endi S. Dewata * Petr Vobornik * * Copyright (C) 2010 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 . */ define([ './ipa', './jquery', './phases', './reg', './spec_util', './text', './facet'], function(IPA, $, phases, reg, su, text, mod_facet) { var exp = {}; exp.search_facet_control_buttons_pre_op = function(spec, context) { spec.actions = spec.actions || []; spec.actions.unshift( 'refresh', 'batch_remove', 'add'); spec.control_buttons = spec.control_buttons || []; if (!spec.no_update) { spec.control_buttons.unshift( { name: 'remove', label: '@i18n:buttons.remove', icon: 'remove-icon' }, { name: 'add', label: '@i18n:buttons.add', icon: 'add-icon' }); } spec.control_buttons.unshift( { name: 'refresh', label: '@i18n:buttons.refresh', icon: 'reset-icon' }); spec.state = spec.state || {}; spec.state.evaluators = spec.state.evaluators || []; spec.state.evaluators.push( IPA.selected_state_evaluator, IPA.self_service_state_evaluator); return spec; }; exp.search_facet_pre_op = function(spec, context) { var entity = context.entity; su.context_entity(spec, context); spec.name = spec.name || 'search'; spec.title = spec.title || entity.metadata.label; spec.label = spec.label || entity.metadata.label; spec.tab_label = spec.tab_label || '@i18n:facets.search'; spec.managed_entity = spec.managed_entity ? IPA.get_entity(spec.managed_entity) : spec.entity; spec.disable_breadcrumb = spec.disable_breadcrumb === undefined ? true : spec.disable_breadcrumb; spec.disable_facet_tabs = spec.disable_facet_tabs === undefined ? true : spec.disable_facet_tabs; exp.search_facet_control_buttons_pre_op(spec, context); return spec; }; IPA.search_facet = function(spec, no_init) { spec = spec || {}; var that = IPA.table_facet(spec, true); that.deleter_dialog = spec.deleter_dialog || IPA.search_deleter_dialog; that.create_header = function(container) { that.facet_create_header(container); var div = $('
', { 'class': 'right-aligned-facet-controls' }).appendTo(that.controls); div.append(IPA.create_network_spinner()); that.filter_container = $('
', { 'class': 'search-filter' }).appendTo(div); that.filter = $('', { type: 'text', name: 'filter' }).appendTo(that.filter_container); that.filter.keypress(function(e) { /* if the key pressed is the enter key */ if (e.which == 13) { that.find(); } }); that.find_button = IPA.action_button({ name: 'find', icon: 'search-icon', click: function() { that.find(); return false; } }).appendTo(that.filter_container); that.create_control_buttons(that.controls); }; that.managed_entity_pkey_prefix = function() { if (that.entity !== that.managed_entity) { return that.get_pkeys(); } return that.get_pkey_prefix(); }; that.show = function() { that.facet_show(); var filter = that.state.filter || ''; if (that.filter) { that.filter.val(filter); } }; that.show_add_dialog = function() { var dialog = that.managed_entity.get_dialog('add'); if (!that.adder_dialog) { that.adder_dialog = dialog; dialog.added.attach(function() { that.refresh(); }); } dialog.pkey_prefix = that.managed_entity_pkey_prefix(); dialog.open(that.container); }; that.create_remove_dialog = function() { var values = that.get_selected_values(); var title; if (!values.length) { title = text.get('@i18n:dialogs.remove_empty'); alert(title); return null; } var dialog = that.managed_entity.get_dialog('remove'); if (!dialog) { dialog = that.deleter_dialog(); } dialog.entity_name = that.managed_entity.name; dialog.entity = that.managed_entity; dialog.facet = that; dialog.pkey_prefix = that.managed_entity_pkey_prefix(); title = text.get('@i18n:dialogs.remove_title'); var label = that.managed_entity.metadata.label; dialog.title = title.replace('${entity}', label); dialog.set_values(values); return dialog; }; that.show_remove_dialog = function() { var dialog = that.create_remove_dialog(); dialog.open(that.container); }; that.find = function() { var filter = that.filter.val(); var old_filter = that.state.filter; var state = {}; state[that.managed_entity.name + '-filter'] = filter; if (filter !== old_filter) that.set_expired_flag(); that.state.set({filter: filter}); }; that.get_search_command_name = function() { var name = that.managed_entity.name + '_find'; if (that.pagination && !that.search_all_entries) { name += '_pkeys'; } return name; }; that.get_refresh_command_args = function() { var filter = that.state.filter || ''; var args = that.managed_entity_pkey_prefix(); args.push(filter); return args; }; that.create_refresh_command = function() { var args = that.get_refresh_command_args(); var command = IPA.command({ name: that.get_search_command_name(), entity: that.managed_entity.name, method: 'find', args: args }); if (that.pagination) { if (!that.search_all_entries) command.set_option('pkey_only', true); command.set_option('sizelimit', 0); } return command; }; that.refresh = function() { var command = that.create_refresh_command(); command.on_success = function(data, text_status, xhr) { if (!IPA.opened_dialogs.dialogs.length) that.filter.focus(); that.load(data); that.show_content(); }; command.on_error = function(xhr, text_status, error_thrown) { that.report_error(error_thrown); }; command.execute(); }; that.clear = function() { if (that.needs_clear()) { that.table.clear(); } }; that.needs_clear = function() { var clear = false; var filter = that.state.filter; clear = that.old_filter !== '' || that.old_filter !== filter; var pkeys = that.get_pkeys(); clear = clear || IPA.array_diff(pkeys, that.old_pkeys); return clear; }; that.init_search_facet = function() { that.init_facet(); that.init_table_columns(); that.init_table(that.managed_entity); }; if (!no_init) that.init_search_facet(); // methods that should be invoked by subclasses that.search_facet_refresh = that.refresh; that.search_facet_create_refresh_command = that.create_refresh_command; that.search_facet_create_remove_dialog = that.create_remove_dialog; that.search_facet_create_header = that.create_header; that.search_facet_show = that.show; return that; }; IPA.search_deleter_dialog = function(spec) { spec = spec || {}; var that = IPA.deleter_dialog(spec); that.pkey_prefix = spec.pkey_prefix || []; that.create_command = function() { var batch = IPA.batch_command({ error_message: '@i18n:search.partial_delete' }); for (var i=0; i * * Copyright (C) 2010 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 . */ define([ './ipa', './jquery', './phases', './reg', './details', './search', './association', './entity'], function(IPA, $, phases, reg) { IPA.rule_details_widget = function(spec) { spec = spec || {}; var that = IPA.composite_widget(spec); that.radio_name = spec.radio_name; that.options = spec.options || []; that.tables = spec.tables || []; that.columns = spec.columns; that.init = function() { that.enable_radio = IPA.radio_widget({ name: that.radio_name, options: that.options }); that.widgets.add_widget(that.enable_radio); that.enable_radio.value_changed.attach(that.on_enable_radio_changed); that.enable_radio.updated.attach(that.on_enable_radio_changed); }; that.on_enable_radio_changed = function() { var value = that.enable_radio.save(); if(value.length > 0) { var enabled = ('' === value[0]); for (var i=0; i', { name: that.radio_name, title: title, 'class': 'field' }).appendTo(container); enable_radio_container.append(title+': '); that.enable_radio.create(enable_radio_container); //tables for (var j=0; j', { name: table.name, title: metadata ? metadata.doc : table.name, 'class': 'field' }).appendTo(container); var widget = that.widgets.get_widget(table.name); widget.create(table_container); } }; that.init(); return that; }; IPA.rule_association_table_widget = function(spec) { spec = spec || {}; var that = IPA.association_table_widget(spec); that.external = spec.external; that.setup_column = function(column, div, record) { var suppress_link = false; if (that.external) { suppress_link = record[that.external] === 'true'; } column.setup(div, record, suppress_link); }; that.create_columns = function() { if (!that.columns.length) { that.association_table_widget_create_columns(); if (that.external) { that.create_column({ name: that.external, label: '@i18n:objects.sudorule.external', entity: that.other_entity, formatter: 'boolean', width: '200px' }); } } }; that.create_add_dialog = function() { var entity_label = that.entity.metadata.label_singular; var pkey = that.facet.get_pkey(); var other_entity_label = that.other_entity.metadata.label; var title = that.add_title; title = title.replace('${entity}', entity_label); title = title.replace('${primary_key}', pkey); title = title.replace('${other_entity}', other_entity_label); var exclude = that.values; if (that.external) { exclude = []; for (var i=0; i 0) { //no need to delete if has no values var command = IPA.command({ entity: that.entity.name, method: that.widget.remove_method, args: that.facet.get_pkeys() }); command.set_option(that.widget.other_entity.name, values); update_info.append_command(command, that.priority); } } return update_info; }; return that; }; IPA.rule_association_adder_dialog = function(spec) { spec = spec || {}; var that = IPA.association_adder_dialog(spec); that.external = spec.external; that.add = function() { var rows = that.available_table.remove_selected_rows(); that.selected_table.add_rows(rows); if (that.external) { var pkey_name = that.other_entity.metadata.primary_key; var value = that.external_field.val(); if (!value) return; var record = {}; record[pkey_name] = value; that.selected_table.add_record(record); that.external_field.val(''); } }; return that; }; phases.on('registration', function() { var w = reg.widget; var f = reg.field; w.register('rule_association_table', IPA.rule_association_table_widget); f.register('rule_association_table', IPA.rule_association_table_field); }); return {}; });freeipa-3.3.4/install/ui/src/freeipa/certificate.js0000775000175000017500000012063312271663206021624 0ustar mkosekmkosek/* Authors: * Endi Sukma Dewata * Petr Vobornik * * Copyright (C) 2010 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 . */ define([ 'dojo/_base/lang', './metadata', './ipa', './jquery', './menu', './phases', './reg', './text', './dialog'], function(lang, metadata_provider, IPA, $, menu, phases, reg, text) { var exp = IPA.cert = {}; IPA.cert.BEGIN_CERTIFICATE = '-----BEGIN CERTIFICATE-----'; IPA.cert.END_CERTIFICATE = '-----END CERTIFICATE-----'; IPA.cert.BEGIN_CERTIFICATE_REQUEST = '-----BEGIN CERTIFICATE REQUEST-----'; IPA.cert.END_CERTIFICATE_REQUEST = '-----END CERTIFICATE REQUEST-----'; /* * Pre-compiled regular expression to match a PEM cert. * * regexp group 1: entire canonical cert (delimiters plus base64) * regexp group 2: base64 data inside PEM delimiters */ IPA.cert.PEM_CERT_REGEXP = RegExp('(-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----)'); /* * Pre-compiled regular expression to match a CSR (Certificate Signing Request). * The delimiter "CERTIFICATE REQUEST" is the cononical standard, however some legacy * software will produce a delimiter with "NEW" in it, i.e. "NEW CERTIFICATE REQUEST" * This regexp will work with either form. * * regexp group 1: entire canonical CSR (delimiters plus base64) * regexp group 2: base64 data inside canonical CSR delimiters * regexp group 3: entire legacy CSR (delimiters plus base64) * regexp group 4: base64 data inside legacy CSR delimiters */ IPA.cert.PEM_CSR_REGEXP = RegExp('(-----BEGIN CERTIFICATE REQUEST-----([^-]*)-----END CERTIFICATE REQUEST-----)|(-----BEGIN NEW CERTIFICATE REQUEST-----([^-]*)-----END NEW CERTIFICATE REQUEST-----)'); IPA.cert.CERTIFICATE_STATUS_MISSING = 0; IPA.cert.CERTIFICATE_STATUS_VALID = 1; IPA.cert.CERTIFICATE_STATUS_REVOKED = 2; IPA.cert.CRL_REASON = [ 'unspecified', 'key_compromise', 'ca_compromise', 'affiliation_changed', 'superseded', 'cessation_of_operation', 'certificate_hold', null, 'remove_from_crl', 'privilege_withdrawn', 'aa_compromise' ]; IPA.cert.parse_dn = function(dn) { var result = {}; if (!dn) return result; // TODO: Use proper LDAP DN parser var rdns = dn.split(','); for (var i=0; i */ /* * Does the text already have the PEM delimiters? * If so just return the text unmodified. */ if (text.match(IPA.cert.PEM_CERT_REGEXP)) { return text; } /* No PEM delimiters so format the base64 & add the delimiters. */ return IPA.cert.BEGIN_CERTIFICATE + "\n" + IPA.cert.pem_format_base64(text) + "\n" + IPA.cert.END_CERTIFICATE; }; IPA.cert.pem_csr_format = function(text) { /* * Input is assumed to be either PEM formated data or the base64 * encoding of DER binary certificate request (csr) data. Return * data in PEM format. The function checks if the input text is * PEM formatted, if so it just returns the input text. Otherwise * the input is treated as base64 which is formatted to be PEM> */ /* * Does the text already have the PEM delimiters? * If so just return the text unmodified. */ if (text.match(IPA.cert.PEM_CSR_REGEXP)) { return text; } /* No PEM delimiters so format the base64 & add the delimiters. */ return IPA.cert.BEGIN_CERTIFICATE_REQUEST + "\n" + IPA.cert.pem_format_base64(text) + "\n" + IPA.cert.END_CERTIFICATE_REQUEST; }; IPA.cert.download_dialog = function(spec) { spec = spec || {}; var that = IPA.dialog(spec); that.width = spec.width || 500; that.height = spec.height || 380; that.add_pem_delimiters = typeof spec.add_pem_delimiters == 'undefined' ? true : spec.add_pem_delimiters; that.certificate = spec.certificate || ''; that.create_button({ name: 'close', label: '@i18n:buttons.close', click: function() { that.close(); } }); that.create = function() { var textarea = $('