mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Merge branch 'upstream' into debian
This commit is contained in:
commit
4026d69f55
2
.bzrignore
Normal file
2
.bzrignore
Normal file
@ -0,0 +1,2 @@
|
||||
.git
|
||||
freeipa2-dev-doc
|
76
.gitignore
vendored
Normal file
76
.gitignore
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
configure
|
||||
config.h
|
||||
config.h.in
|
||||
Makefile
|
||||
Makefile.in
|
||||
.deps/
|
||||
.libs/
|
||||
*.la
|
||||
*.lo
|
||||
*.o
|
||||
*.pyc
|
||||
.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-kpasswd/ipa_kpasswd
|
||||
daemons/ipa-version.h
|
||||
daemons/libtool
|
||||
daemons/ltmain.sh
|
||||
daemons/missing
|
||||
daemons/stamp-h1
|
||||
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/ui/test/results
|
||||
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
|
||||
freeipa.spec
|
||||
ipapython/setup.py
|
||||
ipapython/version.py
|
||||
version.m4
|
||||
|
8
.tx/config
Normal file
8
.tx/config
Normal file
@ -0,0 +1,8 @@
|
||||
[main]
|
||||
host = https://www.transifex.net
|
||||
|
||||
[freeipa.ipa]
|
||||
file_filter = install/po/<lang>.po
|
||||
source_file = install/po/ipa.pot
|
||||
source_lang = en
|
||||
|
97
BUILD.txt
Normal file
97
BUILD.txt
Normal file
@ -0,0 +1,97 @@
|
||||
Here is a quickie guide to get you started in IPA development.
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
The quickest way to get the dependencies needed for building is:
|
||||
|
||||
# yum install rpm-build `grep "^BuildRequires" freeipa.spec.in | awk '{ print $2 }' | grep -v "^/"`
|
||||
|
||||
This is currently (01/05/11):
|
||||
|
||||
yum install 389-ds-base-devel mozldap-devel svrcore-devel nspr-devel \
|
||||
openssl-devel openldap-devel e2fsprogs-devel krb5-devel nss-devel \
|
||||
libcap-devel python-devel autoconf automake libtool popt-devel m4 \
|
||||
policycoreutils python-setuptools python-krbV xmlrpc-c-devel \
|
||||
libcurl-devel gettext authconfig libuuid-devel
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
From the root of the source tree run:
|
||||
$ make rpms
|
||||
|
||||
The resulting rpm packages are in dist/rpms:
|
||||
|
||||
# yum --nogpgcheck localinstall dist/rpms/*
|
||||
# ipa-server-install
|
||||
|
||||
It may be possible to do a simple make all install but this has not been
|
||||
well-tested. Additional work is done in pre/post install scripts in the ipa
|
||||
spec file.
|
||||
|
||||
Developing plugins
|
||||
------------------
|
||||
|
||||
It is possible to do management plugin development within the source tree.
|
||||
|
||||
To start with, you need a full IPA install on the current system. Build and
|
||||
install the rpms and then configure IPA using ipa-server-install.
|
||||
|
||||
Get a TGT for the admin user with: kinit admin
|
||||
|
||||
Next you'll need 2 sessions in the source tree. In the first session run
|
||||
python lite-server.py. In the second session you can run the ./ipa
|
||||
tool and it will make requests to the lite-server listening on 127.0.0.1:8080.
|
||||
|
||||
This makes developing plugins much faster and you can also make use of the
|
||||
Python pdb debugger on the server side.
|
||||
|
||||
You'll find you may need to refresh the underlying build if schema or other
|
||||
changes are required.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
We use python nosetests to test for regressions in the management framework
|
||||
and plugins. You'll need the python-nose package installed to run the tests.
|
||||
|
||||
To run all of the tests you will need 2 sessions, one to run the lite-server
|
||||
and the other to execute the tests. You'll also need a TGT before starting
|
||||
the lite-server:
|
||||
|
||||
% kinit admin
|
||||
% make test
|
||||
|
||||
Some tests may be skipped. For example, all the XML-RPC tests will be skipped
|
||||
if you haven't started the lite-server. The DNS tests will be skipped if
|
||||
the underlying IPA installation doesn't configure DNS, etc.
|
||||
|
||||
API.txt
|
||||
-------
|
||||
The purpose of the file API.txt is to prevent accidental API changes. The
|
||||
program ./makeapi creates file and also validates it (with the --validate
|
||||
option). This validation is part of the build process.
|
||||
|
||||
There are three solutions to changes to the API:
|
||||
|
||||
1. Changes to existing API require a change to the MAJOR version.
|
||||
2. Addition of new API requires a change to the MINOR version.
|
||||
3. Or just back out your changes and don't make an API change.
|
||||
|
||||
If the API changes you'll need to run ./makeapi to update API.txt and
|
||||
commit it along with VERSION with your API change.
|
||||
|
||||
If a module is optionally loaded then you will need to be able to
|
||||
conditionally load it for API validation. The environment variable
|
||||
api.env.validate_api is True during validation.
|
||||
|
||||
General Notes
|
||||
-------------
|
||||
IPA is not relocatable.
|
||||
|
||||
When building rpms the version contains the GIT id in the version. To prevent
|
||||
this pass the argument IPA_VERSION_IS_GIT_SNAPSHOT=yes to make.
|
||||
|
||||
If you don't need a full CA during testing then using the self-signed CA
|
||||
(pass --selfsign to ipa-server-install) takes less time to install.
|
674
COPYING
Normal file
674
COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
76
Contributors.txt
Normal file
76
Contributors.txt
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
The following people have contributed to the FreeIPA project.
|
||||
(Listed in alphabetical order within category)
|
||||
|
||||
Developers:
|
||||
Jr Aquino
|
||||
Alexander Bokovoy
|
||||
Jan Cholasta
|
||||
Rob Crittenden
|
||||
Nalin Dahyabhai
|
||||
John Dennis
|
||||
Jason DeRose
|
||||
Endi Dewata
|
||||
Jakub Hrozek
|
||||
Martin Kosek
|
||||
Nathan Kinder
|
||||
Rich Megginson
|
||||
Martin Nagy
|
||||
Simo Sorce
|
||||
Andrew Wnuk
|
||||
Adam Young
|
||||
Jan Zeleny
|
||||
Pavel Zůna
|
||||
|
||||
Documentation:
|
||||
David O'Brien
|
||||
|
||||
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
|
||||
Gundachandru
|
||||
Jake Li
|
||||
Andrew Martynov
|
||||
Sankarshan Mukhopadhyay
|
||||
|
||||
Wiki, Solution and Idea Contributors:
|
||||
Viji V Nair
|
||||
Ryan Thompson
|
||||
David Zeuthen
|
||||
|
||||
Graphic Design and User Interaction Design:
|
||||
Máirín Duffy
|
||||
|
||||
Managment:
|
||||
Scott Haines
|
||||
Bob Lord
|
||||
Dmitri Pal
|
||||
Kevin Unthank
|
||||
Karl Wirth
|
||||
|
||||
Past and Occasional Contributors:
|
||||
Sylvain Baubeau
|
||||
Yuri Chornoivan
|
||||
Frank Cusack
|
||||
Don Davis
|
||||
Gunther Deschner
|
||||
Stephen Gallagher
|
||||
Ian Kumlien
|
||||
Karl MacMillan
|
||||
Jon McCann
|
||||
Kevin McCarthy
|
||||
Jim Meyering
|
||||
Pete Rowley
|
||||
Andreas Schneider
|
||||
|
2
MANIFEST.in
Normal file
2
MANIFEST.in
Normal file
@ -0,0 +1,2 @@
|
||||
include COPYING TODO lite-server.py
|
||||
include tests/*/*.py
|
218
Makefile
Normal file
218
Makefile
Normal file
@ -0,0 +1,218 @@
|
||||
include VERSION
|
||||
|
||||
SUBDIRS=daemons install ipapython ipa-client
|
||||
CLIENTDIRS=ipapython ipa-client
|
||||
|
||||
PRJ_PREFIX=freeipa
|
||||
|
||||
RPMBUILD ?= $(PWD)/rpmbuild
|
||||
TARGET ?= master
|
||||
|
||||
SUPPORTED_PLATFORM=redhat
|
||||
|
||||
# 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_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 # 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
|
||||
|
||||
all: bootstrap-autogen server
|
||||
@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
|
||||
|
||||
install: all server-install
|
||||
@for subdir in $(SUBDIRS); do \
|
||||
(cd $$subdir && $(MAKE) $@) || exit 1; \
|
||||
done
|
||||
|
||||
client-install: client
|
||||
@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
|
||||
|
||||
lint:
|
||||
./make-lint $(LINT_OPTIONS)
|
||||
|
||||
test:
|
||||
$(MAKE) -C install/po test_lang
|
||||
./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
|
||||
perl -pi -e "s:__NUM_VERSION__:$(IPA_VERSION_MAJOR)$(IPA_VERSION_MINOR)$(IPA_VERSION_RELEASE):" ipapython/version.py
|
||||
perl -pi -e "s:__API_VERSION__:$(IPA_API_VERSION_MAJOR).$(IPA_API_VERSION_MINOR):" 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_VERSION_MAJOR)$(IPA_VERSION_MINOR)$(IPA_VERSION_RELEASE):" 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; \
|
||||
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
|
||||
|
||||
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:
|
||||
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 selinux && $(MAKE) maintainer-clean
|
||||
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
|
66
README
Normal file
66
README
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
IPA Server
|
||||
|
||||
What is it?
|
||||
-----------
|
||||
|
||||
For efficiency, compliance and risk mitigation, organizations need to
|
||||
centrally manage and correlate vital security information including:
|
||||
|
||||
* Identity (machine, user, virtual machines, groups, authentication
|
||||
credentials)
|
||||
* Policy (configuration settings, access control information)
|
||||
* Audit (events, logs, analysis thereof)
|
||||
|
||||
Since these are not new problems. there exist many approaches and
|
||||
products focused on addressing them. However, these tend to have the
|
||||
following weaknesses:
|
||||
|
||||
* Focus on solving identity management across the enterprise has meant
|
||||
less focus on policy and audit.
|
||||
* Vendor focus on Web identity management problems has meant less well
|
||||
developed solutions for central management of the Linux and Unix
|
||||
world's vital security info. Organizations are forced to maintain
|
||||
a hodgepodge of internal and proprietary solutions at high TCO.
|
||||
* Proprietary security products don't easily provide access to the
|
||||
vital security information they collect or manage. This makes it
|
||||
difficult to synchronize and analyze effectively.
|
||||
|
||||
The Latest Version
|
||||
------------------
|
||||
|
||||
Details of the latest version can be found on the IPA server project
|
||||
page under <http://www.freeipa.org/>.
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
The most up-to-date documentation can be found at
|
||||
<http://freeipa.org/page/Documentation/>.
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
To get started quickly, start here:
|
||||
<https://fedorahosted.org/freeipa/wiki/QuickStartGuide>
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
Please see the file called COPYING.
|
||||
|
||||
Contacts
|
||||
--------
|
||||
|
||||
* If you want to be informed about new code releases, bug fixes,
|
||||
security fixes, general news and information about the IPA server
|
||||
subscribe to the freeipa-announce mailing list at
|
||||
<https://www.redhat.com/mailman/listinfo/freeipa-interest/>.
|
||||
|
||||
* If you have a bug report please submit it at:
|
||||
<https://bugzilla.redhat.com>
|
||||
|
||||
* If you want to participate in actively developing IPA please
|
||||
subscribe to the freeipa-devel mailing list at
|
||||
<https://www.redhat.com/mailman/listinfo/freeipa-devel/> or join
|
||||
us in IRC at irc://irc.freenode.net/freeipa
|
93
TODO
Normal file
93
TODO
Normal file
@ -0,0 +1,93 @@
|
||||
General 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.
|
||||
|
||||
* All "comma-separated list of..." parameters should really be changed to
|
||||
multivalue and have a flag that tells the CLI whether a multivalue should
|
||||
be parsed as comma-separated. The List type currently satisfy this, but it
|
||||
would be nice to have a comma-separated multivalue of any type.
|
||||
|
||||
* 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?
|
82
VERSION
Normal file
82
VERSION
Normal file
@ -0,0 +1,82 @@
|
||||
########################################################
|
||||
# freeIPA Version #
|
||||
# #
|
||||
# freeIPA versions are as follows #
|
||||
# 1.0.x New production series #
|
||||
# 1.0.x{pre,rc}y Preview/Testing & RC #
|
||||
# 1.0.0GITabcdefg Build from GIT #
|
||||
# #
|
||||
########################################################
|
||||
|
||||
########################################################
|
||||
# This are the main version numbers #
|
||||
# #
|
||||
# <MAJOR>.<MINOR>.<RELEASE> #
|
||||
# #
|
||||
# e.g. IPA_VERSION_MAJOR=1 #
|
||||
# IPA_VERSION_MINOR=0 #
|
||||
# IPA_VERSION_RELEASE=0 #
|
||||
# -> "1.0.0" #
|
||||
########################################################
|
||||
IPA_VERSION_MAJOR=2
|
||||
IPA_VERSION_MINOR=1
|
||||
IPA_VERSION_RELEASE=3
|
||||
|
||||
########################################################
|
||||
# For 'pre' releases the version will be #
|
||||
# #
|
||||
# <MAJOR>.<MINOR>.<RELEASE>pre<PRE_RELEASE> #
|
||||
# #
|
||||
# e.g. IPA_VERSION_PRE_RELEASE=1 #
|
||||
# -> "1.0.0pre1" #
|
||||
########################################################
|
||||
IPA_VERSION_PRE_RELEASE=
|
||||
|
||||
########################################################
|
||||
# For 'rc' releases the version will be #
|
||||
# #
|
||||
# <MAJOR>.<MINOR>.<RELEASE>rc<RC_RELEASE> #
|
||||
# #
|
||||
# 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 #
|
||||
# #
|
||||
# <MAJOR>.<MINOR>.<RELEASE>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=13
|
3
autogen.sh
Executable file
3
autogen.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
autoreconf -i -f
|
||||
./configure ${1+"$@"}
|
3
checks/README
Normal file
3
checks/README
Normal file
@ -0,0 +1,3 @@
|
||||
This directory is for integration tests that require a live backend (LDAP,
|
||||
Certificate Server, etc.). It's named "checks" so nose wont discover tests
|
||||
here.
|
131
checks/check-ra.py
Executable file
131
checks/check-ra.py
Executable file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/python
|
||||
# Authors:
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
# John Dennis <jdennis@redhat.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""
|
||||
This tests the api.Backend.ra plugin against a test CA server awnuk has runnig.
|
||||
It's only accessible from inside the Red Hat firewall. Obviously this needs
|
||||
work so the community can also run this test, but it's a start.
|
||||
|
||||
Also, awnuk had to help me register the IPA instance I'm running with his
|
||||
server. I don't exactly remember the steps, so ping him for help.
|
||||
|
||||
--jderose 2009-02-13
|
||||
"""
|
||||
|
||||
from os import path
|
||||
import sys
|
||||
parent = path.dirname(path.dirname(path.abspath(__file__)))
|
||||
sys.path.insert(0, parent)
|
||||
verbose = True
|
||||
|
||||
from base64 import b64encode, b64decode
|
||||
from ipalib import api
|
||||
|
||||
subject = u'CN=vm-070.idm.lab.bos.redhat.com'
|
||||
csr = '\
|
||||
MIIBZzCB0QIBADAoMSYwJAYDVQQDEx12bS0wNzAuaWRtLmxhYi5ib3MucmVkaGF0\n\
|
||||
LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAriTSlAG+/xkvtxliWMeO\n\
|
||||
Qu+vFQTz+/fgy7xWIg6WR2At6j/9eJ7LUYhqguqevOAQpuePxY4/FEfpmQ6PTgs/\n\
|
||||
LXKa0vhIkXzkmMjKynUIWHYeaZekcXxye1dV/PdNB6H801xs60YjbScOJj3Hexvm\n\
|
||||
hOKsdmwO1ukqTTEKDXrr3c8CAwEAAaAAMA0GCSqGSIb3DQEBBQUAA4GBAG4pTLrE\n\
|
||||
cvrkQXVdMOjgAVJ6KZYl/caIOYhIlcJ3jhf95Bv/Zs3lpfHjXnM8jj4EWfyd0lZx\n\
|
||||
2EUytXXubKJUpjUCeBp4oaQ2Ahvdxo++oUcbXkKxtCOUB6Mw8XEIVYaldZlcHDHM\n\
|
||||
dysLdrZ3K9HOzoeSq2e0m+trQaWnBQG47O7F\n\
|
||||
'
|
||||
|
||||
reference_decode = {
|
||||
'certificate' : b64decode
|
||||
}
|
||||
|
||||
trial_decode = {
|
||||
'certificate' : b64decode
|
||||
}
|
||||
|
||||
api.bootstrap(
|
||||
in_server=True,
|
||||
enable_ra=True,
|
||||
ra_plugin='dogtag',
|
||||
ca_host='vm-070.idm.lab.bos.redhat.com',
|
||||
debug=True,
|
||||
in_tree=True,
|
||||
)
|
||||
api.finalize()
|
||||
ra = api.Backend.ra
|
||||
|
||||
def assert_equal(trial, reference):
|
||||
keys = reference.keys()
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
reference_val = reference[key]
|
||||
trial_val = trial[key]
|
||||
|
||||
if reference_decode.has_key(key):
|
||||
reference_val = reference_decode[key](reference_val)
|
||||
|
||||
if trial_decode.has_key(key):
|
||||
trial_val = trial_decode[key](trial_val)
|
||||
|
||||
assert reference_val == trial_val, \
|
||||
'%s: not equal\n\nreference_val:\n%r\ntrial_val:\n%r' % \
|
||||
(key, reference[key], trial[key])
|
||||
|
||||
|
||||
api.log.info('******** Testing ra.request_certificate() ********')
|
||||
request_result = ra.request_certificate(csr)
|
||||
if verbose: print "request_result=\n%s" % request_result
|
||||
assert_equal(request_result,
|
||||
{'subject' : subject,
|
||||
})
|
||||
|
||||
api.log.info('******** Testing ra.check_request_status() ********')
|
||||
status_result = ra.check_request_status(request_result['request_id'])
|
||||
if verbose: print "status_result=\n%s" % status_result
|
||||
assert_equal(status_result,
|
||||
{'serial_number' : request_result['serial_number'],
|
||||
'request_id' : request_result['request_id'],
|
||||
'cert_request_status' : u'complete',
|
||||
})
|
||||
|
||||
api.log.info('******** Testing ra.get_certificate() ********')
|
||||
get_result = ra.get_certificate(request_result['serial_number'])
|
||||
if verbose: print "get_result=\n%s" % get_result
|
||||
assert_equal(get_result,
|
||||
{'serial_number' : request_result['serial_number'],
|
||||
'certificate' : request_result['certificate'],
|
||||
})
|
||||
|
||||
api.log.info('******** Testing ra.revoke_certificate() ********')
|
||||
revoke_result = ra.revoke_certificate(request_result['serial_number'],
|
||||
revocation_reason=6) # Put on hold
|
||||
if verbose: print "revoke_result=\n%s" % revoke_result
|
||||
assert_equal(revoke_result,
|
||||
{'revoked' : True
|
||||
})
|
||||
|
||||
|
||||
api.log.info('******** Testing ra.take_certificate_off_hold() ********')
|
||||
unrevoke_result = ra.take_certificate_off_hold(request_result['serial_number'])
|
||||
if verbose: print "unrevoke_result=\n%s" % unrevoke_result
|
||||
assert_equal(unrevoke_result,
|
||||
{'unrevoked' : True
|
||||
})
|
||||
|
13
contrib/RHEL4/Makefile.am
Normal file
13
contrib/RHEL4/Makefile.am
Normal file
@ -0,0 +1,13 @@
|
||||
NULL =
|
||||
|
||||
sbin_SCRIPTS = \
|
||||
ipa-client-setup \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(sbin_SCRIPTS) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
55
contrib/RHEL4/configure.ac
Normal file
55
contrib/RHEL4/configure.ac
Normal file
@ -0,0 +1,55 @@
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT([ipa-client],
|
||||
[0.99.0],
|
||||
[http://www.freeipa.org/])
|
||||
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
|
||||
AC_SUBST(VERSION)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for Python
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
AC_MSG_NOTICE([Checking for Python])
|
||||
have_python=no
|
||||
AM_PATH_PYTHON([2.3])
|
||||
|
||||
if test "x$PYTHON" = "x" ; then
|
||||
AC_MSG_ERROR([Python not found])
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Set the data install directory since we don't use pkgdatadir
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
IPA_DATA_DIR="$datadir/ipa"
|
||||
AC_SUBST(IPA_DATA_DIR)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Finish
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
# Files
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo "
|
||||
IPA client $VERSION
|
||||
========================
|
||||
|
||||
prefix: ${prefix}
|
||||
exec_prefix: ${exec_prefix}
|
||||
libdir: ${libdir}
|
||||
bindir: ${bindir}
|
||||
sbindir: ${sbindir}
|
||||
sysconfdir: ${sysconfdir}
|
||||
localstatedir: ${localstatedir}
|
||||
datadir: ${datadir}
|
||||
source code location: ${srcdir}
|
||||
Maintainer mode: ${USE_MAINTAINER_MODE}
|
||||
"
|
368
contrib/RHEL4/ipa-client-setup
Normal file
368
contrib/RHEL4/ipa-client-setup
Normal file
@ -0,0 +1,368 @@
|
||||
#! /usr/bin/python -E
|
||||
# Authors: Simo Sorce <ssorce@redhat.com>
|
||||
# Karl MacMillan <kmacmillan@mentalrootkit.com>
|
||||
#
|
||||
# Copyright (C) 2007 Red Hat
|
||||
# see file 'COPYING' for use and warranty information
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
VERSION = "%prog .1"
|
||||
|
||||
import sys
|
||||
import os
|
||||
import string
|
||||
import shutil
|
||||
import socket
|
||||
import logging
|
||||
from optparse import OptionParser
|
||||
import ipachangeconf
|
||||
import ldap
|
||||
from ldap import LDAPError
|
||||
|
||||
class ipaserver:
|
||||
|
||||
def __init__(self, server):
|
||||
self.server = server
|
||||
self.realm = None
|
||||
self.domain = None
|
||||
self.basedn = None
|
||||
|
||||
def getServerName(self):
|
||||
return str(self.server)
|
||||
|
||||
def getDomainName(self):
|
||||
return str(self.domain)
|
||||
|
||||
def getRealmName(self):
|
||||
return str(self.realm)
|
||||
|
||||
def getBaseDN(self):
|
||||
return str(self.basedn)
|
||||
|
||||
def check(self):
|
||||
|
||||
lret = []
|
||||
lres = []
|
||||
lattr = ""
|
||||
linfo = ""
|
||||
lrealms = []
|
||||
|
||||
i = 0
|
||||
|
||||
#now verify the server is really an IPA server
|
||||
try:
|
||||
logging.debug("Init ldap with: ldap://"+self.server+":389")
|
||||
lh = ldap.initialize("ldap://"+self.server+":389")
|
||||
lh.simple_bind_s("","")
|
||||
|
||||
logging.debug("Search rootdse")
|
||||
lret = lh.search_s("", ldap.SCOPE_BASE, "(objectClass=*)")
|
||||
for lattr in lret[0][1]:
|
||||
if lattr.lower() == "namingcontexts":
|
||||
self.basedn = lret[0][1][lattr][0]
|
||||
|
||||
logging.debug("Search for (info=*) in "+self.basedn+"(base)")
|
||||
lret = lh.search_s(self.basedn, ldap.SCOPE_BASE, "(info=IPA*)")
|
||||
if not lret:
|
||||
return False
|
||||
logging.debug("Found: "+str(lret))
|
||||
|
||||
for lattr in lret[0][1]:
|
||||
if lattr.lower() == "info":
|
||||
linfo = lret[0][1][lattr][0].lower()
|
||||
break
|
||||
|
||||
if not linfo:
|
||||
return False
|
||||
|
||||
#search and return known realms
|
||||
logging.debug("Search for (objectClass=krbRealmContainer) in "+self.basedn+"(sub)")
|
||||
lret = lh.search_s("cn=kerberos,"+self.basedn, ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
|
||||
if not lret:
|
||||
#something very wrong
|
||||
return False
|
||||
logging.debug("Found: "+str(lret))
|
||||
|
||||
for lres in lret:
|
||||
for lattr in lres[1]:
|
||||
if lattr.lower() == "cn":
|
||||
lrealms.append(lres[1][lattr][0])
|
||||
|
||||
|
||||
if len(lrealms) != 1:
|
||||
#which one? we can't attach to a multi-realm server without DNS working
|
||||
return False
|
||||
else:
|
||||
self.realm = lrealms[0]
|
||||
self.domain = lrealms[0].lower()
|
||||
return True
|
||||
|
||||
except LDAPError, err:
|
||||
#no good
|
||||
logging.error("Ldap Error: "+str(err))
|
||||
return False
|
||||
|
||||
ntp_conf = """# Permit time synchronization with our time source, but do not
|
||||
# permit the source to query or modify the service on this system.
|
||||
restrict default kod nomodify notrap nopeer noquery
|
||||
restrict -6 default kod nomodify notrap nopeer noquery
|
||||
|
||||
# Permit all access over the loopback interface. This could
|
||||
# be tightened as well, but to do so would effect some of
|
||||
# the administrative functions.
|
||||
restrict 127.0.0.1
|
||||
restrict -6 ::1
|
||||
|
||||
# Hosts on local network are less restricted.
|
||||
#restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap
|
||||
|
||||
# Use public servers from the pool.ntp.org project.
|
||||
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
|
||||
server $SERVER
|
||||
|
||||
#broadcast 192.168.1.255 key 42 # broadcast server
|
||||
#broadcastclient # broadcast client
|
||||
#broadcast 224.0.1.1 key 42 # multicast server
|
||||
#multicastclient 224.0.1.1 # multicast client
|
||||
#manycastserver 239.255.254.254 # manycast server
|
||||
#manycastclient 239.255.254.254 key 42 # manycast client
|
||||
|
||||
# Undisciplined Local Clock. This is a fake driver intended for backup
|
||||
# and when no outside source of synchronized time is available.
|
||||
server 127.127.1.0 # local clock
|
||||
#fudge 127.127.1.0 stratum 10
|
||||
|
||||
# Drift file. Put this in a directory which the daemon can write to.
|
||||
# No symbolic links allowed, either, since the daemon updates the file
|
||||
# by creating a temporary in the same directory and then rename()'ing
|
||||
# it to the file.
|
||||
driftfile /var/lib/ntp/drift
|
||||
|
||||
# Key file containing the keys and key identifiers used when operating
|
||||
# with symmetric key cryptography.
|
||||
keys /etc/ntp/keys
|
||||
|
||||
# Specify the key identifiers which are trusted.
|
||||
#trustedkey 4 8 42
|
||||
|
||||
# Specify the key identifier to use with the ntpdc utility.
|
||||
#requestkey 8
|
||||
|
||||
# Specify the key identifier to use with the ntpq utility.
|
||||
#controlkey 8
|
||||
"""
|
||||
|
||||
ntp_sysconfig = """# Drop root to id 'ntp:ntp' by default.
|
||||
OPTIONS="-x -u ntp:ntp -p /var/run/ntpd.pid"
|
||||
|
||||
# Set to 'yes' to sync hw clock after successful ntpdate
|
||||
SYNC_HWCLOCK=yes
|
||||
|
||||
# Additional options for ntpdate
|
||||
NTPDATE_OPTIONS=""
|
||||
"""
|
||||
|
||||
def config_ntp(server_fqdn):
|
||||
|
||||
nc = string.replace(ntp_conf, "$SERVER", server_fqdn)
|
||||
|
||||
shutil.copy("/etc/ntp.conf", "/etc/ntp.conf.ipasave")
|
||||
|
||||
fd = open("/etc/ntp.conf", "w")
|
||||
fd.write(nc)
|
||||
fd.close()
|
||||
|
||||
shutil.copy("/etc/sysconfig/ntpd", "/etc/sysconfig/ntpd.ipasave")
|
||||
|
||||
fd = open("/etc/sysconfig/ntpd", "w")
|
||||
fd.write(ntp_sysconfig)
|
||||
fd.close()
|
||||
|
||||
# Set the ntpd to start on boot
|
||||
os.system("/sbin/chkconfig ntpd on")
|
||||
|
||||
# Restart ntpd
|
||||
os.system("/sbin/service ntpd restart")
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser(version=VERSION)
|
||||
parser.add_option("--server", dest="server", help="IPA server")
|
||||
parser.add_option("-d", "--debug", dest="debug", action="store_true",
|
||||
default=False, help="print debugging information")
|
||||
parser.add_option("-U", "--unattended", dest="unattended",
|
||||
action="store_true",
|
||||
help="unattended installation never prompts the user")
|
||||
parser.add_option("-N", "--no-ntp", action="store_false",
|
||||
help="do not configure ntp", default=True, dest="conf_ntp")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
if not options.server:
|
||||
parser.error("must provide an IPA server name with --server")
|
||||
|
||||
return options
|
||||
|
||||
def ask_for_confirmation(message):
|
||||
yesno = raw_input(message + " [y/N]: ")
|
||||
if not yesno or yesno.lower()[0] != "y":
|
||||
return False
|
||||
print "\n"
|
||||
return True
|
||||
|
||||
def logging_setup(options):
|
||||
# Always log everything (i.e., DEBUG) to the log
|
||||
# file.
|
||||
logger = logging.getLogger('ipa-client-setup')
|
||||
fh = logging.FileHandler('ipaclient-install.log')
|
||||
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
|
||||
fh.setFormatter(formatter)
|
||||
logger.addHandler(fh)
|
||||
|
||||
# If the debug option is set, also log debug messages to the console
|
||||
if options.debug:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
else:
|
||||
# Otherwise, log critical and error messages
|
||||
logger.setLevel(logging.ERROR)
|
||||
|
||||
return logger
|
||||
|
||||
def main():
|
||||
options = parse_options()
|
||||
logger = logging_setup(options)
|
||||
dnsok = True
|
||||
|
||||
ipasrv = ipaserver(options.server)
|
||||
|
||||
ret = ipasrv.check()
|
||||
if ret == False:
|
||||
print "Failed to verify that ["+options.server+"] is an IPA Server, aborting!"
|
||||
return -1
|
||||
|
||||
print "IPA Server verified."
|
||||
print "Realm: "+ipasrv.getRealmName()
|
||||
print "DNS Domain: "+ipasrv.getDomainName()
|
||||
print "IPA Server: "+ipasrv.getServerName()
|
||||
print "BaseDN: "+ipasrv.getBaseDN()
|
||||
|
||||
print "\n"
|
||||
if not options.unattended and not ask_for_confirmation("Continue to configure the system with these values?"):
|
||||
return 1
|
||||
|
||||
# Configure ipa.conf
|
||||
ipaconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
||||
ipaconf.setOptionAssignment(" = ")
|
||||
ipaconf.setSectionNameDelimiters(("[","]"))
|
||||
|
||||
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
||||
{'name':'empty', 'type':'empty'}]
|
||||
|
||||
#[global]
|
||||
defopts = [{'name':'xmlrpc_uri', 'type':'option', 'value':'https://%s/ipa/xml' % ipasrv.getServerName()},
|
||||
{'name':'realm', 'type':'option', 'value':ipasrv.getRealmName()}]
|
||||
|
||||
opts.append({'name':'global', 'type':'section', 'value':defopts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
ipaconf.newConf("/etc/ipa/default.conf", opts)
|
||||
|
||||
# Configure ldap.conf
|
||||
ldapconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
||||
ldapconf.setOptionAssignment(" ")
|
||||
|
||||
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
||||
{'name':'empty', 'type':'empty'},
|
||||
{'name':'ldap_version', 'type':'option', 'value':'3'},
|
||||
{'name':'base', 'type':'option', 'value':ipasrv.getBaseDN()},
|
||||
{'name':'empty', 'type':'empty'},
|
||||
{'name':'nss_base_passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+ipasrv.getBaseDN()+'?sub'},
|
||||
{'name':'nss_base_group', 'type':'option', 'value':'cn=users,cn=accounts,'+ipasrv.getBaseDN()+'?sub'},
|
||||
{'name':'nss_schema', 'type':'option', 'value':'rfc2307bis'},
|
||||
{'name':'nss_map_attribute', 'type':'option', 'value':'uniqueMember member'},
|
||||
{'name':'nss_initgroups_ignoreusers', 'type':'option', 'value':'root,dirsrv'},
|
||||
{'name':'empty', 'type':'empty'},
|
||||
{'name':'nss_reconnect_maxsleeptime', 'type':'option', 'value':'8'},
|
||||
{'name':'nss_reconnect_sleeptime', 'type':'option', 'value':'1'},
|
||||
{'name':'bind_timelimit', 'type':'option', 'value':'5'},
|
||||
{'name':'timelimit', 'type':'option', 'value':'15'},
|
||||
{'name':'empty', 'type':'empty'},
|
||||
{'name':'uri', 'type':'option', 'value':'ldap://'+ipasrv.getServerName()},
|
||||
{'name':'empty', 'type':'empty'}]
|
||||
try:
|
||||
ldapconf.newConf("/etc/ldap.conf", opts)
|
||||
except Exception, e:
|
||||
print "Configuration failed: " + str(e)
|
||||
return 1
|
||||
|
||||
if not "" == ipasrv.getRealmName():
|
||||
#Configure krb5.conf
|
||||
krbconf = ipachangeconf.IPAChangeConf("IPA Installer")
|
||||
krbconf.setOptionAssignment(" = ")
|
||||
krbconf.setSectionNameDelimiters(("[","]"))
|
||||
krbconf.setSubSectionDelimiters(("{","}"))
|
||||
krbconf.setIndent((""," "," "))
|
||||
|
||||
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
|
||||
{'name':'empty', 'type':'empty'}]
|
||||
|
||||
#[libdefaults]
|
||||
libopts = [{'name':'default_realm', 'type':'option', 'value':ipasrv.getRealmName()}]
|
||||
libopts.append({'name':'dns_lookup_realm', 'type':'option', 'value':'false'})
|
||||
libopts.append({'name':'dns_lookup_kdc', 'type':'option', 'value':'false'})
|
||||
libopts.append({'name':'ticket_lifetime', 'type':'option', 'value':'24h'})
|
||||
libopts.append({'name':'forwardable', 'type':'option', 'value':'yes'})
|
||||
|
||||
opts.append({'name':'libdefaults', 'type':'section', 'value':libopts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
#[realms]
|
||||
kropts =[{'name':'kdc', 'type':'option', 'value':ipasrv.getServerName()+':88'},
|
||||
{'name':'admin_server', 'type':'option', 'value':ipasrv.getServerName()+':749'},
|
||||
{'name':'default_domain', 'type':'option', 'value':ipasrv.getDomainName()}]
|
||||
ropts = [{'name':ipasrv.getRealmName(), 'type':'subsection', 'value':kropts}]
|
||||
opts.append({'name':'realms', 'type':'section', 'value':ropts})
|
||||
opts.append({'name':'empty', 'type':'empty'})
|
||||
|
||||
#[domain_realm]
|
||||
dropts = [{'name':'.'+ipasrv.getDomainName(), 'type':'option', 'value':ipasrv.getRealmName()},
|
||||
{'name':ipasrv.getDomainName(), 'type':'option', 'value':ipasrv.getRealmName()}]
|
||||
opts.append({'name':'domain_realm', 'type':'section', 'value':dropts})
|
||||
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})
|
||||
|
||||
krbconf.newConf("/etc/krb5.conf", opts);
|
||||
|
||||
#Modify nsswitch to add nss_ldap
|
||||
os.system("/usr/sbin/authconfig --enableldap --kickstart")
|
||||
|
||||
#Modify pam to add pam_krb5
|
||||
os.system("/usr/sbin/authconfig --enablekrb5 --kickstart")
|
||||
|
||||
if options.conf_ntp:
|
||||
config_ntp(ipasrv.getServerName())
|
||||
|
||||
print "Client configuration complete."
|
||||
|
||||
return 0
|
||||
|
||||
sys.exit(main())
|
54
contrib/RHEL4/ipa-client.spec
Normal file
54
contrib/RHEL4/ipa-client.spec
Normal file
@ -0,0 +1,54 @@
|
||||
Name: ipa-client
|
||||
Version: 1.0.0
|
||||
Release: 1%{?dist}
|
||||
Summary: IPA client Setup script for RHEL-4
|
||||
|
||||
Group: System Environment/Base
|
||||
License: GPLv2
|
||||
URL: http://www.freeipa.org
|
||||
Source0: %{name}-%{version}.tgz
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
#BuildRequires: python-devel
|
||||
|
||||
Requires: python
|
||||
Requires: python-ldap
|
||||
|
||||
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
|
||||
|
||||
%description
|
||||
IPA is a server for identity, policy, and audit.
|
||||
The client package provide install and configuration scripts for RHEL-4 clients.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%configure --prefix=/usr
|
||||
|
||||
%build
|
||||
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
%{__python} setup.py install --no-compile --root=%{buildroot}
|
||||
%makeinstall \
|
||||
SBINDIR=$RPM_BUILD_ROOT%{_sbindir}
|
||||
mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/ipa
|
||||
install -m644 ipa.conf $RPM_BUILD_ROOT%{_sysconfdir}/ipa/ipa.conf
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%files
|
||||
%defattr(-,root,root,-)
|
||||
%{_sbindir}/ipa-client-setup
|
||||
%{python_sitelib}/ipachangeconf.py*
|
||||
%config(noreplace) %{_sysconfdir}/ipa/ipa.conf
|
||||
|
||||
%changelog
|
||||
* Thu Apr 3 2008 Rob Crittenden <rcritten@redhat.com> - 1.0.0-1
|
||||
- Version bump for release
|
||||
|
||||
* Mon Mar 25 2008 Simo Sorce <ssorce@redhat.com> - 0.99.0-1
|
||||
- First RHEL-4 release
|
||||
|
3
contrib/RHEL4/ipa.conf
Normal file
3
contrib/RHEL4/ipa.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[defaults]
|
||||
# realm = EXAMPLE.COM
|
||||
# server = ipa.example.com
|
458
contrib/RHEL4/ipachangeconf.py
Normal file
458
contrib/RHEL4/ipachangeconf.py
Normal file
@ -0,0 +1,458 @@
|
||||
#
|
||||
# ipachangeconf - configuration file manipulation classes and functions
|
||||
# partially based on authconfig code
|
||||
# Copyright (c) 1999-2007 Red Hat, Inc.
|
||||
# Author: Simo Sorce <ssorce@redhat.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import fcntl
|
||||
import os
|
||||
import string
|
||||
import time
|
||||
import shutil
|
||||
|
||||
def openLocked(filename, perms):
|
||||
fd = -1
|
||||
try:
|
||||
fd = os.open(filename, os.O_RDWR | os.O_CREAT, perms)
|
||||
|
||||
fcntl.lockf(fd, fcntl.LOCK_EX)
|
||||
except OSError, (errno, strerr):
|
||||
if fd != -1:
|
||||
try:
|
||||
os.close(fd)
|
||||
except OSError:
|
||||
pass
|
||||
raise IOError(errno, strerr)
|
||||
return os.fdopen(fd, "r+")
|
||||
|
||||
|
||||
#TODO: add subsection as a concept
|
||||
# (ex. REALM.NAME = { foo = x bar = y } )
|
||||
#TODO: put section delimiters as separating element of the list
|
||||
# so that we can process multiple sections in one go
|
||||
#TODO: add a comment all but provided options as a section option
|
||||
class IPAChangeConf:
|
||||
|
||||
def __init__(self, name):
|
||||
self.progname = name
|
||||
self.indent = ("","","")
|
||||
self.assign = (" = ","=")
|
||||
self.dassign = self.assign[0]
|
||||
self.comment = ("#",)
|
||||
self.dcomment = self.comment[0]
|
||||
self.eol = ("\n",)
|
||||
self.deol = self.eol[0]
|
||||
self.sectnamdel = ("[","]")
|
||||
self.subsectdel = ("{","}")
|
||||
|
||||
def setProgName(self, name):
|
||||
self.progname = name
|
||||
|
||||
def setIndent(self, indent):
|
||||
if type(indent) is tuple:
|
||||
self.indent = indent
|
||||
elif type(indent) is str:
|
||||
self.indent = (indent, )
|
||||
else:
|
||||
raise ValueError, 'Indent must be a list of strings'
|
||||
|
||||
def setOptionAssignment(self, assign):
|
||||
if type(assign) is tuple:
|
||||
self.assign = assign
|
||||
else:
|
||||
self.assign = (assign, )
|
||||
self.dassign = self.assign[0]
|
||||
|
||||
def setCommentPrefix(self, comment):
|
||||
if type(comment) is tuple:
|
||||
self.comment = comment
|
||||
else:
|
||||
self.comment = (comment, )
|
||||
self.dcomment = self.comment[0]
|
||||
|
||||
def setEndLine(self, eol):
|
||||
if type(eol) is tuple:
|
||||
self.eol = eol
|
||||
else:
|
||||
self.eol = (eol, )
|
||||
self.deol = self.eol[0]
|
||||
|
||||
def setSectionNameDelimiters(self, delims):
|
||||
self.sectnamdel = delims
|
||||
|
||||
def setSubSectionDelimiters(self, delims):
|
||||
self.subsectdel = delims
|
||||
|
||||
def matchComment(self, line):
|
||||
for v in self.comment:
|
||||
if line.lstrip().startswith(v):
|
||||
return line.lstrip()[len(v):]
|
||||
return False
|
||||
|
||||
def matchEmpty(self, line):
|
||||
if line.strip() == "":
|
||||
return True
|
||||
return False
|
||||
|
||||
def matchSection(self, line):
|
||||
cl = "".join(line.strip().split()).lower()
|
||||
if len(self.sectnamdel) != 2:
|
||||
return False
|
||||
if not cl.startswith(self.sectnamdel[0]):
|
||||
return False
|
||||
if not cl.endswith(self.sectnamdel[1]):
|
||||
return False
|
||||
return cl[len(self.sectnamdel[0]):-len(self.sectnamdel[1])]
|
||||
|
||||
def matchSubSection(self, line):
|
||||
if self.matchComment(line):
|
||||
return False
|
||||
|
||||
parts = line.split(self.dassign, 1)
|
||||
if len(parts) < 2:
|
||||
return False
|
||||
|
||||
if parts[1].strip() == self.subsectdel[0]:
|
||||
return parts[0].strip()
|
||||
|
||||
return False
|
||||
|
||||
def matchSubSectionEnd(self, line):
|
||||
if self.matchComment(line):
|
||||
return False
|
||||
|
||||
if line.strip() == self.subsectdel[1]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def getSectionLine(self, section):
|
||||
if len(self.sectnamdel) != 2:
|
||||
return section
|
||||
return self.sectnamdel[0]+section+self.sectnamdel[1]+self.deol
|
||||
|
||||
def dump(self, options, level=0):
|
||||
output = ""
|
||||
if level >= len(self.indent):
|
||||
level = len(self.indent)-1
|
||||
|
||||
for o in options:
|
||||
if o['type'] == "section":
|
||||
output += self.sectnamdel[0]+o['name']+self.sectnamdel[1]+self.deol
|
||||
output += self.dump(o['value'], level+1)
|
||||
continue
|
||||
if o['type'] == "subsection":
|
||||
output += self.indent[level]+o['name']+self.dassign+self.subsectdel[0]+self.deol
|
||||
output += self.dump(o['value'], level+1)
|
||||
output += self.indent[level]+self.subsectdel[1]+self.deol
|
||||
continue
|
||||
if o['type'] == "option":
|
||||
output += self.indent[level]+o['name']+self.dassign+o['value']+self.deol
|
||||
continue
|
||||
if o['type'] == "comment":
|
||||
output += self.dcomment+o['value']+self.deol
|
||||
continue
|
||||
if o['type'] == "empty":
|
||||
output += self.deol
|
||||
continue
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
return output
|
||||
|
||||
def parseLine(self, line):
|
||||
|
||||
if self.matchEmpty(line):
|
||||
return {'name':'empty', 'type':'empty'}
|
||||
|
||||
value = self.matchComment(line)
|
||||
if value:
|
||||
return {'name':'comment', 'type':'comment', 'value':value.rstrip()} #pylint: disable=E1103
|
||||
|
||||
parts = line.split(self.dassign, 1)
|
||||
if len(parts) < 2:
|
||||
raise SyntaxError, 'Syntax Error: Unknown line format'
|
||||
|
||||
return {'name':parts[0].strip(), 'type':'option', 'value':parts[1].rstrip()}
|
||||
|
||||
def findOpts(self, opts, type, name, exclude_sections=False):
|
||||
|
||||
num = 0
|
||||
for o in opts:
|
||||
if o['type'] == type and o['name'] == name:
|
||||
return (num, o)
|
||||
if exclude_sections and (o['type'] == "section" or o['type'] == "subsection"):
|
||||
return (num, None)
|
||||
num += 1
|
||||
return (num, None)
|
||||
|
||||
def commentOpts(self, inopts, level = 0):
|
||||
|
||||
opts = []
|
||||
|
||||
if level >= len(self.indent):
|
||||
level = len(self.indent)-1
|
||||
|
||||
for o in inopts:
|
||||
if o['type'] == 'section':
|
||||
no = self.commentOpts(o['value'], level+1)
|
||||
val = self.dcomment+self.sectnamdel[0]+o['name']+self.sectnamdel[1]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
for n in no:
|
||||
opts.append(n)
|
||||
continue
|
||||
if o['type'] == 'subsection':
|
||||
no = self.commentOpts(o['value'], level+1)
|
||||
val = self.indent[level]+o['name']+self.dassign+self.subsectdel[0]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
for n in no:
|
||||
opts.append(n)
|
||||
val = self.indent[level]+self.subsectdel[1]
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
continue
|
||||
if o['type'] == 'option':
|
||||
val = self.indent[level]+o['name']+self.dassign+o['value']
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':val})
|
||||
continue
|
||||
if o['type'] == 'comment':
|
||||
opts.append(o)
|
||||
continue
|
||||
if o['type'] == 'empty':
|
||||
opts.append({'name':'comment', 'type':'comment', 'value':''})
|
||||
continue
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
return opts
|
||||
|
||||
def mergeOld(self, oldopts, newopts):
|
||||
|
||||
opts = []
|
||||
|
||||
for o in oldopts:
|
||||
if o['type'] == "section" or o['type'] == "subsection":
|
||||
(num, no) = self.findOpts(newopts, o['type'], o['name'])
|
||||
if not no:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == "set":
|
||||
mo = self.mergeOld(o['value'], no['value'])
|
||||
opts.append({'name':o['name'], 'type':o['type'], 'value':mo})
|
||||
continue
|
||||
if no['action'] == "comment":
|
||||
co = self.commentOpts(o['value'])
|
||||
for c in co:
|
||||
opts.append(c)
|
||||
continue
|
||||
if no['action'] == "remove":
|
||||
continue
|
||||
raise SyntaxError, 'Unknown action: ['+no['action']+']'
|
||||
|
||||
if o['type'] == "comment" or o['type'] == "empty":
|
||||
opts.append(o)
|
||||
continue
|
||||
|
||||
if o['type'] == "option":
|
||||
(num, no) = self.findOpts(newopts, 'option', o['name'], True)
|
||||
if not no:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == 'comment' or no['action'] == 'remove':
|
||||
if no['value'] != None and o['value'] != no['value']:
|
||||
opts.append(o)
|
||||
continue
|
||||
if no['action'] == 'comment':
|
||||
opts.append({'name':'comment', 'type':'comment',
|
||||
'value':self.dcomment+o['name']+self.dassign+o['value']})
|
||||
continue
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
raise SyntaxError, 'Unknown action: ['+o['action']+']'
|
||||
|
||||
raise SyntaxError, 'Unknown type: ['+o['type']+']'
|
||||
|
||||
return opts
|
||||
|
||||
def mergeNew(self, opts, newopts):
|
||||
|
||||
cline = 0
|
||||
|
||||
for no in newopts:
|
||||
|
||||
if no['type'] == "section" or no['type'] == "subsection":
|
||||
(num, o) = self.findOpts(opts, no['type'], no['name'])
|
||||
if not o:
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
if no['action'] == "set":
|
||||
self.mergeNew(o['value'], no['value'])
|
||||
continue
|
||||
cline = num+1
|
||||
continue
|
||||
|
||||
if no['type'] == "option":
|
||||
(num, o) = self.findOpts(opts, no['type'], no['name'], True)
|
||||
if not o:
|
||||
if no['action'] == 'set':
|
||||
opts.append(no)
|
||||
continue
|
||||
cline = num+1
|
||||
continue
|
||||
|
||||
if no['type'] == "comment" or no['type'] == "empty":
|
||||
opts.insert(cline, no)
|
||||
cline += 1
|
||||
continue
|
||||
|
||||
raise SyntaxError, 'Unknown type: ['+no['type']+']'
|
||||
|
||||
|
||||
def merge(self, oldopts, newopts):
|
||||
|
||||
#Use a two pass strategy
|
||||
#First we create a new opts tree from oldopts removing/commenting
|
||||
# the options as indicated by the contents of newopts
|
||||
#Second we fill in the new opts tree with options as indicated
|
||||
# in the newopts tree (this is becaus eentire (sub)sections may
|
||||
# exist in the newopts that do not exist in oldopts)
|
||||
|
||||
opts = self.mergeOld(oldopts, newopts)
|
||||
self.mergeNew(opts, newopts)
|
||||
return opts
|
||||
|
||||
#TODO: Make parse() recursive?
|
||||
def parse(self, f):
|
||||
|
||||
opts = []
|
||||
sectopts = []
|
||||
section = None
|
||||
subsectopts = []
|
||||
subsection = None
|
||||
curopts = opts
|
||||
fatheropts = opts
|
||||
|
||||
# Read in the old file.
|
||||
for line in f:
|
||||
|
||||
# It's a section start.
|
||||
value = self.matchSection(line)
|
||||
if value:
|
||||
if section is not None:
|
||||
opts.append({'name':section, 'type':'section', 'value':sectopts})
|
||||
sectopts = []
|
||||
curopts = sectopts
|
||||
fatheropts = sectopts
|
||||
section = value
|
||||
continue
|
||||
|
||||
# It's a subsection start.
|
||||
value = self.matchSubSection(line)
|
||||
if value:
|
||||
if subsection is not None:
|
||||
raise SyntaxError, 'nested subsections are not supported yet'
|
||||
subsectopts = []
|
||||
curopts = subsectopts
|
||||
subsection = value
|
||||
continue
|
||||
|
||||
value = self.matchSubSectionEnd(line)
|
||||
if value:
|
||||
if subsection is None:
|
||||
raise SyntaxError, 'Unmatched end subsection terminator found'
|
||||
fatheropts.append({'name':subsection, 'type':'subsection', 'value':subsectopts})
|
||||
subsection = None
|
||||
curopts = fatheropts
|
||||
continue
|
||||
|
||||
# Copy anything else as is.
|
||||
curopts.append(self.parseLine(line))
|
||||
|
||||
#Add last section if any
|
||||
if len(sectopts) is not 0:
|
||||
opts.append({'name':section, 'type':'section', 'value':sectopts})
|
||||
|
||||
return opts
|
||||
|
||||
# Write settings to configuration file
|
||||
# file is a path
|
||||
# options is a set of dictionaries in the form:
|
||||
# [{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}]
|
||||
# section is a section name like 'global'
|
||||
def changeConf(self, file, newopts):
|
||||
autosection = False
|
||||
savedsection = None
|
||||
done = False
|
||||
output = ""
|
||||
f = None
|
||||
try:
|
||||
#Do not catch an unexisting file error, we want to fail in that case
|
||||
shutil.copy2(file, file+".ipabkp")
|
||||
|
||||
f = openLocked(file, 0644)
|
||||
|
||||
oldopts = self.parse(f)
|
||||
|
||||
options = self.merge(oldopts, newopts)
|
||||
|
||||
output = self.dump(options)
|
||||
|
||||
# Write it out and close it.
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
f.write(output)
|
||||
finally:
|
||||
try:
|
||||
if f:
|
||||
f.close()
|
||||
except IOError:
|
||||
pass
|
||||
return True
|
||||
|
||||
# Write settings to new file, backup old
|
||||
# file is a path
|
||||
# options is a set of dictionaries in the form:
|
||||
# [{'name': 'foo', 'value': 'bar', 'action': 'set/comment'}]
|
||||
# section is a section name like 'global'
|
||||
def newConf(self, file, options):
|
||||
autosection = False
|
||||
savedsection = None
|
||||
done = False
|
||||
output = ""
|
||||
f = None
|
||||
try:
|
||||
try:
|
||||
shutil.copy2(file, file+".ipabkp")
|
||||
except IOError, err:
|
||||
if err.errno == 2:
|
||||
# The orign file did not exist
|
||||
pass
|
||||
|
||||
f = openLocked(file, 0644)
|
||||
|
||||
# Trunkate
|
||||
f.seek(0)
|
||||
f.truncate(0)
|
||||
|
||||
output = self.dump(options)
|
||||
|
||||
f.write(output)
|
||||
finally:
|
||||
try:
|
||||
if f:
|
||||
f.close()
|
||||
except IOError:
|
||||
pass
|
||||
return True
|
75
contrib/RHEL4/setup.py
Normal file
75
contrib/RHEL4/setup.py
Normal file
@ -0,0 +1,75 @@
|
||||
#!/usr/bin/python
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
"""FreeIPA python support library
|
||||
|
||||
FreeIPA is a server for identity, policy, and audit.
|
||||
"""
|
||||
|
||||
DOCLINES = __doc__.split("\n")
|
||||
|
||||
import os
|
||||
import sys
|
||||
import distutils.sysconfig
|
||||
|
||||
CLASSIFIERS = """\
|
||||
Development Status :: 4 - Beta
|
||||
Intended Audience :: System Environment/Base
|
||||
License :: GPL
|
||||
Programming Language :: Python
|
||||
Operating System :: POSIX
|
||||
Operating System :: Unix
|
||||
"""
|
||||
|
||||
# BEFORE importing distutils, remove MANIFEST. distutils doesn't properly
|
||||
# update it when the contents of directories change.
|
||||
if os.path.exists('MANIFEST'): os.remove('MANIFEST')
|
||||
|
||||
def setup_package():
|
||||
|
||||
from distutils.core import setup
|
||||
|
||||
old_path = os.getcwd()
|
||||
local_path = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
os.chdir(local_path)
|
||||
sys.path.insert(0,local_path)
|
||||
|
||||
try:
|
||||
setup(
|
||||
name = "ipa-client",
|
||||
version = "0.99.0",
|
||||
license = "GPL",
|
||||
author = "Simo Sorce",
|
||||
author_email = "ssorce@redhat.com",
|
||||
maintainer = "freeIPA Developers",
|
||||
maintainer_email = "freeipa-devel@redhat.com",
|
||||
url = "http://www.freeipa.org/",
|
||||
description = DOCLINES[0],
|
||||
long_description = "\n".join(DOCLINES[2:]),
|
||||
download_url = "http://www.freeipa.org/page/Downloads",
|
||||
classifiers=filter(None, CLASSIFIERS.split('\n')),
|
||||
platforms = ["Linux"],
|
||||
py_modules=['ipachangeconf']
|
||||
)
|
||||
finally:
|
||||
del sys.path[0]
|
||||
os.chdir(old_path)
|
||||
return
|
||||
|
||||
if __name__ == '__main__':
|
||||
setup_package()
|
32
contrib/completion/ipa.bash_completion
Normal file
32
contrib/completion/ipa.bash_completion
Normal file
@ -0,0 +1,32 @@
|
||||
# -*- shell-script -*-
|
||||
# Programmable completion for the IPA ipa command under bash. Source
|
||||
# this file (or on some systems add it to ~/.bash_completion and start a new
|
||||
# shell) and bash's completion mechanism will know all about ipa's options!
|
||||
|
||||
# Known to work with bash 2.05a with programmable completion and extended
|
||||
# pattern matching enabled (use 'shopt -s extglob progcomp' to enable
|
||||
# these if they are not already enabled).
|
||||
|
||||
# based on the bzr bash completion script by Martin Pool
|
||||
|
||||
_ipa_commands()
|
||||
{
|
||||
ipa help commands | sed -r 's/^([-[:alnum:]]*).*/\1/' | grep '^[[:alnum:]]'
|
||||
}
|
||||
|
||||
_ipa()
|
||||
{
|
||||
cur=${COMP_WORDS[COMP_CWORD]}
|
||||
prev=${COMP_WORDS[COMP_CWORD-1]}
|
||||
if [ $COMP_CWORD -eq 1 ]; then
|
||||
COMPREPLY=( $( compgen -W "$(_ipa_commands)" $cur ) )
|
||||
elif [ $COMP_CWORD -eq 2 ]; then
|
||||
case "$prev" in
|
||||
help)
|
||||
COMPREPLY=( $( compgen -W "$(_ipa_commands) commands" $cur ) )
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
complete -F _ipa -o default ipa
|
43
daemons/Makefile.am
Normal file
43
daemons/Makefile.am
Normal file
@ -0,0 +1,43 @@
|
||||
# This file will be processed with automake-1.7 to create Makefile.in
|
||||
#
|
||||
AUTOMAKE_OPTIONS = 1.7
|
||||
|
||||
NULL =
|
||||
|
||||
AM_CFLAGS = $(NULL)
|
||||
if HAVE_GCC
|
||||
AM_CFLAGS += -Wall -Wshadow -Wstrict-prototypes -Wpointer-arith \
|
||||
-Wcast-align -Werror-implicit-function-declaration \
|
||||
$(NULL)
|
||||
endif
|
||||
export AM_CFLAGS
|
||||
|
||||
SUBDIRS = \
|
||||
ipa-kpasswd \
|
||||
ipa-slapi-plugins \
|
||||
$(NULL)
|
||||
|
||||
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)
|
323
daemons/configure.ac
Normal file
323
daemons/configure.ac
Normal file
@ -0,0 +1,323 @@
|
||||
AC_PREREQ(2.59)
|
||||
m4_include(../version.m4)
|
||||
AC_INIT([ipa-server],
|
||||
IPA_VERSION,
|
||||
[https://hosted.fedoraproject.org/projects/freeipa/newticket])
|
||||
|
||||
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
|
||||
|
||||
AM_CONDITIONAL([HAVE_GCC], [test "$ac_cv_prog_gcc" = yes])
|
||||
|
||||
AC_SUBST(VERSION)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for NSPR
|
||||
dnl ---------------------------------------------------------------------------
|
||||
AC_CHECK_HEADER(nspr4/nspr.h)
|
||||
AC_CHECK_HEADER(nspr/nspr.h)
|
||||
if test "x$ac_cv_header_nspr4_nspr_h" = "xno" && test "x$ac_cv_header_nspr_nspr_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required NSPR header not available (nspr-devel)])
|
||||
fi
|
||||
if test "x$ac_cv_header_nspr4_nspr_h" = "xyes" ; then
|
||||
NSPR4="-I/usr/include/nspr4"
|
||||
fi
|
||||
if test "x$ac_cv_header_nspr_nspr_h" = "xyes" ; then
|
||||
NSPR4="-I/usr/include/nspr"
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for NSS
|
||||
dnl ---------------------------------------------------------------------------
|
||||
SAVE_CPPFLAGS=$CPPFLAGS
|
||||
CPPFLAGS=$NSPR4
|
||||
AC_CHECK_HEADER(nss3/nss.h)
|
||||
AC_CHECK_HEADER(nss/nss.h)
|
||||
CPPFLAGS=$SAVE_CPPFLAGS
|
||||
if test "x$ac_cv_header_nss3_nss_h" = "xno" && test "x$ac_cv_header_nss_nss_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required NSS header not available (nss-devel)])
|
||||
fi
|
||||
if test "x$ac_cv_header_nss3_nss_h" = "xyes" ; then
|
||||
NSS3="-I/usr/include/nss3"
|
||||
fi
|
||||
if test "x$ac_cv_header_nss_nss_h" = "xyes" ; then
|
||||
NSS3="-I/usr/include/nss"
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for DS slapi plugin
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
# Need to hack CPPFLAGS to be able to correctly detetct slapi-plugin.h
|
||||
SAVE_CPPFLAGS=$CPPFLAGS
|
||||
CPPFLAGS=$NSPR4
|
||||
AC_CHECK_HEADER(dirsrv/slapi-plugin.h)
|
||||
if test "x$ac_cv_header_dirsrv_slapi-plugin_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required 389-ds header not available (389-ds-base-devel)])
|
||||
fi
|
||||
AC_CHECK_HEADER(dirsrv/repl-session-plugin.h)
|
||||
if test "x$ac_cv_header_dirsrv_repl_session_plugin_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required 389-ds header not available (389-ds-base-devel)])
|
||||
fi
|
||||
CPPFLAGS=$SAVE_CPPFLAGS
|
||||
|
||||
if test "x$ac_cv_header_dirsrv_slapi_plugin_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required DS slapi plugin header not available (fedora-ds-base-devel)])
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for KRB5
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
KRB5_LIBS=
|
||||
AC_CHECK_HEADER(krb5.h, [], [AC_MSG_ERROR([krb5.h not found])])
|
||||
|
||||
krb5_impl=mit
|
||||
|
||||
if test "x$ac_cv_header_krb5_h" = "xyes" ; then
|
||||
dnl lazy check for Heimdal Kerberos
|
||||
AC_CHECK_HEADERS(heim_err.h)
|
||||
if test $ac_cv_header_heim_err_h = yes ; then
|
||||
krb5_impl=heimdal
|
||||
else
|
||||
krb5_impl=mit
|
||||
fi
|
||||
|
||||
if test "x$krb5_impl" = "xmit"; then
|
||||
AC_CHECK_LIB(k5crypto, main,
|
||||
[krb5crypto=k5crypto],
|
||||
[krb5crypto=crypto])
|
||||
|
||||
AC_CHECK_LIB(krb5, main,
|
||||
[have_krb5=yes
|
||||
KRB5_LIBS="-lkrb5 -l$krb5crypto -lcom_err"],
|
||||
[have_krb5=no],
|
||||
[-l$krb5crypto -lcom_err])
|
||||
|
||||
elif test "x$krb5_impl" = "xheimdal"; then
|
||||
AC_CHECK_LIB(des, main,
|
||||
[krb5crypto=des],
|
||||
[krb5crypto=crypto])
|
||||
|
||||
AC_CHECK_LIB(krb5, main,
|
||||
[have_krb5=yes
|
||||
KRB5_LIBS="-lkrb5 -l$krb5crypto -lasn1 -lroken -lcom_err"],
|
||||
[have_krb5=no],
|
||||
[-l$krb5crypto -lasn1 -lroken -lcom_err])
|
||||
|
||||
AC_DEFINE(HAVE_HEIMDAL_KERBEROS, 1,
|
||||
[define if you have HEIMDAL Kerberos])
|
||||
|
||||
else
|
||||
have_krb5=no
|
||||
AC_MSG_WARN([Unrecognized Kerberos5 Implementation])
|
||||
fi
|
||||
|
||||
if test "x$have_krb5" = "xyes" ; then
|
||||
ol_link_krb5=yes
|
||||
|
||||
AC_DEFINE(HAVE_KRB5, 1,
|
||||
[define if you have Kerberos V])
|
||||
|
||||
else
|
||||
AC_MSG_ERROR([Required Kerberos 5 support not available])
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
AC_SUBST(KRB5_LIBS)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for Mozilla LDAP and OpenLDAP SDK
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
SAVE_CPPFLAGS=$CPPFLAGS
|
||||
CPPFLAGS="$NSPR4 $NSS3"
|
||||
AC_CHECK_HEADER(svrcore.h)
|
||||
AC_CHECK_HEADER(svrcore/svrcore.h)
|
||||
if test "x$ac_cv_header_svrcore_h" = "xno" && test "x$ac_cv_header_svrcore_svrcore_h" = "xno" ; then
|
||||
AC_MSG_ERROR([Required svrcore header not available (svrcore-devel)])
|
||||
fi
|
||||
if test "x$ac_cv_header_svrcore_svrcore_h" = "yes" ; then
|
||||
CPPFLAGS="$CPPFLAGS -I/usr/include/svrcore"
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB(ldap, ldap_search, with_ldap=yes)
|
||||
dnl Check for other libraries we need to link with to get the main routines.
|
||||
test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes], , -llber) }
|
||||
test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes with_ldap_krb=yes], , -llber -lkrb) }
|
||||
test "$with_ldap" != "yes" && { AC_CHECK_LIB(ldap, ldap_open, [with_ldap=yes with_ldap_lber=yes with_ldap_krb=yes with_ldap_des=yes], , -llber -lkrb -ldes) }
|
||||
dnl Recently, we need -lber even though the main routines are elsewhere,
|
||||
dnl because otherwise be get link errors w.r.t. ber_pvt_opt_on. So just
|
||||
dnl check for that (it's a variable not a fun but that doesn't seem to
|
||||
dnl matter in these checks) and stick in -lber if so. Can't hurt (even to
|
||||
dnl stick it in always shouldn't hurt, I don't think) ... #### Someone who
|
||||
dnl #### understands LDAP needs to fix this properly.
|
||||
test "$with_ldap_lber" != "yes" && { AC_CHECK_LIB(lber, ber_pvt_opt_on, with_ldap_lber=yes) }
|
||||
|
||||
if test "$with_ldap" = "yes"; then
|
||||
if test "$with_ldap_des" = "yes" ; then
|
||||
OPENLDAP_LIBS="${OPENLDAP_LIBS} -ldes"
|
||||
fi
|
||||
if test "$with_ldap_krb" = "yes" ; then
|
||||
OPENLDAP_LIBS="${OPENLDAP_LIBS} -lkrb"
|
||||
fi
|
||||
if test "$with_ldap_lber" = "yes" ; then
|
||||
OPENLDAP_LIBS="${OPENLDAP_LIBS} -llber"
|
||||
fi
|
||||
OPENLDAP_LIBS="${OPENLDAP_LIBS} -lldap"
|
||||
else
|
||||
AC_MSG_ERROR([OpenLDAP not found])
|
||||
fi
|
||||
|
||||
AC_SUBST(OPENLDAP_LIBS)
|
||||
|
||||
OPENLDAP_CFLAGS="${OPENLDAP_CFLAGS} -DWITH_OPENLDAP"
|
||||
AC_SUBST(OPENLDAP_CFLAGS)
|
||||
|
||||
AC_ARG_WITH([openldap],
|
||||
[AS_HELP_STRING([--with-openldap],
|
||||
[compile plugins with openldap instead of mozldap])],
|
||||
[], [])
|
||||
|
||||
LDAP_CFLAGS="${OPENLDAP_CFLAGS} $NSPR4 $NSS3 -DUSE_OPENLDAP"
|
||||
LDAP_LIBS="${OPENLDAP_LIBS}"
|
||||
AC_DEFINE_UNQUOTED(WITH_OPENLDAP, 1, [Use OpenLDAP libraries])
|
||||
|
||||
AC_SUBST(LDAP_CFLAGS)
|
||||
AC_SUBST(LDAP_LIBS)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for OpenSSL Crypto library
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl This is a very simple check, we should probably check also for MD4_Init and
|
||||
dnl probably also the version we are using is recent enough
|
||||
SSL_LIBS=
|
||||
AC_CHECK_HEADER(openssl/des.h, [], [AC_MSG_ERROR([openssl/des.h not found])])
|
||||
AC_CHECK_LIB(crypto, DES_set_key_unchecked, [SSL_LIBS="-lcrypto"])
|
||||
AC_SUBST(SSL_LIBS)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for UUID library
|
||||
dnl ---------------------------------------------------------------------------
|
||||
AC_CHECK_HEADERS(uuid/uuid.h,,[AC_MSG_ERROR([uuid/uuid.h not found])])
|
||||
|
||||
AC_CHECK_LIB(uuid, uuid_generate_time, [UUID_LIBS="-luuid"])
|
||||
AC_SUBST(UUID_LIBS)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Check for Python
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
AC_MSG_NOTICE([Checking for Python])
|
||||
have_python=no
|
||||
AM_PATH_PYTHON(2.3)
|
||||
|
||||
if test "x$PYTHON" = "x" ; then
|
||||
AC_MSG_ERROR([Python not found])
|
||||
fi
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl - Set the data install directory since we don't use pkgdatadir
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
IPA_DATA_DIR="$datadir/ipa"
|
||||
AC_SUBST(IPA_DATA_DIR)
|
||||
|
||||
dnl ---------------------------------------------------------------------------
|
||||
dnl Finish
|
||||
dnl ---------------------------------------------------------------------------
|
||||
|
||||
# Turn on the additional warnings last, so -Werror doesn't affect other tests.
|
||||
|
||||
AC_ARG_ENABLE(more-warnings,
|
||||
[AC_HELP_STRING([--enable-more-warnings],
|
||||
[Maximum compiler warnings])],
|
||||
set_more_warnings="$enableval",[
|
||||
if test -d $srcdir/../.hg; then
|
||||
set_more_warnings=yes
|
||||
else
|
||||
set_more_warnings=no
|
||||
fi
|
||||
])
|
||||
AC_MSG_CHECKING(for more warnings)
|
||||
if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
|
||||
AC_MSG_RESULT(yes)
|
||||
CFLAGS="\
|
||||
-Wall \
|
||||
-Wchar-subscripts -Wmissing-declarations -Wmissing-prototypes \
|
||||
-Wnested-externs -Wpointer-arith \
|
||||
-Wcast-align -Wsign-compare \
|
||||
$CFLAGS"
|
||||
|
||||
for option in -Wno-strict-aliasing -Wno-sign-compare; do
|
||||
SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $option"
|
||||
AC_MSG_CHECKING([whether gcc understands $option])
|
||||
AC_TRY_COMPILE([], [],
|
||||
has_option=yes,
|
||||
has_option=no,)
|
||||
if test $has_option = no; then
|
||||
CFLAGS="$SAVE_CFLAGS"
|
||||
fi
|
||||
AC_MSG_RESULT($has_option)
|
||||
unset has_option
|
||||
unset SAVE_CFLAGS
|
||||
done
|
||||
unset option
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Flags
|
||||
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CPPFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
|
||||
# Files
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
ipa-kpasswd/Makefile
|
||||
ipa-slapi-plugins/Makefile
|
||||
ipa-slapi-plugins/ipa-enrollment/Makefile
|
||||
ipa-slapi-plugins/ipa-lockout/Makefile
|
||||
ipa-slapi-plugins/ipa-pwd-extop/Makefile
|
||||
ipa-slapi-plugins/ipa-winsync/Makefile
|
||||
ipa-slapi-plugins/ipa-version/Makefile
|
||||
ipa-slapi-plugins/ipa-uuid/Makefile
|
||||
ipa-slapi-plugins/ipa-modrdn/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
||||
|
||||
echo "
|
||||
IPA Server $VERSION
|
||||
========================
|
||||
|
||||
prefix: ${prefix}
|
||||
exec_prefix: ${exec_prefix}
|
||||
libdir: ${libdir}
|
||||
bindir: ${bindir}
|
||||
sbindir: ${sbindir}
|
||||
sysconfdir: ${sysconfdir}
|
||||
localstatedir: ${localstatedir}
|
||||
datadir: ${datadir}
|
||||
source code location: ${srcdir}
|
||||
compiler: ${CC}
|
||||
cflags: ${CFLAGS}
|
||||
LDAP libs: ${LDAP_LIBS}
|
||||
KRB5 libs: ${KRB5_LIBS}
|
||||
OpenSSL libs: ${SSL_LIBS}
|
||||
Maintainer mode: ${USE_MAINTAINER_MODE}
|
||||
"
|
59
daemons/ipa-kpasswd/Makefile.am
Normal file
59
daemons/ipa-kpasswd/Makefile.am
Normal file
@ -0,0 +1,59 @@
|
||||
NULL =
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(OPENLDAP_CFLAGS) \
|
||||
$(KRB5_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
sbin_PROGRAMS = \
|
||||
ipa_kpasswd \
|
||||
$(NULL)
|
||||
|
||||
ipa_kpasswd_SOURCES = \
|
||||
ipa_kpasswd.c \
|
||||
$(NULL)
|
||||
|
||||
ipa_kpasswd_LDADD = \
|
||||
$(OPENLDAP_LIBS) \
|
||||
$(KRB5_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
install-exec-local:
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/cache/ipa/kpasswd
|
||||
chmod 700 $(DESTDIR)$(localstatedir)/cache/ipa/kpasswd
|
||||
|
||||
uninstall-local:
|
||||
-rmdir $(DESTDIR)$(localstatedir)/cache/ipa/kpasswd
|
||||
-rmdir $(DESTDIR)$(localstatedir)/cache/ipa
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
ipa_kpasswd.init \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
||||
|
||||
initdir=$(sysconfdir)/rc.d/init.d
|
||||
|
||||
install-data-hook: ipa_kpasswd.init
|
||||
|
||||
if test '!' -d $(DESTDIR)$(initdir); then \
|
||||
$(mkinstalldirs) $(DESTDIR)$(initdir); \
|
||||
chmod 755 $(DESTDIR)$(initdir); \
|
||||
fi
|
||||
|
||||
$(INSTALL_SCRIPT) $(srcdir)/ipa_kpasswd.init $(DESTDIR)$(initdir)/ipa_kpasswd
|
||||
|
||||
uninstall-hook:
|
||||
rm -f $(DESTDIR)$(initdir)/ipa_kpasswd
|
2
daemons/ipa-kpasswd/README
Normal file
2
daemons/ipa-kpasswd/README
Normal file
@ -0,0 +1,2 @@
|
||||
This is an implementation of the RFC3244 kpasswd protocol.
|
||||
It is used to proxy password change operations to Directory Server.
|
1422
daemons/ipa-kpasswd/ipa_kpasswd.c
Normal file
1422
daemons/ipa-kpasswd/ipa_kpasswd.c
Normal file
File diff suppressed because it is too large
Load Diff
83
daemons/ipa-kpasswd/ipa_kpasswd.init
Normal file
83
daemons/ipa-kpasswd/ipa_kpasswd.init
Normal file
@ -0,0 +1,83 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# ipa_kpasswd This starts and stops ipa_kpasswd
|
||||
#
|
||||
# chkconfig: - 36 64
|
||||
# description: ipa_kpasswd IPA Kpasswd daemon
|
||||
# processname: /usr/sbin/ipa_kpasswd
|
||||
# configdir: /etc/sysconfig/ipa-kpasswd
|
||||
#
|
||||
|
||||
# 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
|
||||
|
||||
# Source networking configuration.
|
||||
if [ -f /etc/sysconfig/ipa-kpasswd ] ; then
|
||||
. /etc/sysconfig/ipa-kpasswd
|
||||
fi
|
||||
|
||||
NAME="ipa_kpasswd"
|
||||
PROG="/usr/sbin/ipa_kpasswd"
|
||||
|
||||
start() {
|
||||
echo -n $"Starting $NAME: "
|
||||
daemon $NAME
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ipa_kpasswd || \
|
||||
RETVAL=1
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop() {
|
||||
echo -n $"Shutting down $NAME: "
|
||||
killproc $NAME
|
||||
RETVAL=$?
|
||||
echo
|
||||
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ipa_kpasswd
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status $PROG
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
condrestart)
|
||||
[ -f /var/lock/subsys/ipa_kpasswd ] && restart || :
|
||||
;;
|
||||
reload)
|
||||
exit 3
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart}"
|
||||
exit 2
|
||||
esac
|
||||
|
||||
exit $?
|
19
daemons/ipa-slapi-plugins/Makefile.am
Normal file
19
daemons/ipa-slapi-plugins/Makefile.am
Normal file
@ -0,0 +1,19 @@
|
||||
NULL =
|
||||
|
||||
SUBDIRS = \
|
||||
ipa-enrollment \
|
||||
ipa-lockout \
|
||||
ipa-modrdn \
|
||||
ipa-pwd-extop \
|
||||
ipa-uuid \
|
||||
ipa-version \
|
||||
ipa-winsync \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
0
daemons/ipa-slapi-plugins/README
Normal file
0
daemons/ipa-slapi-plugins/README
Normal file
75
daemons/ipa-slapi-plugins/common/util.h
Normal file
75
daemons/ipa-slapi-plugins/common/util.h
Normal file
@ -0,0 +1,75 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#ifndef _SLAPI_PLUGINS_UTIL_H
|
||||
#define _SLAPI_PLUGINS_UTIL_H
|
||||
|
||||
#define EOK 0
|
||||
#define EFAIL -1
|
||||
|
||||
#ifndef discard_const
|
||||
#define discard_const(ptr) ((void *)((uintptr_t)(ptr)))
|
||||
#endif
|
||||
|
||||
#define log_func discard_const(__func__)
|
||||
|
||||
#define LOG_PLUGIN_NAME(NAME, fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_PLUGIN, \
|
||||
NAME, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG(fmt, ...) \
|
||||
LOG_PLUGIN_NAME(IPA_PLUGIN_NAME, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_CONFIG_NAME(NAME, fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_CONFIG, \
|
||||
NAME, \
|
||||
fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_CONFIG(fmt, ...) \
|
||||
LOG_CONFIG_NAME(IPA_PLUGIN_NAME, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_FATAL(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_FATAL, log_func, \
|
||||
"[file %s, line %d]: " fmt, \
|
||||
__FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_TRACE(fmt, ...) \
|
||||
slapi_log_error(SLAPI_LOG_TRACE, log_func, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define LOG_OOM() LOG_FATAL("Out of Memory!\n")
|
||||
|
||||
#endif /* _SLAPI_PLUGINS_UTIL_H */
|
46
daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am
Normal file
46
daemons/ipa-slapi-plugins/ipa-enrollment/Makefile.am
Normal file
@ -0,0 +1,46 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(KRB5_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_enrollment_extop.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_enrollment_extop_la_SOURCES = \
|
||||
ipa_enrollment.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_enrollment_extop_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_enrollment_extop_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
enrollment-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
@ -0,0 +1,16 @@
|
||||
dn: cn=ipa_enrollment_extop,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: ipa_enrollment_extop
|
||||
nsslapd-pluginpath: libipa_enrollment_extop
|
||||
nsslapd-plugininitfunc: ipaenrollment_init
|
||||
nsslapd-plugintype: extendedop
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipa_enrollment_extop
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: RedHat
|
||||
nsslapd-plugindescription: Enroll hosts into the IPA domain
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
nsslapd-realmTree: $SUFFIX
|
462
daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c
Normal file
462
daemons/ipa-slapi-plugins/ipa-enrollment/ipa_enrollment.c
Normal file
@ -0,0 +1,462 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enroll a host into the IPA domain.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <dirsrv/slapi-plugin.h>
|
||||
#include <krb5.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define IPA_PLUGIN_NAME "ipa-enrollment"
|
||||
|
||||
/* OID of the extended operation handled by this plug-in */
|
||||
#define JOIN_OID "2.16.840.1.113730.3.8.10.3"
|
||||
|
||||
Slapi_PluginDesc pdesc = {
|
||||
IPA_PLUGIN_NAME,
|
||||
"IPA Project",
|
||||
"IPA/2.0",
|
||||
"IPA Enrollment Extended Operation plugin"
|
||||
};
|
||||
|
||||
static char *ipaenrollment_oid_list[] = {
|
||||
JOIN_OID,
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *ipaenrollment_name_list[] = {
|
||||
"Enrollment Extended Operation",
|
||||
NULL
|
||||
};
|
||||
|
||||
static void *ipaenrollment_plugin_id;
|
||||
|
||||
static char *realm;
|
||||
static const char *ipa_realm_dn;
|
||||
|
||||
static int
|
||||
ipaenrollement_secure(Slapi_PBlock *pb, char **errMesg)
|
||||
{
|
||||
int ssf;
|
||||
int rc = LDAP_SUCCESS;
|
||||
|
||||
LOG_TRACE("=> ipaenrollment_secure\n");
|
||||
|
||||
/* Allow enrollment on all connections with a Security Strength
|
||||
* Factor (SSF) higher than 1 */
|
||||
if (slapi_pblock_get(pb, SLAPI_OPERATION_SSF, &ssf) != 0) {
|
||||
LOG_TRACE("Could not get SSF from connection\n");
|
||||
*errMesg = "Operation requires a secure connection.\n";
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (NULL == realm) {
|
||||
*errMesg = "Kerberos realm is not set.\n";
|
||||
LOG_FATAL("%s", errMesg);
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ssf <= 1) {
|
||||
*errMesg = "Operation requires a secure connection.\n";
|
||||
rc = LDAP_CONFIDENTIALITY_REQUIRED;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
LOG_TRACE("<= ipaenrollment_secure\n");
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
/* The extop call passes in the FQDN of the host to enroll.
|
||||
* We take that and set the krbPrincipalName and add the appropriate
|
||||
* objectclasses, then return krbPrincipalName. The caller should take
|
||||
* this and pass it to ipa-getkeytab to generate the keytab.
|
||||
*
|
||||
* The password for the entry is removed by ipa-getkeytab.
|
||||
*/
|
||||
static int
|
||||
ipa_join(Slapi_PBlock *pb)
|
||||
{
|
||||
char *bindDN = NULL;
|
||||
char *errMesg = NULL;
|
||||
struct berval *extop_value = NULL;
|
||||
Slapi_PBlock *pbte = NULL;
|
||||
Slapi_PBlock *pbtm = NULL;
|
||||
Slapi_Entry *targetEntry=NULL;
|
||||
Slapi_DN *sdn;
|
||||
Slapi_Backend *be;
|
||||
Slapi_Entry **es = NULL;
|
||||
int rc=0, ret=0, res, i;
|
||||
int is_root=0;
|
||||
char *krbLastPwdChange = NULL;
|
||||
char *fqdn = NULL;
|
||||
Slapi_Mods *smods;
|
||||
char *attrlist[] = {"fqdn", "krbPrincipalKey", "krbLastPwdChange", "krbPrincipalName", NULL };
|
||||
char * filter;
|
||||
|
||||
int scope = LDAP_SCOPE_SUBTREE;
|
||||
char *principal = NULL;
|
||||
struct berval retbval;
|
||||
|
||||
if (NULL == realm) {
|
||||
errMesg = "Kerberos realm is not set.\n";
|
||||
LOG_FATAL("%s", errMesg);
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* Get Bind DN */
|
||||
slapi_pblock_get(pb, SLAPI_CONN_DN, &bindDN);
|
||||
|
||||
/* If the connection is bound anonymously we must refuse to process
|
||||
* this operation.
|
||||
*/
|
||||
if (bindDN == NULL || *bindDN == '\0') {
|
||||
/* Refuse the operation because they're bound anonymously */
|
||||
errMesg = "Anonymous Binds are not allowed.\n";
|
||||
rc = LDAP_INSUFFICIENT_ACCESS;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* Get the ber value of the extended operation */
|
||||
slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
|
||||
|
||||
/* We are passed in the FQDN of the host to enroll. Do an internal
|
||||
* search and pull that entry.
|
||||
*/
|
||||
filter = slapi_ch_smprintf("(fqdn=%s)", extop_value->bv_val);
|
||||
pbte = slapi_pblock_new();
|
||||
slapi_search_internal_set_pb(pbte,
|
||||
ipa_realm_dn, scope, filter, attrlist, 0,
|
||||
NULL, /* Controls */
|
||||
NULL, /* UniqueID */
|
||||
ipaenrollment_plugin_id,
|
||||
0); /* Flags */
|
||||
|
||||
/* do search the tree */
|
||||
ret = slapi_search_internal_pb(pbte);
|
||||
slapi_pblock_get(pbte, SLAPI_PLUGIN_INTOP_RESULT, &res);
|
||||
if (ret == -1 || res != LDAP_SUCCESS) {
|
||||
LOG_TRACE("Search for host failed, err (%d)\n", res?res:ret);
|
||||
errMesg = "Host not found.\n";
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* get entries */
|
||||
slapi_pblock_get(pbte, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &es);
|
||||
if (!es) {
|
||||
LOG_TRACE("No entries ?!");
|
||||
errMesg = "Host not found.\n";
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* count entries */
|
||||
for (i = 0; es[i]; i++) /* count */ ;
|
||||
|
||||
/* if there is none or more than one, freak out */
|
||||
if (i != 1) {
|
||||
LOG_TRACE("Too many entries, or entry no found (%d)", i);
|
||||
errMesg = "Host not found.\n";
|
||||
rc = LDAP_NO_SUCH_OBJECT;
|
||||
goto free_and_return;
|
||||
}
|
||||
targetEntry = es[0];
|
||||
|
||||
/* Is this host already enrolled? */
|
||||
krbLastPwdChange = slapi_entry_attr_get_charptr(targetEntry, "krbLastPwdChange");
|
||||
if (NULL != krbLastPwdChange) {
|
||||
LOG_TRACE("Host already enrolled");
|
||||
errMesg = "Host already enrolled.\n";
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* First thing to do is to ask access control if the bound identity has
|
||||
* rights to modify the userpassword attribute on this entry. If not,
|
||||
* then we fail immediately with insufficient access. This means that
|
||||
* we don't leak any useful information to the client such as current
|
||||
* password wrong, etc.
|
||||
*/
|
||||
|
||||
is_root = slapi_dn_isroot(bindDN);
|
||||
if (slapi_pblock_set(pb, SLAPI_REQUESTOR_ISROOT, &is_root)) {
|
||||
LOG_FATAL("slapi_pblock_set failed!\n");
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* In order to perform the access control check,
|
||||
* we need to select a backend (even though
|
||||
* we don't actually need it otherwise).
|
||||
*/
|
||||
sdn = slapi_sdn_new_dn_byval(bindDN);
|
||||
be = slapi_be_select(sdn);
|
||||
if (slapi_pblock_set(pb, SLAPI_BACKEND, be)) {
|
||||
LOG_FATAL("slapi_pblock_set failed!\n");
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* Access Strategy:
|
||||
* If the user has WRITE-ONLY access, a new keytab is set on the entry.
|
||||
*/
|
||||
|
||||
ret = slapi_access_allowed(pb, targetEntry, "krbPrincipalKey", NULL, SLAPI_ACL_WRITE);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
errMesg = "Insufficient access rights\n";
|
||||
rc = LDAP_INSUFFICIENT_ACCESS;
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* If a principal is already set return the name */
|
||||
principal = slapi_entry_attr_get_charptr(targetEntry, "krbPrincipalName");
|
||||
if (NULL != principal)
|
||||
goto done;
|
||||
|
||||
/* Add the elements needed for enrollment */
|
||||
smods = slapi_mods_new();
|
||||
fqdn = slapi_entry_attr_get_charptr(targetEntry, "fqdn");
|
||||
principal = slapi_ch_smprintf("host/%s@%s", fqdn, realm);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_ADD, "krbPrincipalName", principal);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_ADD, "objectClass", "krbPrincipalAux");
|
||||
|
||||
pbtm = slapi_pblock_new();
|
||||
slapi_modify_internal_set_pb (pbtm, slapi_entry_get_dn_const(targetEntry),
|
||||
slapi_mods_get_ldapmods_byref(smods),
|
||||
NULL, /* Controls */
|
||||
NULL, /* UniqueID */
|
||||
ipaenrollment_plugin_id, /* PluginID */
|
||||
0); /* Flags */
|
||||
|
||||
rc = slapi_modify_internal_pb (pbtm);
|
||||
if (rc) {
|
||||
LOG_TRACE("WARNING: modify error %d on entry '%s'\n",
|
||||
rc, slapi_entry_get_dn_const(targetEntry));
|
||||
} else {
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
|
||||
if (rc != LDAP_SUCCESS){
|
||||
LOG_TRACE("WARNING: modify error %d on entry '%s'\n",
|
||||
rc, slapi_entry_get_dn_const(targetEntry));
|
||||
} else {
|
||||
LOG_TRACE("<= apply mods: Successful\n");
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* Return the krbprincipalname */
|
||||
retbval.bv_val = principal;
|
||||
retbval.bv_len = strlen(principal);
|
||||
|
||||
ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, JOIN_OID);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &retbval);
|
||||
if (ret) {
|
||||
errMesg = "Could not set return values";
|
||||
LOG("%s\n", errMesg);
|
||||
rc = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
|
||||
}
|
||||
|
||||
/* Free anything that we allocated above */
|
||||
free_and_return:
|
||||
|
||||
if (pbte) {
|
||||
slapi_free_search_results_internal(pbte);
|
||||
slapi_pblock_destroy(pbte);
|
||||
}
|
||||
if (pbtm) {
|
||||
slapi_pblock_destroy(pbtm);
|
||||
}
|
||||
|
||||
if (krbLastPwdChange) slapi_ch_free_string(&krbLastPwdChange);
|
||||
|
||||
LOG(errMesg ? errMesg : "success\n");
|
||||
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
|
||||
|
||||
free(principal);
|
||||
|
||||
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
|
||||
}
|
||||
|
||||
/* Extended operation plug-in */
|
||||
static int
|
||||
ipaenrollment_extop(Slapi_PBlock *pb)
|
||||
{
|
||||
char *oid;
|
||||
char *errMesg = NULL;
|
||||
int rc, ret;
|
||||
|
||||
LOG_TRACE("=> ipaenrollment_extop\n");
|
||||
|
||||
rc = ipaenrollement_secure(pb, &errMesg);
|
||||
if (rc) {
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* Get the OID and the value included in the request */
|
||||
if (slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0) {
|
||||
errMesg = "Could not get OID and value from request.\n";
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
LOG(errMesg);
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
if (strcasecmp(oid, JOIN_OID) == 0) {
|
||||
ret = ipa_join(pb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
errMesg = "Request OID does not match supported OIDs.\n";
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
|
||||
free_and_return:
|
||||
LOG(errMesg);
|
||||
slapi_send_ldap_result(pb, rc, NULL, errMesg, 0, NULL);
|
||||
|
||||
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
|
||||
}
|
||||
|
||||
static int
|
||||
ipaenrollment_start(Slapi_PBlock *pb)
|
||||
{
|
||||
krb5_error_code krberr;
|
||||
krb5_context krbctx;
|
||||
char *config_dn = NULL;
|
||||
char *partition_dn = NULL;
|
||||
Slapi_Entry *config_entry = NULL;
|
||||
int ret = LDAP_SUCCESS;
|
||||
Slapi_DN *sdn;
|
||||
int rc = 0;
|
||||
|
||||
krberr = krb5_init_context(&krbctx);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_init_context failed\n");
|
||||
/* Yes, we failed, but it is because /etc/krb5.conf doesn't exist
|
||||
* or is misconfigured. Start up in a degraded mode.
|
||||
*/
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_get_default_realm(krbctx, &realm);
|
||||
if (krberr) {
|
||||
realm = NULL;
|
||||
LOG_FATAL("Failed to get default realm?!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (slapi_pblock_get(pb, SLAPI_TARGET_DN, &config_dn) != 0) {
|
||||
LOG_FATAL("No config DN?\n");
|
||||
goto done;
|
||||
}
|
||||
sdn = slapi_sdn_new_dn_byref(config_dn);
|
||||
if ((rc = slapi_search_internal_get_entry(sdn, NULL, &config_entry,
|
||||
ipaenrollment_plugin_id)) != LDAP_SUCCESS ){
|
||||
LOG_TRACE("ipaenrollment_start: No such entry-(%s), err (%d)\n",
|
||||
config_dn, rc);
|
||||
}
|
||||
slapi_sdn_free(&sdn);
|
||||
|
||||
partition_dn = slapi_entry_attr_get_charptr(config_entry, "nsslapd-realmtree");
|
||||
if (!partition_dn) {
|
||||
LOG_FATAL("Missing partition configuration entry (nsslapd-realmTree)!\n");
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ipa_realm_dn = slapi_ch_smprintf("cn=computers,cn=accounts,%s", partition_dn);
|
||||
slapi_ch_free_string(&partition_dn);
|
||||
if (!ipa_realm_dn) {
|
||||
LOG_FATAL("Out of memory ?\n");
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
if (krbctx) krb5_free_context(krbctx);
|
||||
if (config_entry) slapi_entry_free(config_entry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ipaenrollment_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Get the arguments appended to the plugin extendedop directive
|
||||
* in the plugin entry. The first argument
|
||||
* (after the standard arguments for the directive) should
|
||||
* contain the OID of the extended op.
|
||||
*/
|
||||
|
||||
ret = slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &ipaenrollment_plugin_id);
|
||||
if ((ret != 0) || (NULL == ipaenrollment_plugin_id)) {
|
||||
LOG("Could not get identity or identity was NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG("Registering plug-in for extended op.\n");
|
||||
|
||||
/* Register the plug-in function as an extended operation
|
||||
plug-in function. */
|
||||
ret = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)ipaenrollment_start);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, ipaenrollment_oid_list);
|
||||
if (!ret) ret = slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, ipaenrollment_name_list);
|
||||
if (!ret) slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)ipaenrollment_extop);
|
||||
|
||||
if (ret) {
|
||||
LOG("Failed to set plug-in version, function, and OID.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
46
daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am
Normal file
46
daemons/ipa-slapi-plugins/ipa-lockout/Makefile.am
Normal file
@ -0,0 +1,46 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-I/usr/include/dirsrv \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_lockout.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_lockout_la_SOURCES = \
|
||||
ipa_lockout.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_lockout_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_lockout_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
lockout-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
643
daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c
Normal file
643
daemons/ipa-slapi-plugins/ipa-lockout/ipa_lockout.c
Normal file
@ -0,0 +1,643 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
/**
|
||||
* IPA Lockout plug-in
|
||||
*
|
||||
* Update the Kerberos lockout variables on LDAP binds.
|
||||
*
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include "slapi-plugin.h"
|
||||
#include "nspr.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define IPALOCKOUT_PLUGIN_NAME "ipa-lockout-plugin"
|
||||
#define IPALOCKOUT_PLUGIN_VERSION 0x00010000
|
||||
|
||||
#define IPA_PLUGIN_NAME IPALOCKOUT_PLUGIN_NAME
|
||||
|
||||
#define IPALOCKOUT_FEATURE_DESC "IPA Lockout"
|
||||
#define IPALOCKOUT_PLUGIN_DESC "IPA Lockout plugin"
|
||||
#define IPALOCKOUT_POSTOP_DESC "IPA Lockout postop plugin"
|
||||
#define IPALOCKOUT_PREOP_DESC "IPA Lockout preop plugin"
|
||||
|
||||
static Slapi_PluginDesc pdesc = {
|
||||
IPALOCKOUT_FEATURE_DESC,
|
||||
"Red Hat, Inc.",
|
||||
"1.0",
|
||||
IPALOCKOUT_PLUGIN_DESC
|
||||
};
|
||||
|
||||
static void *_PluginID = NULL;
|
||||
static char *_PluginDN = NULL;
|
||||
|
||||
static int g_plugin_started = 0;
|
||||
|
||||
#define GENERALIZED_TIME_LENGTH 15
|
||||
|
||||
/**
|
||||
*
|
||||
* management functions
|
||||
*
|
||||
*/
|
||||
int ipalockout_init(Slapi_PBlock * pb);
|
||||
static int ipalockout_start(Slapi_PBlock * pb);
|
||||
static int ipalockout_close(Slapi_PBlock * pb);
|
||||
static int ipalockout_postop_init(Slapi_PBlock * pb);
|
||||
static int ipalockout_preop_init(Slapi_PBlock * pb);
|
||||
|
||||
/**
|
||||
*
|
||||
* the ops (where the real work is done)
|
||||
*
|
||||
*/
|
||||
static int ipalockout_postop(Slapi_PBlock *pb);
|
||||
static int ipalockout_preop(Slapi_PBlock *pb);
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the plug-in version
|
||||
*
|
||||
*/
|
||||
int ipalockout_version(void)
|
||||
{
|
||||
return IPALOCKOUT_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin identity mgmt
|
||||
*/
|
||||
void setPluginID(void *pluginID)
|
||||
{
|
||||
_PluginID = pluginID;
|
||||
}
|
||||
|
||||
void *getPluginID(void)
|
||||
{
|
||||
return _PluginID;
|
||||
}
|
||||
|
||||
void setPluginDN(char *pluginDN)
|
||||
{
|
||||
_PluginDN = pluginDN;
|
||||
}
|
||||
|
||||
char *getPluginDN(void)
|
||||
{
|
||||
return _PluginDN;
|
||||
}
|
||||
|
||||
int
|
||||
ipalockout_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int status = EOK;
|
||||
char *plugin_identity = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
|
||||
PR_ASSERT(plugin_identity);
|
||||
setPluginID(plugin_identity);
|
||||
|
||||
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
|
||||
SLAPI_PLUGIN_VERSION_01) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
|
||||
(void *) ipalockout_start) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
|
||||
(void *) ipalockout_close) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *) &pdesc) != 0 ||
|
||||
slapi_register_plugin("postoperation",
|
||||
1,
|
||||
"ipalockout_init",
|
||||
ipalockout_postop_init,
|
||||
IPALOCKOUT_POSTOP_DESC,
|
||||
NULL,
|
||||
plugin_identity
|
||||
) ||
|
||||
slapi_register_plugin("preoperation",
|
||||
1,
|
||||
"ipalockout_init",
|
||||
ipalockout_preop_init,
|
||||
IPALOCKOUT_PREOP_DESC,
|
||||
NULL,
|
||||
plugin_identity
|
||||
)
|
||||
) {
|
||||
LOG_FATAL("failed to register plugin\n");
|
||||
status = EFAIL;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
ipalockout_postop_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int status = EOK;
|
||||
|
||||
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
|
||||
SLAPI_PLUGIN_VERSION_01) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *) &pdesc) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_BIND_FN,
|
||||
(void *) ipalockout_postop) != 0) {
|
||||
status = EFAIL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
ipalockout_preop_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int status = EOK;
|
||||
|
||||
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
|
||||
SLAPI_PLUGIN_VERSION_01) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *) &pdesc) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_BIND_FN,
|
||||
(void *) ipalockout_preop) != 0) {
|
||||
status = EFAIL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
ipalockout_start(Slapi_PBlock * pb)
|
||||
{
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Check if we're already started */
|
||||
if (g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
g_plugin_started = 1;
|
||||
LOG("ready for service\n");
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
done:
|
||||
return EOK;
|
||||
}
|
||||
|
||||
static int
|
||||
ipalockout_close(Slapi_PBlock * pb)
|
||||
{
|
||||
LOG_TRACE( "--in-->\n");
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the post-operation we know whether the bind was successful or not
|
||||
* so here we handle updating the Kerberos lockout policy attributes.
|
||||
*/
|
||||
static int ipalockout_postop(Slapi_PBlock *pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
char *policy_dn = NULL;
|
||||
Slapi_Entry *target_entry = NULL;
|
||||
Slapi_Entry *policy_entry = NULL;
|
||||
Slapi_DN *sdn = NULL;
|
||||
Slapi_DN *pdn = NULL;
|
||||
Slapi_PBlock *pbtm = NULL;
|
||||
Slapi_Mods *smods = NULL;
|
||||
Slapi_Value *objectclass = NULL;
|
||||
char *errstr = NULL;
|
||||
int ldrc, rc = 0;
|
||||
int ret = LDAP_SUCCESS;
|
||||
unsigned long failedcount = 0;
|
||||
char failedcountstr[32];
|
||||
int failed_bind = 0;
|
||||
struct tm utctime;
|
||||
time_t time_now;
|
||||
char timestr[GENERALIZED_TIME_LENGTH+1];
|
||||
unsigned int failcnt_interval = 0;
|
||||
char *lastfail = NULL;
|
||||
int tries = 0;
|
||||
int failure = 1;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Just bail if we aren't ready to service requests yet. */
|
||||
if (!g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
|
||||
|
||||
/* free the dn here */
|
||||
if (slapi_pblock_get(pb, SLAPI_CONN_DN, &dn) != 0) {
|
||||
LOG_FATAL("Error retrieving bind DN\n");
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* dn will be NULL on failed auth, get the target instead */
|
||||
/* don't free this dn */
|
||||
if (dn == NULL && rc != LDAP_SUCCESS) {
|
||||
failed_bind = 1;
|
||||
if (slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn) != 0) {
|
||||
LOG_FATAL("Error retrieving target DN\n");
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
/* Client is anonymously bound */
|
||||
if (dn == NULL) {
|
||||
LOG_TRACE("anonymous bind\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the entry */
|
||||
sdn = slapi_sdn_new_dn_byref(dn);
|
||||
if (sdn == NULL) {
|
||||
LOG_OOM();
|
||||
errstr = "Out of memory.\n";
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry,
|
||||
getPluginID());
|
||||
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Only update kerberos principal entries */
|
||||
objectclass = slapi_value_new_string("krbPrincipalAux");
|
||||
if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) {
|
||||
LOG_TRACE("Not a kerberos user\n");
|
||||
slapi_value_free(&objectclass);
|
||||
goto done;
|
||||
}
|
||||
slapi_value_free(&objectclass);
|
||||
|
||||
/* Only update if there is a password policy */
|
||||
policy_dn = slapi_entry_attr_get_charptr(target_entry, "krbPwdPolicyReference");
|
||||
if (policy_dn == NULL) {
|
||||
LOG_TRACE("No kerberos password policy\n");
|
||||
goto done;
|
||||
} else {
|
||||
pdn = slapi_sdn_new_dn_byref(policy_dn);
|
||||
ldrc = slapi_search_internal_get_entry(pdn, NULL, &policy_entry,
|
||||
getPluginID());
|
||||
slapi_sdn_free(&pdn);
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", policy_dn, ldrc);
|
||||
errstr = "Failed to retrieve account policy.";
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
failedcount = slapi_entry_attr_get_ulong(target_entry, "krbLoginFailedCount");
|
||||
failcnt_interval = slapi_entry_attr_get_uint(policy_entry, "krbPwdFailureCountInterval");
|
||||
lastfail = slapi_entry_attr_get_charptr(target_entry, "krbLastFailedAuth");
|
||||
time_now = time(NULL);
|
||||
if (lastfail != NULL) {
|
||||
struct tm tm;
|
||||
int ret = 0;
|
||||
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
ret = sscanf(lastfail,
|
||||
"%04u%02u%02u%02u%02u%02u",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||
|
||||
if (ret == 6) {
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
|
||||
if (time_now > timegm(&tm) + failcnt_interval) {
|
||||
failedcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (tries < 5) {
|
||||
smods = slapi_mods_new();
|
||||
|
||||
/* On failures try very hard to update the entry so that failures
|
||||
* are counted properly. This involves doing a DELETE of the value
|
||||
* we expect and an ADD of the new one in the same update. If the
|
||||
* record has changed while we were handling the request our
|
||||
* update will fail and we will try again.
|
||||
*
|
||||
* On a successful bind just do a replace and set failurecount to 0.
|
||||
*/
|
||||
if (failed_bind) {
|
||||
PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", failedcount);
|
||||
if (!gmtime_r(&(time_now), &utctime)) {
|
||||
errstr = "failed to parse current date (buggy gmtime_r ?)\n";
|
||||
LOG_FATAL("%s", errstr);
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
strftime(timestr, GENERALIZED_TIME_LENGTH+1,
|
||||
"%Y%m%d%H%M%SZ", &utctime);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_DELETE, "krbLoginFailedCount", failedcountstr);
|
||||
failedcount += 1;
|
||||
PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", failedcount);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_ADD, "krbLoginFailedCount", failedcountstr);
|
||||
if (lastfail)
|
||||
slapi_mods_add_string(smods, LDAP_MOD_DELETE, "krbLastFailedAuth", lastfail);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_ADD, "krbLastFailedAuth", timestr);
|
||||
} else {
|
||||
PR_snprintf(failedcountstr, sizeof(failedcountstr), "%lu", 0L);
|
||||
time_now = time(NULL);
|
||||
if (!gmtime_r(&(time_now), &utctime)) {
|
||||
errstr = "failed to parse current date (buggy gmtime_r ?)\n";
|
||||
LOG_FATAL("%s", errstr);
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
strftime(timestr, GENERALIZED_TIME_LENGTH+1,
|
||||
"%Y%m%d%H%M%SZ", &utctime);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "krbLoginFailedCount", failedcountstr);
|
||||
slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "krbLastSuccessfulAuth", timestr);
|
||||
}
|
||||
|
||||
pbtm = slapi_pblock_new();
|
||||
slapi_modify_internal_set_pb (pbtm, slapi_entry_get_dn_const(target_entry),
|
||||
slapi_mods_get_ldapmods_byref(smods),
|
||||
NULL, /* Controls */
|
||||
NULL, /* UniqueID */
|
||||
getPluginID(), /* PluginID */
|
||||
0); /* Flags */
|
||||
|
||||
slapi_modify_internal_pb (pbtm);
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
|
||||
if (rc != LDAP_SUCCESS) {
|
||||
LOG_TRACE("WARNING: modify error %d on entry '%s'\n",
|
||||
rc, slapi_entry_get_dn_const(target_entry));
|
||||
|
||||
ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry,
|
||||
getPluginID());
|
||||
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc);
|
||||
goto done;
|
||||
}
|
||||
slapi_mods_free(&smods);
|
||||
slapi_pblock_destroy(pbtm);
|
||||
if (lastfail) slapi_ch_free_string(&lastfail);
|
||||
smods = NULL;
|
||||
pbtm = NULL;
|
||||
lastfail = NULL;
|
||||
tries += 1;
|
||||
} else {
|
||||
LOG_TRACE("<= apply mods: Successful\n");
|
||||
failure = 0;
|
||||
break;
|
||||
}
|
||||
} /* while */
|
||||
|
||||
if (failure) {
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!failed_bind && dn != NULL) slapi_ch_free_string(&dn);
|
||||
slapi_entry_free(target_entry);
|
||||
if (policy_dn) {
|
||||
slapi_ch_free_string(&policy_dn);
|
||||
slapi_entry_free(policy_entry);
|
||||
}
|
||||
if (sdn) slapi_sdn_free(&sdn);
|
||||
if (lastfail) slapi_ch_free_string(&lastfail);
|
||||
if (pbtm) slapi_pblock_destroy(pbtm);
|
||||
if (smods) slapi_mods_free(&smods);
|
||||
|
||||
LOG("postop returning %d: %s\n", ret, errstr ? errstr : "success\n");
|
||||
|
||||
if (ret) {
|
||||
slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return (ret == 0 ? EOK : EFAIL);
|
||||
}
|
||||
|
||||
/*
|
||||
* In the pre-op stage the bind hasn't occurred yet. It is here that
|
||||
* we do the lockout enforcement.
|
||||
*/
|
||||
static int ipalockout_preop(Slapi_PBlock *pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
char *policy_dn = NULL;
|
||||
Slapi_Entry *target_entry = NULL;
|
||||
Slapi_Entry *policy_entry = NULL;
|
||||
Slapi_DN *sdn = NULL;
|
||||
Slapi_DN *pdn = NULL;
|
||||
Slapi_Value *objectclass = NULL;
|
||||
char *errstr = NULL;
|
||||
int ldrc = 0;
|
||||
int ret = LDAP_SUCCESS;
|
||||
unsigned long failedcount = 0;
|
||||
time_t time_now;
|
||||
unsigned int failcnt_interval = 0;
|
||||
unsigned int max_fail = 0;
|
||||
unsigned int lockout_duration = 0;
|
||||
time_t last_failed = 0;
|
||||
char *lastfail = NULL;
|
||||
char *unlock_time = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Just bail if we aren't ready to service requests yet. */
|
||||
if (!g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn) != 0) {
|
||||
LOG_FATAL("Error retrieving target DN\n");
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Client is anonymously bound */
|
||||
if (dn == NULL) {
|
||||
LOG_TRACE("anonymous bind\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Get the entry */
|
||||
sdn = slapi_sdn_new_dn_byref(dn);
|
||||
if (sdn == NULL) {
|
||||
LOG_OOM();
|
||||
errstr = "Out of memory.\n";
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry,
|
||||
getPluginID());
|
||||
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", dn, ldrc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Only handle kerberos principal entries */
|
||||
objectclass = slapi_value_new_string("krbPrincipalAux");
|
||||
if ((slapi_entry_attr_has_syntax_value(target_entry, SLAPI_ATTR_OBJECTCLASS, objectclass)) != 1) {
|
||||
LOG_TRACE("Not a kerberos user\n");
|
||||
slapi_value_free(&objectclass);
|
||||
goto done;
|
||||
}
|
||||
slapi_value_free(&objectclass);
|
||||
|
||||
/* Only continue if there is a password policy */
|
||||
policy_dn = slapi_entry_attr_get_charptr(target_entry, "krbPwdPolicyReference");
|
||||
if (policy_dn == NULL) {
|
||||
LOG_TRACE("No kerberos password policy\n");
|
||||
goto done;
|
||||
} else {
|
||||
pdn = slapi_sdn_new_dn_byref(policy_dn);
|
||||
ldrc = slapi_search_internal_get_entry(pdn, NULL, &policy_entry,
|
||||
getPluginID());
|
||||
slapi_sdn_free(&pdn);
|
||||
if (ldrc != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to retrieve entry \"%s\": %d\n", policy_dn, ldrc);
|
||||
errstr = "Failed to retrieve account policy.";
|
||||
ret = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
failedcount = slapi_entry_attr_get_ulong(target_entry, "krbLoginFailedCount");
|
||||
time_now = time(NULL);
|
||||
failcnt_interval = slapi_entry_attr_get_uint(policy_entry, "krbPwdFailureCountInterval");
|
||||
lastfail = slapi_entry_attr_get_charptr(target_entry, "krbLastFailedAuth");
|
||||
unlock_time = slapi_entry_attr_get_charptr(target_entry, "krbLastAdminUnlock");
|
||||
if (lastfail != NULL) {
|
||||
struct tm tm;
|
||||
int ret = 0;
|
||||
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
ret = sscanf(lastfail,
|
||||
"%04u%02u%02u%02u%02u%02u",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||
|
||||
if (ret == 6) {
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
|
||||
last_failed = timegm(&tm);
|
||||
LOG("%d > %d ?\n", time_now, last_failed + failcnt_interval);
|
||||
LOG("diff %d\n", (last_failed + failcnt_interval) - time_now);
|
||||
if (time_now > last_failed + failcnt_interval) {
|
||||
failedcount = 0;
|
||||
}
|
||||
}
|
||||
if (unlock_time) {
|
||||
time_t unlock;
|
||||
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
ret = sscanf(lastfail,
|
||||
"%04u%02u%02u%02u%02u%02u",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec);
|
||||
|
||||
if (ret == 6) {
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
|
||||
unlock = timegm(&tm);
|
||||
if (last_failed <= unlock) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
slapi_ch_free_string(&unlock_time);
|
||||
}
|
||||
slapi_ch_free_string(&lastfail);
|
||||
}
|
||||
|
||||
max_fail = slapi_entry_attr_get_uint(policy_entry, "krbPwdMaxFailure");
|
||||
if (max_fail == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
lockout_duration = slapi_entry_attr_get_uint(policy_entry, "krbPwdLockoutDuration");
|
||||
if (lockout_duration == 0) {
|
||||
errstr = "Entry permanently locked.\n";
|
||||
ret = LDAP_UNWILLING_TO_PERFORM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (failedcount > max_fail) {
|
||||
if (time_now < last_failed + lockout_duration) {
|
||||
/* Too many failures */
|
||||
LOG_TRACE("Too many failed logins. %lu out of %d\n", failedcount, max_fail);
|
||||
errstr = "Too many failed logins.\n";
|
||||
ret = LDAP_UNWILLING_TO_PERFORM;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
slapi_entry_free(target_entry);
|
||||
slapi_entry_free(policy_entry);
|
||||
if (policy_dn) slapi_ch_free_string(&policy_dn);
|
||||
if (sdn) slapi_sdn_free(&sdn);
|
||||
|
||||
LOG("preop returning %d: %s\n", ret, errstr ? errstr : "success\n");
|
||||
|
||||
if (ret) {
|
||||
slapi_send_ldap_result(pb, ret, NULL, errstr, 0, NULL);
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return (ret == 0 ? EOK : EFAIL);
|
||||
}
|
15
daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif
Normal file
15
daemons/ipa-slapi-plugins/ipa-lockout/lockout-conf.ldif
Normal file
@ -0,0 +1,15 @@
|
||||
dn: cn=IPA Lockout,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: IPA Lockout
|
||||
nsslapd-pluginpath: libipa_lockout
|
||||
nsslapd-plugininitfunc: ipalockout_init
|
||||
nsslapd-plugintype: object
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipalockout_version
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat, Inc.
|
||||
nsslapd-plugindescription: IPA Lockout plugin
|
||||
nsslapd-plugin-depends-on-type: database
|
46
daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am
Normal file
46
daemons/ipa-slapi-plugins/ipa-modrdn/Makefile.am
Normal file
@ -0,0 +1,46 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-I/usr/include/dirsrv \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_modrdn.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_modrdn_la_SOURCES = \
|
||||
ipa_modrdn.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_modrdn_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_modrdn_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
modrdn-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
796
daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
Normal file
796
daemons/ipa-slapi-plugins/ipa-modrdn/ipa_modrdn.c
Normal file
@ -0,0 +1,796 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
/**
|
||||
* IPA MODRDN plug-in
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "slapi-plugin.h"
|
||||
#include "nspr.h"
|
||||
#include "prclist.h"
|
||||
#include <pthread.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define IPA_PLUGIN_NAME "ipa-modrdn-plugin"
|
||||
#define IPAMODRDN_PLUGIN_VERSION 0x00010000
|
||||
|
||||
#define IPAMODRDN_DN "cn=IPA MODRDN,cn=plugins,cn=config" /* temporary */
|
||||
|
||||
/**
|
||||
* IPA MODRDN config types
|
||||
*/
|
||||
#define IPAMODRDN_SATTR "ipaModRDNsourceAttr"
|
||||
#define IPAMODRDN_TATTR "ipaModRDNtargetAttr"
|
||||
#define IPAMODRDN_PREFIX "ipaModRDNprefix"
|
||||
#define IPAMODRDN_SUFFIX "ipaModRDNsuffix"
|
||||
#define IPAMODRDN_FILTER "ipaModRDNfilter"
|
||||
#define IPAMODRDN_SCOPE "ipaModRDNscope"
|
||||
|
||||
#define IPAMODRDN_FEATURE_DESC "IPA MODRDN"
|
||||
#define IPAMODRDN_PLUGIN_DESC "IPA MODRDN plugin"
|
||||
#define IPAMODRDN_POSTOP_DESC "IPA MODRDN postop plugin"
|
||||
|
||||
static Slapi_PluginDesc pdesc = {
|
||||
IPAMODRDN_FEATURE_DESC,
|
||||
"Red Hat, Inc.",
|
||||
"1.0",
|
||||
IPAMODRDN_PLUGIN_DESC
|
||||
};
|
||||
|
||||
/**
|
||||
* linked list of config entries
|
||||
*/
|
||||
|
||||
struct configEntry {
|
||||
PRCList list;
|
||||
char *dn;
|
||||
char *sattr;
|
||||
char *tattr;
|
||||
char *prefix;
|
||||
char *suffix;
|
||||
char *filter;
|
||||
Slapi_Filter *slapi_filter;
|
||||
char *scope;
|
||||
};
|
||||
|
||||
static PRCList *ipamodrdn_global_config = NULL;
|
||||
static pthread_rwlock_t g_ipamodrdn_cache_lock;
|
||||
|
||||
static void *_PluginID = NULL;
|
||||
static char *_PluginDN = NULL;
|
||||
|
||||
static int g_plugin_started = 0;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* management functions
|
||||
*
|
||||
*/
|
||||
int ipamodrdn_init(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_start(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_close(Slapi_PBlock * pb);
|
||||
|
||||
/**
|
||||
*
|
||||
* Local operation functions
|
||||
*
|
||||
*/
|
||||
static int ipamodrdn_load_plugin_config(void);
|
||||
static int ipamodrdn_parse_config_entry(Slapi_Entry * e, bool apply);
|
||||
static void ipamodrdn_delete_config(void);
|
||||
static void ipamodrdn_free_config_entry(struct configEntry ** entry);
|
||||
|
||||
/**
|
||||
*
|
||||
* helpers
|
||||
*
|
||||
*/
|
||||
static char *ipamodrdn_get_dn(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_dn_is_config(char *dn);
|
||||
|
||||
/**
|
||||
*
|
||||
* the ops (where the real work is done)
|
||||
*
|
||||
*/
|
||||
static int ipamodrdn_config_check_post_op(Slapi_PBlock * pb);
|
||||
static int ipamodrdn_post_op(Slapi_PBlock * pb);
|
||||
|
||||
/**
|
||||
* debug functions - global, for the debugger
|
||||
*/
|
||||
void ipamodrdn_dump_config(void);
|
||||
void ipamodrdn_dump_config_entry(struct configEntry *);
|
||||
|
||||
/**
|
||||
*
|
||||
* Deal with cache locking
|
||||
*
|
||||
*/
|
||||
void ipamodrdn_read_lock(void)
|
||||
{
|
||||
pthread_rwlock_rdlock(&g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
void ipamodrdn_write_lock(void)
|
||||
{
|
||||
pthread_rwlock_wrlock(&g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
void ipamodrdn_unlock(void)
|
||||
{
|
||||
pthread_rwlock_unlock(&g_ipamodrdn_cache_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the plug-in version
|
||||
*
|
||||
*/
|
||||
int ipamodrdn_version(void)
|
||||
{
|
||||
return IPAMODRDN_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin identity mgmt
|
||||
*/
|
||||
void setPluginID(void *pluginID)
|
||||
{
|
||||
_PluginID = pluginID;
|
||||
}
|
||||
|
||||
void *getPluginID(void)
|
||||
{
|
||||
return _PluginID;
|
||||
}
|
||||
|
||||
void setPluginDN(char *pluginDN)
|
||||
{
|
||||
_PluginDN = pluginDN;
|
||||
}
|
||||
|
||||
char *getPluginDN(void)
|
||||
{
|
||||
return _PluginDN;
|
||||
}
|
||||
|
||||
/*
|
||||
ipamodrdn_init
|
||||
-------------
|
||||
adds our callbacks to the list
|
||||
*/
|
||||
int
|
||||
ipamodrdn_init(Slapi_PBlock *pb)
|
||||
{
|
||||
int status = EOK;
|
||||
char *plugin_identity = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/**
|
||||
* Store the plugin identity for later use.
|
||||
* Used for internal operations
|
||||
*/
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
|
||||
PR_ASSERT(plugin_identity);
|
||||
setPluginID(plugin_identity);
|
||||
|
||||
if (slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
|
||||
SLAPI_PLUGIN_VERSION_01) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *) &pdesc) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
|
||||
(void *) ipamodrdn_start) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
|
||||
(void *) ipamodrdn_close) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
|
||||
(void *) ipamodrdn_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
|
||||
(void *) ipamodrdn_config_check_post_op) != 0) {
|
||||
LOG_FATAL("failed to register plugin\n");
|
||||
status = EFAIL;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ipamodrdn_start
|
||||
--------------
|
||||
Kicks off the config cache.
|
||||
It is called after ipamodrdn_init.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_start(Slapi_PBlock * pb)
|
||||
{
|
||||
char *plugindn = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Check if we're already started */
|
||||
if (g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pthread_rwlock_init(&g_ipamodrdn_cache_lock, NULL) != 0) {
|
||||
LOG_FATAL("lock creation failed\n");
|
||||
|
||||
return EFAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plug-in target dn from the system
|
||||
* and store it for future use. This should avoid
|
||||
* hardcoding of DN's in the code.
|
||||
*/
|
||||
slapi_pblock_get(pb, SLAPI_TARGET_DN, &plugindn);
|
||||
if (NULL == plugindn || 0 == strlen(plugindn)) {
|
||||
LOG("had to use hard coded config dn\n");
|
||||
plugindn = IPAMODRDN_DN;
|
||||
} else {
|
||||
LOG("config at %s\n", plugindn);
|
||||
|
||||
}
|
||||
|
||||
setPluginDN(plugindn);
|
||||
|
||||
/*
|
||||
* Load the config for our plug-in
|
||||
*/
|
||||
ipamodrdn_global_config = (PRCList *)
|
||||
slapi_ch_calloc(1, sizeof(struct configEntry));
|
||||
PR_INIT_CLIST(ipamodrdn_global_config);
|
||||
|
||||
if (ipamodrdn_load_plugin_config() != EOK) {
|
||||
LOG_FATAL("unable to load plug-in configuration\n");
|
||||
return EFAIL;
|
||||
}
|
||||
|
||||
g_plugin_started = 1;
|
||||
LOG("ready for service\n");
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
done:
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
ipamodrdn_close
|
||||
--------------
|
||||
closes down the cache
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_close(Slapi_PBlock * pb)
|
||||
{
|
||||
LOG_TRACE( "--in-->\n");
|
||||
|
||||
ipamodrdn_delete_config();
|
||||
|
||||
slapi_ch_free((void **)&ipamodrdn_global_config);
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return EOK;
|
||||
}
|
||||
|
||||
/*
|
||||
* config looks like this
|
||||
* - cn=myplugin
|
||||
* --- cn=posix
|
||||
* ------ cn=accounts
|
||||
* ------ cn=groups
|
||||
* --- cn=samba
|
||||
* --- cn=etc
|
||||
* ------ cn=etc etc
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_load_plugin_config(void)
|
||||
{
|
||||
int status = EOK;
|
||||
int result;
|
||||
int i;
|
||||
Slapi_PBlock *search_pb;
|
||||
Slapi_Entry **entries = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
ipamodrdn_write_lock();
|
||||
ipamodrdn_delete_config();
|
||||
|
||||
search_pb = slapi_pblock_new();
|
||||
|
||||
slapi_search_internal_set_pb(search_pb, getPluginDN(),
|
||||
LDAP_SCOPE_SUBTREE, "objectclass=*",
|
||||
NULL, 0, NULL, NULL, getPluginID(), 0);
|
||||
slapi_search_internal_pb(search_pb);
|
||||
slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
|
||||
|
||||
if (LDAP_SUCCESS != result) {
|
||||
status = EFAIL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
|
||||
&entries);
|
||||
if (NULL == entries || NULL == entries[0]) {
|
||||
status = EOK;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; (entries[i] != NULL); i++) {
|
||||
/* We don't care about the status here because we may have
|
||||
* some invalid config entries, but we just want to continue
|
||||
* looking for valid ones. */
|
||||
ipamodrdn_parse_config_entry(entries[i], true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
slapi_free_search_results_internal(search_pb);
|
||||
slapi_pblock_destroy(search_pb);
|
||||
ipamodrdn_unlock();
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* ipamodrdn_parse_config_entry()
|
||||
*
|
||||
* Parses a single config entry. If apply is non-zero, then
|
||||
* we will load and start using the new config. You can simply
|
||||
* validate config without making any changes by setting apply
|
||||
* to 0.
|
||||
*
|
||||
* Returns EOK if the entry is valid and EFAIL
|
||||
* if it is invalid.
|
||||
*/
|
||||
static int
|
||||
ipamodrdn_parse_config_entry(Slapi_Entry * e, bool apply)
|
||||
{
|
||||
char *value;
|
||||
struct configEntry *entry = NULL;
|
||||
struct configEntry *config_entry;
|
||||
PRCList *list;
|
||||
int entry_added = 0;
|
||||
int ret = EOK;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* If this is the main MODRDN plug-in config entry, just bail. */
|
||||
if (strcasecmp(getPluginDN(), slapi_entry_get_ndn(e)) == 0) {
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
entry = (struct configEntry *)
|
||||
slapi_ch_calloc(1, sizeof(struct configEntry));
|
||||
if (NULL == entry) {
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
value = slapi_entry_get_ndn(e);
|
||||
if (value) {
|
||||
entry->dn = slapi_ch_strdup(value);
|
||||
}
|
||||
|
||||
LOG_CONFIG("----------> dn [%s]\n", entry->dn);
|
||||
|
||||
entry->sattr = slapi_entry_attr_get_charptr(e, IPAMODRDN_SATTR);
|
||||
if (!entry->sattr) {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_SATTR, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SATTR, entry->sattr);
|
||||
|
||||
entry->tattr = slapi_entry_attr_get_charptr(e, IPAMODRDN_TATTR);
|
||||
if (!entry->tattr) {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_TATTR, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_TATTR, entry->tattr);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_PREFIX);
|
||||
if (value && value[0]) {
|
||||
entry->prefix = value;
|
||||
} else {
|
||||
entry->prefix = slapi_ch_strdup("");
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_PREFIX, entry->prefix);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_SUFFIX);
|
||||
if (value && value[0]) {
|
||||
entry->suffix = value;
|
||||
} else {
|
||||
entry->suffix = slapi_ch_strdup("");
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SUFFIX, entry->suffix);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_FILTER);
|
||||
if (value) {
|
||||
entry->filter = value;
|
||||
if (NULL == (entry->slapi_filter = slapi_str2filter(value))) {
|
||||
LOG_FATAL("Error: Invalid search filter in entry [%s]: [%s]\n",
|
||||
entry->dn, value);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
LOG_FATAL("The %s config setting is required for %s.\n",
|
||||
IPAMODRDN_FILTER, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_FILTER, value);
|
||||
|
||||
value = slapi_entry_attr_get_charptr(e, IPAMODRDN_SCOPE);
|
||||
if (value) {
|
||||
entry->scope = value;
|
||||
} else {
|
||||
LOG_FATAL("The %s config config setting is required for %s.\n",
|
||||
IPAMODRDN_SCOPE, entry->dn);
|
||||
ret = EFAIL;
|
||||
goto bail;
|
||||
}
|
||||
LOG_CONFIG("----------> %s [%s]\n", IPAMODRDN_SCOPE, entry->scope);
|
||||
|
||||
/* If we were only called to validate config, we can
|
||||
* just bail out before applying the config changes */
|
||||
if (!apply) {
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finally add the entry to the list.
|
||||
* We sort by scope dn length with longer
|
||||
* dn's first - this allows the scope
|
||||
* checking code to be simple and quick and
|
||||
* cunningly linear.
|
||||
*/
|
||||
if (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
while (list != ipamodrdn_global_config) {
|
||||
config_entry = (struct configEntry *) list;
|
||||
|
||||
if (slapi_dn_issuffix(entry->scope, config_entry->scope)) {
|
||||
PR_INSERT_BEFORE(&(entry->list), list);
|
||||
LOG_CONFIG("store [%s] before [%s] \n",
|
||||
entry->scope, config_entry->scope);
|
||||
entry_added = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
list = PR_NEXT_LINK(list);
|
||||
|
||||
if (ipamodrdn_global_config == list) {
|
||||
/* add to tail */
|
||||
PR_INSERT_BEFORE(&(entry->list), list);
|
||||
LOG_CONFIG("store [%s] at tail\n", entry->scope);
|
||||
entry_added = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* first entry */
|
||||
PR_INSERT_LINK(&(entry->list), ipamodrdn_global_config);
|
||||
LOG_CONFIG("store [%s] at head \n", entry->scope);
|
||||
entry_added = 1;
|
||||
}
|
||||
|
||||
bail:
|
||||
if (0 == entry_added) {
|
||||
/* Don't log error if we weren't asked to apply config */
|
||||
if (apply && (entry != NULL)) {
|
||||
LOG_FATAL("Invalid config entry [%s] skipped\n", entry->dn);
|
||||
}
|
||||
ipamodrdn_free_config_entry(&entry);
|
||||
} else {
|
||||
ret = EOK;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_free_config_entry(struct configEntry **entry)
|
||||
{
|
||||
struct configEntry *e;
|
||||
|
||||
if (!entry || !*entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
e = *entry;
|
||||
|
||||
if (e->dn) {
|
||||
LOG_CONFIG("freeing config entry [%s]\n", e->dn);
|
||||
}
|
||||
slapi_ch_free_string(&e->dn);
|
||||
slapi_ch_free_string(&e->sattr);
|
||||
slapi_ch_free_string(&e->tattr);
|
||||
slapi_ch_free_string(&e->prefix);
|
||||
slapi_ch_free_string(&e->suffix);
|
||||
slapi_ch_free_string(&e->filter);
|
||||
slapi_filter_free(e->slapi_filter, 1);
|
||||
slapi_ch_free_string(&e->scope);
|
||||
slapi_ch_free((void **)entry);
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_delete_configEntry(PRCList *entry)
|
||||
{
|
||||
PR_REMOVE_LINK(entry);
|
||||
ipamodrdn_free_config_entry((struct configEntry **) &entry);
|
||||
}
|
||||
|
||||
static void
|
||||
ipamodrdn_delete_config(void)
|
||||
{
|
||||
PRCList *list;
|
||||
|
||||
while (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
ipamodrdn_delete_configEntry(list);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
Helpers
|
||||
****************************************************/
|
||||
|
||||
static char *ipamodrdn_get_dn(Slapi_PBlock * pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if (slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn)) {
|
||||
LOG_FATAL("failed to get dn of changed entry");
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
/* config check
|
||||
matching config dn or a descendent reloads config
|
||||
*/
|
||||
static int ipamodrdn_dn_is_config(char *dn)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if (slapi_dn_issuffix(dn, getPluginDN())) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************
|
||||
Functions that actually do things other
|
||||
than config and startup
|
||||
****************************************************/
|
||||
|
||||
static int
|
||||
ipamodrdn_change_attr(struct configEntry *cfgentry,
|
||||
char *targetdn, const char *value)
|
||||
{
|
||||
Slapi_PBlock *mod_pb = slapi_pblock_new();
|
||||
LDAPMod mod;
|
||||
LDAPMod *mods[2];
|
||||
char *val[2] = { NULL };
|
||||
int ret;
|
||||
|
||||
val[0] = slapi_ch_smprintf("%s%s%s",
|
||||
cfgentry->prefix, value, cfgentry->suffix);
|
||||
if (!val[0]) {
|
||||
LOG_OOM();
|
||||
ret = EFAIL;
|
||||
goto done;
|
||||
}
|
||||
val[1] = 0;
|
||||
|
||||
mod.mod_op = LDAP_MOD_REPLACE;
|
||||
mod.mod_type = cfgentry->tattr;
|
||||
mod.mod_values = val;
|
||||
|
||||
mods[0] = &mod;
|
||||
mods[1] = 0;
|
||||
|
||||
LOG("Setting %s to %s in entry (%s)\n", cfgentry->tattr, value, targetdn);
|
||||
|
||||
/* Perform the modify operation. */
|
||||
slapi_modify_internal_set_pb(mod_pb, targetdn, mods,
|
||||
0, 0, getPluginID(), 0);
|
||||
slapi_modify_internal_pb(mod_pb);
|
||||
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
LOG_FATAL("Failed to change attribute with error %d\n", ret);
|
||||
ret = EFAIL;
|
||||
}
|
||||
ret = EOK;
|
||||
|
||||
done:
|
||||
if (val[0]) slapi_ch_free_string(&(val[0]));
|
||||
slapi_pblock_destroy(mod_pb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* for mods and adds:
|
||||
where dn's are supplied, the closest in scope
|
||||
is used as long as the type filter matches
|
||||
and the attr value has not been generated yet.
|
||||
*/
|
||||
|
||||
static int ipamodrdn_post_op(Slapi_PBlock *pb)
|
||||
{
|
||||
char *dn = NULL;
|
||||
PRCList *list = NULL;
|
||||
struct configEntry *cfgentry = NULL;
|
||||
struct slapi_entry *e = NULL;
|
||||
Slapi_Attr *sattr = NULL;
|
||||
Slapi_Attr *tattr = NULL;
|
||||
int ret = LDAP_SUCCESS;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
/* Just bail if we aren't ready to service requests yet. */
|
||||
if (!g_plugin_started) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
|
||||
if (NULL == e) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
dn = slapi_entry_get_ndn(e);
|
||||
if (NULL == dn) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ipamodrdn_read_lock();
|
||||
|
||||
if (!PR_CLIST_IS_EMPTY(ipamodrdn_global_config)) {
|
||||
list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
|
||||
for(list = PR_LIST_HEAD(ipamodrdn_global_config);
|
||||
list != ipamodrdn_global_config;
|
||||
list = PR_NEXT_LINK(list)) {
|
||||
cfgentry = (struct configEntry *) list;
|
||||
|
||||
/* is the entry in scope? */
|
||||
if (cfgentry->scope) {
|
||||
if (!slapi_dn_issuffix(dn, cfgentry->scope)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* does the entry match the filter? */
|
||||
if (cfgentry->slapi_filter) {
|
||||
ret = slapi_vattr_filter_test(pb, e,
|
||||
cfgentry->slapi_filter, 0);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (slapi_entry_attr_find(e, cfgentry->sattr, &sattr) != 0) {
|
||||
LOG_TRACE("Source attr %s not found for %s\n",
|
||||
cfgentry->sattr, dn);
|
||||
continue;
|
||||
}
|
||||
if (slapi_entry_attr_find(e, cfgentry->tattr, &tattr) != 0) {
|
||||
LOG_TRACE("Target attr %s not found for %s\n",
|
||||
cfgentry->tattr, dn);
|
||||
} else {
|
||||
Slapi_Value *val;
|
||||
const char *strval;
|
||||
|
||||
ret = slapi_attr_first_value(sattr, &val);
|
||||
if (ret == -1 || !val) {
|
||||
LOG_FATAL("Source attr %s is empty\n", cfgentry->sattr);
|
||||
continue;
|
||||
}
|
||||
strval = slapi_value_get_string(val);
|
||||
|
||||
ret = ipamodrdn_change_attr(cfgentry, dn, strval);
|
||||
if (ret != EOK) {
|
||||
LOG_FATAL("Failed to set target attr %s for %s\n",
|
||||
cfgentry->tattr, dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ipamodrdn_unlock();
|
||||
|
||||
ret = LDAP_SUCCESS;
|
||||
|
||||
done:
|
||||
if (ret) {
|
||||
LOG("operation failure [%d]\n", ret);
|
||||
ret = EFAIL;
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ipamodrdn_config_check_post_op(Slapi_PBlock * pb)
|
||||
{
|
||||
char *dn;
|
||||
|
||||
LOG_TRACE("--in-->\n");
|
||||
|
||||
if ((dn = ipamodrdn_get_dn(pb))) {
|
||||
if (ipamodrdn_dn_is_config(dn)) {
|
||||
ipamodrdn_load_plugin_config();
|
||||
}
|
||||
}
|
||||
|
||||
LOG_TRACE("<--out--\n");
|
||||
|
||||
return 0;
|
||||
}
|
16
daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
Normal file
16
daemons/ipa-slapi-plugins/ipa-modrdn/modrdn-conf.ldif
Normal file
@ -0,0 +1,16 @@
|
||||
dn: cn=IPA MODRDN,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: IPA MODRDN
|
||||
nsslapd-pluginpath: libipa_modrdn
|
||||
nsslapd-plugininitfunc: ipamodrdn_init
|
||||
nsslapd-plugintype: postoperation
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipamodrdn_version
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat, Inc.
|
||||
nsslapd-plugindescription: IPA MODRDN plugin
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
nsslapd-pluginPrecedence: 60
|
57
daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
Normal file
57
daemons/ipa-slapi-plugins/ipa-pwd-extop/Makefile.am
Normal file
@ -0,0 +1,57 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
KRB5_UTIL_DIR= ../../../util
|
||||
KRB5_UTIL_SRCS=$(KRB5_UTIL_DIR)/ipa_krb5.c
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-I$(KRB5_UTIL_DIR) \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(KRB5_CFLAGS) \
|
||||
$(SSL_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_pwd_extop.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_pwd_extop_la_SOURCES = \
|
||||
ipapwd_common.c \
|
||||
ipapwd_encoding.c \
|
||||
ipapwd_prepost.c \
|
||||
ipa_pwd_extop.c \
|
||||
$(KRB5_UTIL_SRCS) \
|
||||
$(NULL)
|
||||
|
||||
libipa_pwd_extop_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_pwd_extop_la_LIBADD = \
|
||||
$(KRB5_LIBS) \
|
||||
$(SSL_LIBS) \
|
||||
$(LDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
pwd-extop-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
0
daemons/ipa-slapi-plugins/ipa-pwd-extop/README
Normal file
0
daemons/ipa-slapi-plugins/ipa-pwd-extop/README
Normal file
1305
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
Normal file
1305
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
Normal file
File diff suppressed because it is too large
Load Diff
170
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
Normal file
170
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd.h
Normal file
@ -0,0 +1,170 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Authors:
|
||||
* Simo Sorce <ssorce@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2007-2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <prio.h>
|
||||
#include <ssl.h>
|
||||
#include <dirsrv/slapi-plugin.h>
|
||||
#include <krb5.h>
|
||||
#include <lber.h>
|
||||
#include <time.h>
|
||||
#include <iconv.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
|
||||
#define IPAPWD_PLUGIN_NAME "ipa-pwd-extop"
|
||||
#define IPAPWD_FEATURE_DESC "IPA Password Manager"
|
||||
#define IPAPWD_PLUGIN_DESC "IPA Password Extended Operation plugin"
|
||||
|
||||
#define IPA_PLUGIN_NAME IPAPWD_PLUGIN_NAME
|
||||
|
||||
#define IPAPWD_CHECK_CONN_SECURE 0x00000001
|
||||
#define IPAPWD_CHECK_DN 0x00000002
|
||||
|
||||
#define IPA_CHANGETYPE_NORMAL 0
|
||||
#define IPA_CHANGETYPE_ADMIN 1
|
||||
#define IPA_CHANGETYPE_DSMGR 2
|
||||
|
||||
struct ipapwd_data {
|
||||
Slapi_Entry *target;
|
||||
char *dn;
|
||||
char *password;
|
||||
time_t timeNow;
|
||||
time_t lastPwChange;
|
||||
time_t expireTime;
|
||||
int changetype;
|
||||
int pwHistoryLen;
|
||||
};
|
||||
|
||||
struct ipapwd_operation {
|
||||
struct ipapwd_data pwdata;
|
||||
int pwd_op;
|
||||
int is_krb;
|
||||
};
|
||||
|
||||
#define GENERALIZED_TIME_LENGTH 15
|
||||
|
||||
#define IPAPWD_POLICY_MASK 0x0FF
|
||||
#define IPAPWD_POLICY_ERROR 0x100
|
||||
#define IPAPWD_POLICY_OK 0
|
||||
|
||||
|
||||
/* from ipapwd_common.c */
|
||||
struct ipapwd_encsalt {
|
||||
krb5_int32 enc_type;
|
||||
krb5_int32 salt_type;
|
||||
};
|
||||
|
||||
struct ipapwd_krbcfg {
|
||||
krb5_context krbctx;
|
||||
char *realm;
|
||||
krb5_keyblock *kmkey;
|
||||
int num_supp_encsalts;
|
||||
struct ipapwd_encsalt *supp_encsalts;
|
||||
int num_pref_encsalts;
|
||||
struct ipapwd_encsalt *pref_encsalts;
|
||||
char **passsync_mgrs;
|
||||
int num_passsync_mgrs;
|
||||
bool allow_lm_hash;
|
||||
bool allow_nt_hash;
|
||||
};
|
||||
|
||||
int ipapwd_entry_checks(Slapi_PBlock *pb, struct slapi_entry *e,
|
||||
int *is_root, int *is_krb, int *is_smb,
|
||||
char *attr, int access);
|
||||
int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg,
|
||||
struct ipapwd_krbcfg **config, int check_flags);
|
||||
int ipapwd_CheckPolicy(struct ipapwd_data *data);
|
||||
int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist);
|
||||
int ipapwd_get_cur_kvno(Slapi_Entry *target);
|
||||
int ipapwd_SetPassword(struct ipapwd_krbcfg *krbcfg,
|
||||
struct ipapwd_data *data, int is_krb);
|
||||
Slapi_Value **ipapwd_setPasswordHistory(Slapi_Mods *smods,
|
||||
struct ipapwd_data *data);
|
||||
int ipapwd_apply_mods(const char *dn, Slapi_Mods *mods);
|
||||
int ipapwd_set_extradata(const char *dn,
|
||||
const char *principal,
|
||||
time_t unixtime);
|
||||
void ipapwd_free_slapi_value_array(Slapi_Value ***svals);
|
||||
void free_ipapwd_krbcfg(struct ipapwd_krbcfg **cfg);
|
||||
|
||||
/* from ipapwd_encoding.c */
|
||||
struct ipapwd_krbkeydata {
|
||||
int32_t type;
|
||||
struct berval value;
|
||||
};
|
||||
struct ipapwd_krbkey {
|
||||
struct ipapwd_krbkeydata *salt;
|
||||
struct ipapwd_krbkeydata *ekey;
|
||||
struct berval s2kparams;
|
||||
};
|
||||
struct ipapwd_keyset {
|
||||
uint16_t major_vno;
|
||||
uint16_t minor_vno;
|
||||
uint32_t kvno;
|
||||
uint32_t mkvno;
|
||||
struct ipapwd_krbkey *keys;
|
||||
int num_keys;
|
||||
};
|
||||
|
||||
void encode_int16(unsigned int val, unsigned char *p);
|
||||
struct berval *encode_keys(struct ipapwd_keyset *kset);
|
||||
void ipapwd_keyset_free(struct ipapwd_keyset **pkset);
|
||||
|
||||
int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
|
||||
struct ipapwd_data *data, char *userpw,
|
||||
int is_krb, int is_smb, Slapi_Value ***svals,
|
||||
char **nthash, char **lmhash, char **errMesg);
|
||||
|
||||
/* from ipapwd_prepost.c */
|
||||
int ipapwd_ext_init(void);
|
||||
int ipapwd_pre_init(Slapi_PBlock *pb);
|
||||
int ipapwd_post_init(Slapi_PBlock *pb);
|
||||
|
1488
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
Normal file
1488
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_common.c
Normal file
File diff suppressed because it is too large
Load Diff
796
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
Normal file
796
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c
Normal file
@ -0,0 +1,796 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Authors:
|
||||
* Simo Sorce <ssorce@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2007-2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <dirsrv/slapi-plugin.h>
|
||||
#include <lber.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ipapwd.h"
|
||||
#include "util.h"
|
||||
#include "ipa_krb5.h"
|
||||
|
||||
/* krbTicketFlags */
|
||||
#define KTF_DISALLOW_POSTDATED 0x00000001
|
||||
#define KTF_DISALLOW_FORWARDABLE 0x00000002
|
||||
#define KTF_DISALLOW_TGT_BASED 0x00000004
|
||||
#define KTF_DISALLOW_RENEWABLE 0x00000008
|
||||
#define KTF_DISALLOW_PROXIABLE 0x00000010
|
||||
#define KTF_DISALLOW_DUP_SKEY 0x00000020
|
||||
#define KTF_DISALLOW_ALL_TIX 0x00000040
|
||||
#define KTF_REQUIRES_PRE_AUTH 0x00000080
|
||||
#define KTF_REQUIRES_HW_AUTH 0x00000100
|
||||
#define KTF_REQUIRES_PWCHANGE 0x00000200
|
||||
#define KTF_DISALLOW_SVR 0x00001000
|
||||
#define KTF_PWCHANGE_SERVICE 0x00002000
|
||||
|
||||
/* Salt types */
|
||||
#define KRB5_KDB_SALTTYPE_NORMAL 0
|
||||
#define KRB5_KDB_SALTTYPE_V4 1
|
||||
#define KRB5_KDB_SALTTYPE_NOREALM 2
|
||||
#define KRB5_KDB_SALTTYPE_ONLYREALM 3
|
||||
#define KRB5_KDB_SALTTYPE_SPECIAL 4
|
||||
#define KRB5_KDB_SALTTYPE_AFS3 5
|
||||
#define KRB5P_SALT_SIZE 16
|
||||
|
||||
void krb5int_c_free_keyblock_contents(krb5_context context,
|
||||
register krb5_keyblock *key);
|
||||
|
||||
/* Novell key-format scheme:
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/* ascii hex output of bytes in "in"
|
||||
* out len is 32 (preallocated)
|
||||
* in len is 16 */
|
||||
static const char hexchars[] = "0123456789ABCDEF";
|
||||
static void hexbuf(char *out, const uint8_t *in)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
out[i*2] = hexchars[in[i] >> 4];
|
||||
out[i*2+1] = hexchars[in[i] & 0x0f];
|
||||
}
|
||||
}
|
||||
|
||||
struct berval *encode_keys(struct ipapwd_keyset *kset)
|
||||
{
|
||||
BerElement *be = NULL;
|
||||
struct berval *bval = NULL;
|
||||
int ret, i;
|
||||
|
||||
be = ber_alloc_t(LBER_USE_DER);
|
||||
|
||||
if (!be) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = ber_printf(be, "{t[i]t[i]t[i]t[i]t[{",
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||
kset->major_vno,
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||
kset->minor_vno,
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2),
|
||||
kset->kvno,
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 3),
|
||||
kset->mkvno,
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 4));
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("encoding asn1 vno info failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (i = 0; i < kset->num_keys; i++) {
|
||||
|
||||
ret = ber_printf(be, "{");
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("encoding asn1 EncryptionKey failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (kset->keys[i].salt) {
|
||||
ret = ber_printf(be, "t[{t[i]",
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||
kset->keys[i].salt->type);
|
||||
if ((ret != -1) && kset->keys[i].salt->value.bv_len) {
|
||||
ret = ber_printf(be, "t[o]",
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||
kset->keys[i].salt->value.bv_val,
|
||||
kset->keys[i].salt->value.bv_len);
|
||||
}
|
||||
if (ret != -1) {
|
||||
ret = ber_printf(be, "}]");
|
||||
}
|
||||
if (ret == -1) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ber_printf(be, "t[{t[i]t[o]}]",
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||
kset->keys[i].ekey->type,
|
||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||
kset->keys[i].ekey->value.bv_val,
|
||||
kset->keys[i].ekey->value.bv_len);
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("encoding asn1 EncryptionKey failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* FIXME: s2kparams not supported yet */
|
||||
|
||||
ret = ber_printf(be, "}");
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("encoding asn1 EncryptionKey failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ber_printf(be, "}]}");
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("encoding asn1 end of sequences failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = ber_flatten(be, &bval);
|
||||
if (ret == -1) {
|
||||
LOG_FATAL("flattening asn1 failed\n");
|
||||
goto done;
|
||||
}
|
||||
done:
|
||||
ber_free(be, 1);
|
||||
|
||||
return bval;
|
||||
}
|
||||
|
||||
void ipapwd_keyset_free(struct ipapwd_keyset **pkset)
|
||||
{
|
||||
struct ipapwd_keyset *kset = *pkset;
|
||||
int i;
|
||||
|
||||
if (!kset) return;
|
||||
|
||||
for (i = 0; i < kset->num_keys; i++) {
|
||||
if (kset->keys[i].salt) {
|
||||
free(kset->keys[i].salt->value.bv_val);
|
||||
free(kset->keys[i].salt);
|
||||
}
|
||||
if (kset->keys[i].ekey) {
|
||||
free(kset->keys[i].ekey->value.bv_val);
|
||||
free(kset->keys[i].ekey);
|
||||
}
|
||||
free(kset->keys[i].s2kparams.bv_val);
|
||||
}
|
||||
free(kset->keys);
|
||||
free(kset);
|
||||
*pkset = NULL;
|
||||
}
|
||||
|
||||
|
||||
void encode_int16(unsigned int val, unsigned char *p)
|
||||
{
|
||||
p[1] = (val >> 8) & 0xff;
|
||||
p[0] = (val ) & 0xff;
|
||||
}
|
||||
|
||||
static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg,
|
||||
struct ipapwd_data *data,
|
||||
char **errMesg)
|
||||
{
|
||||
krb5_context krbctx;
|
||||
char *krbPrincipalName = NULL;
|
||||
uint32_t krbMaxTicketLife;
|
||||
int kvno, i;
|
||||
int krbTicketFlags;
|
||||
struct berval *bval = NULL;
|
||||
Slapi_Value **svals = NULL;
|
||||
krb5_principal princ = NULL;
|
||||
krb5_error_code krberr;
|
||||
krb5_data pwd;
|
||||
struct ipapwd_keyset *kset = NULL;
|
||||
|
||||
krbctx = krbcfg->krbctx;
|
||||
|
||||
svals = (Slapi_Value **)calloc(2, sizeof(Slapi_Value *));
|
||||
if (!svals) {
|
||||
LOG_OOM();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
kvno = ipapwd_get_cur_kvno(data->target);
|
||||
|
||||
krbPrincipalName = slapi_entry_attr_get_charptr(data->target,
|
||||
"krbPrincipalName");
|
||||
if (!krbPrincipalName) {
|
||||
*errMesg = "no krbPrincipalName present in this entry\n";
|
||||
LOG_FATAL("%s", *errMesg);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
krberr = krb5_parse_name(krbctx, krbPrincipalName, &princ);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_parse_name failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
krbMaxTicketLife = slapi_entry_attr_get_uint(data->target,
|
||||
"krbMaxTicketLife");
|
||||
if (krbMaxTicketLife == 0) {
|
||||
/* FIXME: retrieve the default from config (max_life from kdc.conf) */
|
||||
krbMaxTicketLife = 86400; /* just set the default 24h for now */
|
||||
}
|
||||
|
||||
krbTicketFlags = slapi_entry_attr_get_int(data->target,
|
||||
"krbTicketFlags");
|
||||
|
||||
pwd.data = (char *)data->password;
|
||||
pwd.length = strlen(data->password);
|
||||
|
||||
kset = malloc(sizeof(struct ipapwd_keyset));
|
||||
if (!kset) {
|
||||
LOG_OOM();
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
/* this encoding assumes all keys have the same kvno */
|
||||
/* major-vno = 1 and minor-vno = 1 */
|
||||
kset->major_vno = 1;
|
||||
kset->minor_vno = 1;
|
||||
/* increment kvno (will be 1 if this is a new entry) */
|
||||
kset->kvno = kvno + 1;
|
||||
/* we also assum mkvno is 0 */
|
||||
kset->mkvno = 0;
|
||||
|
||||
kset->num_keys = krbcfg->num_pref_encsalts;
|
||||
kset->keys = calloc(kset->num_keys, sizeof(struct ipapwd_krbkey));
|
||||
if (!kset->keys) {
|
||||
LOG_OOM();
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < kset->num_keys; i++) {
|
||||
krb5_keyblock key;
|
||||
krb5_data salt;
|
||||
krb5_octet *ptr;
|
||||
krb5_data plain;
|
||||
krb5_enc_data cipher;
|
||||
size_t len;
|
||||
const char *p;
|
||||
|
||||
salt.data = NULL;
|
||||
|
||||
switch (krbcfg->pref_encsalts[i].salt_type) {
|
||||
|
||||
case KRB5_KDB_SALTTYPE_ONLYREALM:
|
||||
|
||||
p = strchr(krbPrincipalName, '@');
|
||||
if (!p) {
|
||||
LOG_FATAL("Invalid principal name, no realm found!\n");
|
||||
goto enc_error;
|
||||
}
|
||||
p++;
|
||||
salt.data = strdup(p);
|
||||
if (!salt.data) {
|
||||
LOG_OOM();
|
||||
goto enc_error;
|
||||
}
|
||||
salt.length = strlen(salt.data); /* final \0 omitted on purpose */
|
||||
break;
|
||||
|
||||
case KRB5_KDB_SALTTYPE_NOREALM:
|
||||
|
||||
krberr = ipa_krb5_principal2salt_norealm(krbctx, princ, &salt);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_principal2salt failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
goto enc_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case KRB5_KDB_SALTTYPE_NORMAL:
|
||||
|
||||
krberr = krb5_principal2salt(krbctx, princ, &salt);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_principal2salt failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
goto enc_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case KRB5_KDB_SALTTYPE_SPECIAL:
|
||||
|
||||
/* make random salt */
|
||||
salt.length = KRB5P_SALT_SIZE;
|
||||
salt.data = malloc(KRB5P_SALT_SIZE);
|
||||
if (!salt.data) {
|
||||
LOG_OOM();
|
||||
goto enc_error;
|
||||
}
|
||||
krberr = krb5_c_random_make_octets(krbctx, &salt);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_c_random_make_octets failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
goto enc_error;
|
||||
}
|
||||
break;
|
||||
|
||||
case KRB5_KDB_SALTTYPE_V4:
|
||||
salt.length = 0;
|
||||
break;
|
||||
|
||||
case KRB5_KDB_SALTTYPE_AFS3:
|
||||
|
||||
p = strchr(krbPrincipalName, '@');
|
||||
if (!p) {
|
||||
LOG_FATAL("Invalid principal name, no realm found!\n");
|
||||
goto enc_error;
|
||||
}
|
||||
p++;
|
||||
salt.data = strdup(p);
|
||||
if (!salt.data) {
|
||||
LOG_OOM();
|
||||
goto enc_error;
|
||||
}
|
||||
salt.length = SALT_TYPE_AFS_LENGTH; /* special value */
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Invalid salt type [%d]\n",
|
||||
krbcfg->pref_encsalts[i].salt_type);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
/* need to build the key now to manage the AFS salt.length
|
||||
* special case */
|
||||
krberr = krb5_c_string_to_key(krbctx,
|
||||
krbcfg->pref_encsalts[i].enc_type,
|
||||
&pwd, &salt, &key);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_c_string_to_key failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
krb5_free_data_contents(krbctx, &salt);
|
||||
goto enc_error;
|
||||
}
|
||||
if (salt.length == SALT_TYPE_AFS_LENGTH) {
|
||||
salt.length = strlen(salt.data);
|
||||
}
|
||||
|
||||
krberr = krb5_c_encrypt_length(krbctx,
|
||||
krbcfg->kmkey->enctype,
|
||||
key.length, &len);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_c_string_to_key failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
krb5_free_data_contents(krbctx, &salt);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL) {
|
||||
LOG_OOM();
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
krb5_free_data_contents(krbctx, &salt);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
encode_int16(key.length, ptr);
|
||||
|
||||
plain.length = key.length;
|
||||
plain.data = (char *)key.contents;
|
||||
|
||||
cipher.ciphertext.length = len;
|
||||
cipher.ciphertext.data = (char *)ptr+2;
|
||||
|
||||
krberr = krb5_c_encrypt(krbctx, krbcfg->kmkey, 0, 0, &plain, &cipher);
|
||||
if (krberr) {
|
||||
LOG_FATAL("krb5_c_encrypt failed [%s]\n",
|
||||
krb5_get_error_message(krbctx, krberr));
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
krb5_free_data_contents(krbctx, &salt);
|
||||
free(ptr);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
/* KrbSalt */
|
||||
kset->keys[i].salt = malloc(sizeof(struct ipapwd_krbkeydata));
|
||||
if (!kset->keys[i].salt) {
|
||||
LOG_OOM();
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
free(ptr);
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
kset->keys[i].salt->type = krbcfg->pref_encsalts[i].salt_type;
|
||||
|
||||
if (salt.length) {
|
||||
kset->keys[i].salt->value.bv_len = salt.length;
|
||||
kset->keys[i].salt->value.bv_val = salt.data;
|
||||
}
|
||||
|
||||
/* EncryptionKey */
|
||||
kset->keys[i].ekey = malloc(sizeof(struct ipapwd_krbkeydata));
|
||||
if (!kset->keys[i].ekey) {
|
||||
LOG_OOM();
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
free(ptr);
|
||||
goto enc_error;
|
||||
}
|
||||
kset->keys[i].ekey->type = key.enctype;
|
||||
kset->keys[i].ekey->value.bv_len = len+2;
|
||||
kset->keys[i].ekey->value.bv_val = malloc(len+2);
|
||||
if (!kset->keys[i].ekey->value.bv_val) {
|
||||
LOG_OOM();
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
free(ptr);
|
||||
goto enc_error;
|
||||
}
|
||||
memcpy(kset->keys[i].ekey->value.bv_val, ptr, len+2);
|
||||
|
||||
/* make sure we free the memory used now that we are done with it */
|
||||
krb5int_c_free_keyblock_contents(krbctx, &key);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
bval = encode_keys(kset);
|
||||
if (!bval) {
|
||||
LOG_FATAL("encoding asn1 KrbSalt failed\n");
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
svals[0] = slapi_value_new_berval(bval);
|
||||
if (!svals[0]) {
|
||||
LOG_FATAL("Converting berval to Slapi_Value\n");
|
||||
goto enc_error;
|
||||
}
|
||||
|
||||
ipapwd_keyset_free(&kset);
|
||||
krb5_free_principal(krbctx, princ);
|
||||
slapi_ch_free_string(&krbPrincipalName);
|
||||
ber_bvfree(bval);
|
||||
return svals;
|
||||
|
||||
enc_error:
|
||||
*errMesg = "key encryption/encoding failed\n";
|
||||
if (kset) ipapwd_keyset_free(&kset);
|
||||
krb5_free_principal(krbctx, princ);
|
||||
slapi_ch_free_string(&krbPrincipalName);
|
||||
if (bval) ber_bvfree(bval);
|
||||
free(svals);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define KTF_DOS_CHARSET "CP850" /* same default as samba */
|
||||
#define KTF_UTF8 "UTF-8"
|
||||
#define KTF_UCS2 "UCS-2LE"
|
||||
|
||||
static const uint8_t parity_table[128] = {
|
||||
1, 2, 4, 7, 8, 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31,
|
||||
32, 35, 37, 38, 41, 42, 44, 47, 49, 50, 52, 55, 56, 59, 61, 62,
|
||||
64, 67, 69, 70, 73, 74, 76, 79, 81, 82, 84, 87, 88, 91, 93, 94,
|
||||
97, 98,100,103,104,107,109,110,112,115,117,118,121,122,124,127,
|
||||
128,131,133,134,137,138,140,143,145,146,148,151,152,155,157,158,
|
||||
161,162,164,167,168,171,173,174,176,179,181,182,185,186,188,191,
|
||||
193,194,196,199,200,203,205,206,208,211,213,214,217,218,220,223,
|
||||
224,227,229,230,233,234,236,239,241,242,244,247,248,251,253,254
|
||||
};
|
||||
|
||||
static void lm_shuffle(uint8_t *out, uint8_t *in)
|
||||
{
|
||||
out[0] = parity_table[in[0]>>1];
|
||||
out[1] = parity_table[((in[0]<<6)|(in[1]>>2)) & 0x7F];
|
||||
out[2] = parity_table[((in[1]<<5)|(in[2]>>3)) & 0x7F];
|
||||
out[3] = parity_table[((in[2]<<4)|(in[3]>>4)) & 0x7F];
|
||||
out[4] = parity_table[((in[3]<<3)|(in[4]>>5)) & 0x7F];
|
||||
out[5] = parity_table[((in[4]<<2)|(in[5]>>6)) & 0x7F];
|
||||
out[6] = parity_table[((in[5]<<1)|(in[6]>>7)) & 0x7F];
|
||||
out[7] = parity_table[in[6] & 0x7F];
|
||||
}
|
||||
|
||||
struct ntlm_keys {
|
||||
uint8_t lm[16];
|
||||
uint8_t nt[16];
|
||||
};
|
||||
|
||||
/* create the lm and nt hashes
|
||||
newPassword: the clear text utf8 password
|
||||
do_lm_hash: determine if LM hash is generated
|
||||
do_nt_hash: determine if NT hash is generated
|
||||
keys[out]: array with generated hashes
|
||||
*/
|
||||
static int encode_ntlm_keys(char *newPasswd,
|
||||
bool do_lm_hash,
|
||||
bool do_nt_hash,
|
||||
struct ntlm_keys *keys)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* do lanman first */
|
||||
if (do_lm_hash) {
|
||||
iconv_t cd;
|
||||
size_t cs, il, ol;
|
||||
char *inc, *outc;
|
||||
char *upperPasswd;
|
||||
char *asciiPasswd;
|
||||
DES_key_schedule schedule;
|
||||
DES_cblock deskey;
|
||||
DES_cblock magic = "KGS!@#$%";
|
||||
|
||||
/* TODO: must store the dos charset somewhere in the directory */
|
||||
cd = iconv_open(KTF_DOS_CHARSET, KTF_UTF8);
|
||||
if (cd == (iconv_t)(-1)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* the lanman password is upper case */
|
||||
upperPasswd = (char *)slapi_utf8StrToUpper((unsigned char *)newPasswd);
|
||||
if (!upperPasswd) {
|
||||
iconv_close(cd);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
il = strlen(upperPasswd);
|
||||
|
||||
/* an ascii string can only be smaller than or equal to an utf8 one */
|
||||
ol = il;
|
||||
if (ol < 14) ol = 14;
|
||||
asciiPasswd = calloc(ol+1, 1);
|
||||
if (!asciiPasswd) {
|
||||
slapi_ch_free_string(&upperPasswd);
|
||||
iconv_close(cd);
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
inc = upperPasswd;
|
||||
outc = asciiPasswd;
|
||||
cs = iconv(cd, &inc, &il, &outc, &ol);
|
||||
if (cs == -1) {
|
||||
ret = -1;
|
||||
slapi_ch_free_string(&upperPasswd);
|
||||
free(asciiPasswd);
|
||||
iconv_close(cd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* done with these */
|
||||
slapi_ch_free_string(&upperPasswd);
|
||||
iconv_close(cd);
|
||||
|
||||
/* we are interested only in the first 14 ASCII chars for lanman */
|
||||
if (strlen(asciiPasswd) > 14) {
|
||||
asciiPasswd[14] = '\0';
|
||||
}
|
||||
|
||||
/* first half */
|
||||
lm_shuffle(deskey, (uint8_t *)asciiPasswd);
|
||||
|
||||
DES_set_key_unchecked(&deskey, &schedule);
|
||||
DES_ecb_encrypt(&magic, (DES_cblock *)keys->lm,
|
||||
&schedule, DES_ENCRYPT);
|
||||
|
||||
/* second half */
|
||||
lm_shuffle(deskey, (uint8_t *)&asciiPasswd[7]);
|
||||
|
||||
DES_set_key_unchecked(&deskey, &schedule);
|
||||
DES_ecb_encrypt(&magic, (DES_cblock *)&(keys->lm[8]),
|
||||
&schedule, DES_ENCRYPT);
|
||||
|
||||
/* done with it */
|
||||
free(asciiPasswd);
|
||||
|
||||
} else {
|
||||
memset(keys->lm, 0, 16);
|
||||
}
|
||||
|
||||
if (do_nt_hash) {
|
||||
iconv_t cd;
|
||||
size_t cs, il, ol, sl;
|
||||
char *inc, *outc;
|
||||
char *ucs2Passwd;
|
||||
MD4_CTX md4ctx;
|
||||
|
||||
/* TODO: must store the dos charset somewhere in the directory */
|
||||
cd = iconv_open(KTF_UCS2, KTF_UTF8);
|
||||
if (cd == (iconv_t)(-1)) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
il = strlen(newPasswd);
|
||||
|
||||
/* an ucs2 string can be at most double than an utf8 one */
|
||||
sl = ol = (il+1)*2;
|
||||
ucs2Passwd = calloc(ol, 1);
|
||||
if (!ucs2Passwd) {
|
||||
ret = -1;
|
||||
iconv_close(cd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
inc = newPasswd;
|
||||
outc = ucs2Passwd;
|
||||
cs = iconv(cd, &inc, &il, &outc, &ol);
|
||||
if (cs == -1) {
|
||||
ret = -1;
|
||||
free(ucs2Passwd);
|
||||
iconv_close(cd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* done with it */
|
||||
iconv_close(cd);
|
||||
|
||||
/* get the final ucs2 string length */
|
||||
sl -= ol;
|
||||
|
||||
ret = MD4_Init(&md4ctx);
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
free(ucs2Passwd);
|
||||
goto done;
|
||||
}
|
||||
ret = MD4_Update(&md4ctx, ucs2Passwd, sl);
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
free(ucs2Passwd);
|
||||
goto done;
|
||||
}
|
||||
ret = MD4_Final(keys->nt, &md4ctx);
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
free(ucs2Passwd);
|
||||
goto done;
|
||||
}
|
||||
|
||||
} else {
|
||||
memset(keys->nt, 0, 16);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ipapwd_gen_hashes(struct ipapwd_krbcfg *krbcfg,
|
||||
struct ipapwd_data *data, char *userpw,
|
||||
int is_krb, int is_smb, Slapi_Value ***svals,
|
||||
char **nthash, char **lmhash, char **errMesg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
*svals = NULL;
|
||||
*nthash = NULL;
|
||||
*lmhash = NULL;
|
||||
*errMesg = NULL;
|
||||
|
||||
if (is_krb) {
|
||||
|
||||
*svals = encrypt_encode_key(krbcfg, data, errMesg);
|
||||
|
||||
if (!*svals) {
|
||||
/* errMesg should have been set in encrypt_encode_key() */
|
||||
LOG_FATAL("key encryption/encoding failed\n");
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_smb) {
|
||||
char lm[33], nt[33];
|
||||
struct ntlm_keys ntlm;
|
||||
int ret;
|
||||
|
||||
ret = encode_ntlm_keys(userpw,
|
||||
krbcfg->allow_lm_hash,
|
||||
krbcfg->allow_nt_hash,
|
||||
&ntlm);
|
||||
if (ret) {
|
||||
*errMesg = "Failed to generate NT/LM hashes\n";
|
||||
LOG_FATAL("%s", *errMesg);
|
||||
rc = LDAP_OPERATIONS_ERROR;
|
||||
goto done;
|
||||
}
|
||||
if (krbcfg->allow_lm_hash) {
|
||||
hexbuf(lm, ntlm.lm);
|
||||
lm[32] = '\0';
|
||||
*lmhash = slapi_ch_strdup(lm);
|
||||
}
|
||||
if (krbcfg->allow_nt_hash) {
|
||||
hexbuf(nt, ntlm.nt);
|
||||
nt[32] = '\0';
|
||||
*nthash = slapi_ch_strdup(nt);
|
||||
}
|
||||
}
|
||||
|
||||
rc = LDAP_SUCCESS;
|
||||
|
||||
done:
|
||||
|
||||
/* when error, free possibly allocated output parameters */
|
||||
if (rc) {
|
||||
ipapwd_free_slapi_value_array(svals);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
1110
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
Normal file
1110
daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_prepost.c
Normal file
File diff suppressed because it is too large
Load Diff
16
daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
Normal file
16
daemons/ipa-slapi-plugins/ipa-pwd-extop/pwd-extop-conf.ldif
Normal file
@ -0,0 +1,16 @@
|
||||
dn: cn=ipa_pwd_extop,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: ipa_pwd_extop
|
||||
nsslapd-pluginpath: libipa_pwd_extop
|
||||
nsslapd-plugininitfunc: ipapwd_init
|
||||
nsslapd-plugintype: extendedop
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipa_pwd_extop
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: RedHat
|
||||
nsslapd-plugindescription: Support saving passwords in multiple formats for different consumers (krb5, samba, freeradius, etc.)
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
nsslapd-realmTree: $SUFFIX
|
47
daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am
Normal file
47
daemons/ipa-slapi-plugins/ipa-uuid/Makefile.am
Normal file
@ -0,0 +1,47 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-I/usr/include/dirsrv \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_uuid.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_uuid_la_SOURCES = \
|
||||
ipa_uuid.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_uuid_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_uuid_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(UUID_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
uuid-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
1227
daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c
Normal file
1227
daemons/ipa-slapi-plugins/ipa-uuid/ipa_uuid.c
Normal file
File diff suppressed because it is too large
Load Diff
15
daemons/ipa-slapi-plugins/ipa-uuid/uuid-conf.ldif
Normal file
15
daemons/ipa-slapi-plugins/ipa-uuid/uuid-conf.ldif
Normal file
@ -0,0 +1,15 @@
|
||||
dn: cn=IPA UUID,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: IPA UUID
|
||||
nsslapd-pluginpath: libipa_uuid
|
||||
nsslapd-plugininitfunc: ipauuid_init
|
||||
nsslapd-plugintype: preoperation
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-pluginid: ipauuid_version
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat, Inc.
|
||||
nsslapd-plugindescription: IPA UUID plugin
|
||||
nsslapd-plugin-depends-on-type: database
|
48
daemons/ipa-slapi-plugins/ipa-version/Makefile.am
Normal file
48
daemons/ipa-slapi-plugins/ipa-version/Makefile.am
Normal file
@ -0,0 +1,48 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I../../ \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-I/usr/include/dirsrv \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(KRB5_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_repl_version.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_repl_version_la_SOURCES = \
|
||||
ipa_repl_version.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_repl_version_la_LDFLAGS = -avoid-version
|
||||
|
||||
libipa_repl_version_la_LIBADD = \
|
||||
$(LDAP_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
version-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
199
daemons/ipa-slapi-plugins/ipa-version/ipa_repl_version.c
Normal file
199
daemons/ipa-slapi-plugins/ipa-version/ipa_repl_version.c
Normal file
@ -0,0 +1,199 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#include "slapi-plugin.h"
|
||||
#include "repl-session-plugin.h"
|
||||
#include "ipa-version.h"
|
||||
#include "util.h"
|
||||
#include <string.h>
|
||||
|
||||
/* Identify the type of data we're sending, an unsigned int in this case */
|
||||
#define REPL_VERSION_DATA_GUID "2D562D8B-2F30-4447-AF76-2B721D1D5F6A"
|
||||
|
||||
#define IPA_PLUGIN_NAME "ipa_replication_version"
|
||||
static char *data_version = NULL;
|
||||
|
||||
/*
|
||||
* Plugin identifiers
|
||||
*/
|
||||
static Slapi_PluginDesc repl_version_pdesc = {
|
||||
"ipa-repl-version-plugin",
|
||||
"Red Hat, Inc.",
|
||||
"1.0",
|
||||
"IPA Replication version plugin"
|
||||
};
|
||||
|
||||
static Slapi_ComponentId *repl_version_plugin_id = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Replication Version Callbacks
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is called on a master when we are about to acquire a
|
||||
* replica.
|
||||
*
|
||||
* Returning non-0 will abort the replication session. This
|
||||
* results in the master going into incremental backoff mode.
|
||||
*/
|
||||
static int
|
||||
repl_version_plugin_pre_acquire_cb(void *cookie, const Slapi_DN *repl_subtree,
|
||||
int is_total, char **data_guid, struct berval **data)
|
||||
{
|
||||
LOG("repl_version_plugin_pre_acquire_cb() called for suffix \"%s\", "
|
||||
"is_total: \"%s\".\n", slapi_sdn_get_ndn(repl_subtree),
|
||||
is_total ? "TRUE" : "FALSE");
|
||||
|
||||
/* allocate some data to be sent to the replica */
|
||||
*data_guid = slapi_ch_smprintf("%s", REPL_VERSION_DATA_GUID);
|
||||
*data = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
|
||||
(*data)->bv_val = slapi_ch_smprintf("%s", data_version);
|
||||
(*data)->bv_len = strlen((*data)->bv_val) + 1;
|
||||
|
||||
LOG("repl_version_plugin_pre_acquire_cb() sending data: guid: \"%s\" data: \"%s\".\n",
|
||||
*data_guid, (*data)->bv_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called on a replica when it receives a start replication
|
||||
* extended operation from a master.
|
||||
*
|
||||
* The data sent by the master (version) is compared with our own
|
||||
* hardcoded version to determine if replication can proceed or not.
|
||||
*
|
||||
* The replication plug-in will take care of freeing data_guid and data.
|
||||
*
|
||||
* Returning non-0 will abort the replication session. This
|
||||
* results in the master going into incremental backoff mode.
|
||||
*/
|
||||
static int
|
||||
repl_version_plugin_recv_acquire_cb(const char *repl_subtree, int is_total,
|
||||
const char *data_guid, const struct berval *data)
|
||||
{
|
||||
LOG("test_repl_session_plugin_recv_acquire_cb() called for suffix \"%s\", is_total: \"%s\".\n",
|
||||
repl_subtree, is_total ? "TRUE" : "FALSE");
|
||||
|
||||
/* compare our data version to the master data version */
|
||||
if (data_guid && data && (strcmp(data_guid, REPL_VERSION_DATA_GUID) == 0)) {
|
||||
LOG("repl_version_plugin_recv_acquire_cb() received data: guid: \"%s\" data: \"%s\".\n",
|
||||
data_guid, data->bv_val);
|
||||
if (!(strcmp(data_version, data->bv_val) == 0)) {
|
||||
LOG_FATAL("Incompatible IPA versions, pausing replication. "
|
||||
"This server: \"%s\" remote server: \"%s\".\n",
|
||||
data_version, data->bv_val);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback list for registering API
|
||||
*/
|
||||
static void *repl_version_api[] = {
|
||||
NULL, /* reserved for api broker use, must be zero */
|
||||
NULL, /* init cb */
|
||||
repl_version_plugin_pre_acquire_cb,
|
||||
NULL, /* reply_acquire_cb */
|
||||
NULL, /* post_acquire_cb */
|
||||
repl_version_plugin_recv_acquire_cb,
|
||||
NULL /* destroy cb */
|
||||
};
|
||||
|
||||
/*
|
||||
* Plug-in framework functions
|
||||
*/
|
||||
static int
|
||||
repl_version_plugin_start(Slapi_PBlock *pb)
|
||||
{
|
||||
LOG("--> repl_version_plugin_start -- begin\n");
|
||||
|
||||
data_version = slapi_ch_smprintf("%llu", (unsigned long long) DATA_VERSION);
|
||||
|
||||
LOG("<-- repl_version_plugin_start -- end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
repl_version_plugin_close(Slapi_PBlock *pb)
|
||||
{
|
||||
LOG("--> repl_version_plugin_close -- begin\n");
|
||||
|
||||
slapi_apib_unregister(REPL_SESSION_v1_0_GUID);
|
||||
|
||||
slapi_ch_free_string(&data_version);
|
||||
|
||||
LOG("<-- repl_version_plugin_close -- end\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int repl_version_plugin_init(Slapi_PBlock *pb)
|
||||
{
|
||||
LOG("--> repl_version_plugin_init -- begin\n");
|
||||
|
||||
if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
|
||||
SLAPI_PLUGIN_VERSION_01 ) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
|
||||
(void *) repl_version_plugin_start ) != 0 ||
|
||||
slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
|
||||
(void *) repl_version_plugin_close ) != 0 ||
|
||||
slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
|
||||
(void *)&repl_version_pdesc ) != 0 )
|
||||
{
|
||||
LOG_FATAL("<-- repl_version_plugin_init -- failed to register plugin -- end\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( slapi_apib_register(REPL_SESSION_v1_0_GUID, repl_version_api) ) {
|
||||
LOG_FATAL("<-- repl_version_plugin_start -- failed to register repl_version api -- end\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve and save the plugin identity to later pass to
|
||||
internal operations */
|
||||
if (slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &repl_version_plugin_id) != 0) {
|
||||
LOG_FATAL("<-- repl_version_plugin_init -- failed to retrieve plugin identity -- end\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG("<-- repl_version_plugin_init -- end\n");
|
||||
return 0;
|
||||
}
|
17
daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif
Normal file
17
daemons/ipa-slapi-plugins/ipa-version/version-conf.ldif
Normal file
@ -0,0 +1,17 @@
|
||||
dn: cn=IPA Version Replication,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: IPA Version Replication
|
||||
nsslapd-pluginpath: libipa_repl_version
|
||||
nsslapd-plugininitfunc: repl_version_plugin_init
|
||||
nsslapd-plugintype: preoperation
|
||||
nsslapd-pluginenabled: off
|
||||
nsslapd-pluginid: ipa_repl_version
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat, Inc.
|
||||
nsslapd-plugindescription: IPA Replication version plugin
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
nsslapd-plugin-depends-on-named: Multimaster Replication Plugin
|
||||
|
47
daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am
Normal file
47
daemons/ipa-slapi-plugins/ipa-winsync/Makefile.am
Normal file
@ -0,0 +1,47 @@
|
||||
NULL =
|
||||
|
||||
PLUGIN_COMMON_DIR=../common
|
||||
|
||||
INCLUDES = \
|
||||
-I. \
|
||||
-I$(srcdir) \
|
||||
-I$(PLUGIN_COMMON_DIR) \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DBINDIR=\""$(bindir)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DLIBEXECDIR=\""$(libexecdir)"\" \
|
||||
-DDATADIR=\""$(datadir)"\" \
|
||||
$(AM_CFLAGS) \
|
||||
$(LDAP_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
plugindir = $(libdir)/dirsrv/plugins
|
||||
plugin_LTLIBRARIES = \
|
||||
libipa_winsync.la \
|
||||
$(NULL)
|
||||
|
||||
libipa_winsync_la_SOURCES = \
|
||||
ipa-winsync.c \
|
||||
ipa-winsync-config.c \
|
||||
$(NULL)
|
||||
|
||||
libipa_winsync_la_LDFLAGS = -avoid-version
|
||||
|
||||
#libipa_winsync_la_LIBADD = \
|
||||
# $(LDAP_LIBS) \
|
||||
# $(NULL)
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
ipa-winsync-conf.ldif \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
README \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
0
daemons/ipa-slapi-plugins/ipa-winsync/README
Normal file
0
daemons/ipa-slapi-plugins/ipa-winsync/README
Normal file
28
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
Normal file
28
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
Normal file
@ -0,0 +1,28 @@
|
||||
dn: cn=ipa-winsync,cn=plugins,cn=config
|
||||
changetype: add
|
||||
objectclass: top
|
||||
objectclass: nsSlapdPlugin
|
||||
objectclass: extensibleObject
|
||||
cn: ipa-winsync
|
||||
nsslapd-pluginpath: libipa_winsync
|
||||
nsslapd-plugininitfunc: ipa_winsync_plugin_init
|
||||
nsslapd-pluginDescription: Allows IPA to work with the DS windows sync feature
|
||||
nsslapd-pluginid: ipa-winsync
|
||||
nsslapd-pluginversion: 1.0
|
||||
nsslapd-pluginvendor: Red Hat
|
||||
nsslapd-plugintype: preoperation
|
||||
nsslapd-pluginenabled: on
|
||||
nsslapd-plugin-depends-on-type: database
|
||||
ipaWinSyncRealmFilter: (objectclass=krbRealmContainer)
|
||||
ipaWinSyncRealmAttr: cn
|
||||
ipaWinSyncNewEntryFilter: (cn=ipaConfig)
|
||||
ipaWinSyncNewUserOCAttr: ipauserobjectclasses
|
||||
ipaWinSyncUserFlatten: true
|
||||
ipaWinsyncHomeDirAttr: ipaHomesRootDir
|
||||
ipaWinsyncLoginShellAttr: ipaDefaultLoginShell
|
||||
ipaWinSyncDefaultGroupAttr: ipaDefaultPrimaryGroup
|
||||
ipaWinSyncDefaultGroupFilter: (gidNumber=*)(objectclass=posixGroup)(objectclass=groupOfNames)
|
||||
ipaWinSyncAcctDisable: both
|
||||
ipaWinSyncForceSync: true
|
||||
ipaWinSyncUserAttr: uidNumber 999
|
||||
ipaWinSyncUserAttr: gidNumber 999
|
1019
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c
Normal file
1019
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-config.c
Normal file
File diff suppressed because it is too large
Load Diff
1130
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c
Normal file
1130
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.c
Normal file
File diff suppressed because it is too large
Load Diff
170
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h
Normal file
170
daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync.h
Normal file
@ -0,0 +1,170 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Authors:
|
||||
* Rich Megginson <rmeggins@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2008 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
#ifndef IPA_WINSYNC_H
|
||||
#define IPA_WINSYNC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef WINSYNC_TEST_IPA
|
||||
#include <slapi-plugin.h>
|
||||
#include "winsync-plugin.h"
|
||||
#else /* the default */
|
||||
#include <dirsrv/slapi-plugin.h>
|
||||
#include <dirsrv/winsync-plugin.h>
|
||||
#endif /* WINSYNC_TEST_IPA */
|
||||
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#define IPA_PLUGIN_NAME "ipa-winsync"
|
||||
|
||||
typedef struct ipa_winsync_config_struct {
|
||||
Slapi_Mutex *lock; /* for config access */
|
||||
Slapi_Entry *config_e; /* configuration entry */
|
||||
PRBool flatten; /* flatten AD DNs */
|
||||
char *realm_filter;
|
||||
char *realm_attr;
|
||||
char *new_entry_filter;
|
||||
char *new_user_oc_attr; /* don't care about groups for now */
|
||||
char *homedir_prefix_attr;
|
||||
char *login_shell_attr;
|
||||
char *default_group_attr;
|
||||
char *default_group_filter;
|
||||
int acct_disable; /* see below for possible values */
|
||||
char *inactivated_filter;
|
||||
char *activated_filter;
|
||||
PRBool forceSync;
|
||||
} IPA_WinSync_Config;
|
||||
|
||||
/*
|
||||
This is the structure that holds our domain
|
||||
specific configuration
|
||||
*/
|
||||
typedef struct ipa_winsync_domain_config {
|
||||
Slapi_Entry *domain_e; /* info is stored in this entry */
|
||||
char *realm_name; /* realm name */
|
||||
char *homedir_prefix;
|
||||
char *login_shell;
|
||||
char *inactivated_group_dn; /* DN of inactivated group */
|
||||
char *activated_group_dn; /* DN of activated group */
|
||||
} IPA_WinSync_Domain_Config;
|
||||
|
||||
void ipa_winsync_set_plugin_identity(void * identity);
|
||||
void * ipa_winsync_get_plugin_identity(void);
|
||||
|
||||
int ipa_winsync_config( Slapi_Entry *config_e );
|
||||
IPA_WinSync_Config *ipa_winsync_get_config( void );
|
||||
|
||||
/*
|
||||
* Agreement/domain specific configuration
|
||||
*/
|
||||
/* return a new domain specific configuration object */
|
||||
void *ipa_winsync_config_new_domain(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree);
|
||||
/* refresh the domain specific configuration object */
|
||||
void ipa_winsync_config_refresh_domain(void *cbdata, const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree);
|
||||
/* destroy the domain specific configuration object */
|
||||
void ipa_winsync_config_destroy_domain(void *cbdata, const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree);
|
||||
|
||||
/* name of attribute holding the filter to use to
|
||||
find the ipa realm value
|
||||
*/
|
||||
#define IPA_WINSYNC_REALM_FILTER_ATTR "ipaWinSyncRealmFilter"
|
||||
/* name of attribute holding the name of the attribute
|
||||
which contains the ipa realm value
|
||||
*/
|
||||
#define IPA_WINSYNC_REALM_ATTR_ATTR "ipaWinSyncRealmAttr"
|
||||
/* name of attribute holding the filter to use to
|
||||
find the new user template entry
|
||||
*/
|
||||
#define IPA_WINSYNC_NEW_ENTRY_FILTER_ATTR "ipaWinSyncNewEntryFilter"
|
||||
/* name of attribute holding the name of the attribute
|
||||
in the new user template entry which has the list of objectclasses
|
||||
*/
|
||||
#define IPA_WINSYNC_NEW_USER_OC_ATTR "ipaWinSyncNewUserOCAttr"
|
||||
/* name of attribute holding the new user attributes and values */
|
||||
#define IPA_WINSYNC_NEW_USER_ATTRS_VALS "ipaWinSyncUserAttr"
|
||||
/* name of attribute holding the name of the attribute which
|
||||
has the homeDirectory prefix - suffix is the uid */
|
||||
#define IPA_WINSYNC_HOMEDIR_PREFIX_ATTR "ipaWinSyncHomeDirAttr"
|
||||
/* name of attribute holding the name of the attribute which
|
||||
has the loginShell value */
|
||||
#define IPA_WINSYNC_LOGIN_SHELL_ATTR "ipaWinSyncLoginShellAttr"
|
||||
/* name of attribute holding the name of the attribute which is
|
||||
used to get the default posix gidNumber */
|
||||
#define IPA_WINSYNC_DEFAULTGROUP_ATTR "ipaWinSyncDefaultGroupAttr"
|
||||
/* filter used to find the group with the gid number whose group name
|
||||
is in the IPA_WINSYNC_DEFAULTGROUP_ATTR - the filter will have
|
||||
cn=valueofIPA_WINSYNC_DEFAULTGROUP_ATTR appended to it */
|
||||
#define IPA_WINSYNC_DEFAULTGROUP_FILTER_ATTR "ipaWinSyncDefaultGroupFilter"
|
||||
/* name of attribute holding boolean value to flatten user dns or not */
|
||||
#define IPA_WINSYNC_USER_FLATTEN "ipaWinSyncUserFlatten"
|
||||
/* name of attribute holding account disable sync value */
|
||||
#define IPA_WINSYNC_ACCT_DISABLE "ipaWinSyncAcctDisable"
|
||||
/* possible values of IPA_WINSYNC_ACCT_DISABLE */
|
||||
#define IPA_WINSYNC_ACCT_DISABLE_NONE "none"
|
||||
#define IPA_WINSYNC_ACCT_DISABLE_TO_AD "to_ad"
|
||||
#define IPA_WINSYNC_ACCT_DISABLE_TO_DS "to_ds"
|
||||
#define IPA_WINSYNC_ACCT_DISABLE_BOTH "both"
|
||||
/* enum representing the values above */
|
||||
enum {
|
||||
ACCT_DISABLE_INVALID, /* the invalid value */
|
||||
ACCT_DISABLE_NONE, /* do not sync acct disable status */
|
||||
ACCT_DISABLE_TO_AD, /* sync only from ds to ad */
|
||||
ACCT_DISABLE_TO_DS, /* sync only from ad to ds */
|
||||
ACCT_DISABLE_BOTH /* bi-directional sync */
|
||||
};
|
||||
/* name of attributes holding the search filters to use to find
|
||||
the DN of the groups that represent inactivated and activated users */
|
||||
#define IPA_WINSYNC_INACTIVATED_FILTER "ipaWinSyncInactivatedFilter"
|
||||
#define IPA_WINSYNC_ACTIVATED_FILTER "ipaWinSyncActivatedFilter"
|
||||
/* name of attribute holding the value of the forceSync parameter -
|
||||
this is a boolean attribute - if true, all users in AD that have
|
||||
a corresponding entry in the DS will be synced - there will be no
|
||||
way to "turn off sync" on individual entries - if this value is
|
||||
false, only users which have the ntUser objectclass and an
|
||||
ntDomainUserID attribute which corresponds to an AD account
|
||||
with the same value for samAccountName will be synced
|
||||
*/
|
||||
#define IPA_WINSYNC_FORCE_SYNC "ipaWinSyncForceSync"
|
||||
#endif /* IPA_WINSYNC_H */
|
48
daemons/ipa-version.h.in
Normal file
48
daemons/ipa-version.h.in
Normal file
@ -0,0 +1,48 @@
|
||||
/** 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, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GPLv3 section 7:
|
||||
*
|
||||
* In the following paragraph, "GPL" means the GNU General Public
|
||||
* License, version 3 or any later version, and "Non-GPL Code" means
|
||||
* code that is governed neither by the GPL nor a license
|
||||
* compatible with the GPL.
|
||||
*
|
||||
* You may link the code of this Program with Non-GPL Code and convey
|
||||
* linked combinations including the two, provided that such Non-GPL
|
||||
* Code only links 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 GPL. Only the copyright holders of this
|
||||
* Program may make changes or additions to the list of Approved
|
||||
* Interfaces.
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
* END COPYRIGHT BLOCK **/
|
||||
|
||||
/* The full version including strings */
|
||||
#define VERSION "__VERSION__"
|
||||
|
||||
/* Just the numeric portion of the version so one can do direct numeric
|
||||
comparisons to see if the API is compatible.
|
||||
*/
|
||||
#define NUM_VERSION __NUM_VERSION__
|
||||
|
||||
/* The data version. This is distinguished from the server version based
|
||||
on the compatibility of the data/plugins/etc from one version to another.
|
||||
*/
|
||||
#define DATA_VERSION __DATA_VERSION__
|
437
doc/examples/examples.py
Normal file
437
doc/examples/examples.py
Normal file
@ -0,0 +1,437 @@
|
||||
# Authors:
|
||||
# Pavel Zuna <pzuna@redhat.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
Example plugins
|
||||
"""
|
||||
|
||||
# Hey guys, so you're interested in writing plugins for IPA? Great!
|
||||
# We compiled this small file with examples on how to extend IPA to suit
|
||||
# your needs. We'll be going from very simple to pretty complex plugins
|
||||
# hopefully covering most of what our framework has to offer.
|
||||
|
||||
# First, let's import some stuff.
|
||||
|
||||
# api is an object containing references to all plugins and useful classes.
|
||||
# errors is a module containing all IPA specific exceptions.
|
||||
from ipalib import api, errors
|
||||
# Command is the base class for command plugin.
|
||||
from ipalib import Command
|
||||
# Str is a subclass of Param, it is used to define string parameters for
|
||||
# command. We'll go through all other subclasses of Param supported by IPA
|
||||
# later in this file
|
||||
from ipalib import Str
|
||||
# output is a module containing the most common output patterns.
|
||||
# Command plugin do output validation based on these patterns.
|
||||
# You can define your own as we're going to show you later.
|
||||
from ipalib import output
|
||||
|
||||
|
||||
# We're going to create an example command plugin, that takes a name as its
|
||||
# only argument. Commands in IPA support input validation by defining
|
||||
# functions we're going to call 'validators'. This is an example of such
|
||||
# function:
|
||||
def validate_name(ugettext, name):
|
||||
"""
|
||||
Validate names for the exhelloworld command. Names starting with 'Y'
|
||||
(picked at random) are considered invalid.
|
||||
"""
|
||||
if name.startswith('Y'):
|
||||
raise errors.ValidationError(
|
||||
name='name',
|
||||
error='Names starting with \'Y\' are invalid!'
|
||||
)
|
||||
# If the validator doesn't return anything (i.e. it returns None),
|
||||
# the parameter passes validation.
|
||||
|
||||
|
||||
class exhelloworld(Command):
|
||||
"""
|
||||
Example command: Hello world!
|
||||
"""
|
||||
# takes_args is an attribute of Command. It's a tuple containing
|
||||
# instances of Param (or its subclasses such as Str) that define
|
||||
# what position arguments are accepted by the command.
|
||||
takes_args = (
|
||||
# The first argument of Param constructor is the name that will be
|
||||
# used to identify this parameter. It can be followed by validator
|
||||
# functions. The constructor can also take a bunch of keyword
|
||||
# arguments. Here we use default, to set the parameters default value
|
||||
# and autofill, that fills the default value if the parameter isn't
|
||||
# present.
|
||||
# Note the ? at the end of the parameter name. It makes the parameter
|
||||
# optional.
|
||||
Str('name?', validate_name,
|
||||
default=u'anonymous coward',
|
||||
autofill=True,
|
||||
),
|
||||
)
|
||||
|
||||
# has_output is an attribute of Command, it is a tuple containing
|
||||
# output.Output instances that define its output pattern.
|
||||
# Commands in IPA return dicts with keys corresponding to items
|
||||
# in the has_output tuple.
|
||||
has_output = (
|
||||
# output.summary is one of the basic patterns.
|
||||
# It's a string that should be filled with a user-friendly
|
||||
# decription of the action performed by the command.
|
||||
output.summary,
|
||||
)
|
||||
|
||||
# Every command needs to override the execute method.
|
||||
# This is where the command functionality should go.
|
||||
# It is always executed on the server-side, so don't rely
|
||||
# on client-side stuff in here!
|
||||
def execute(self, name):
|
||||
return dict(summary='Hello world, %s!' % name)
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exhelloworld)
|
||||
|
||||
# Anyway, that was a pretty bad example of a command or, to be more precise,
|
||||
# a bad example of resource use. When a client executes a command locally, its
|
||||
# name and parameters are transfered to the server over XML-RPC. The command
|
||||
# execute method is then executed on the server and results are transfered
|
||||
# back to the client. The command does nothing, but create a string - a task
|
||||
# that could be easily done locally. This can be done by overriding the Command
|
||||
# forward method. It has the same signature as execute and is normally
|
||||
# responsible for transferring stuff to the server.
|
||||
# Most commands will, however, need to perfom tasks on the server. I didn't
|
||||
# want to start with forward and confuse the hell out of you. :)
|
||||
|
||||
|
||||
# Okey, time to look at something a little more advance. A command that
|
||||
# actually communicates with the LDAP backend.
|
||||
|
||||
# Let's import a new parameter type: Flag.
|
||||
# Parameters of type Flag do not have values per say. They are either enabled
|
||||
# or disabled (True or False), so there's no need to make then optional, ever.
|
||||
from ipalib import Flag
|
||||
|
||||
class exshowuser(Command):
|
||||
"""
|
||||
Example command: retrieve an user entry from LDAP
|
||||
"""
|
||||
takes_args = (
|
||||
Str('username'),
|
||||
)
|
||||
|
||||
# takes_options is another attribute of Command. It works the same
|
||||
# way as takes_args, but instead of positional arguments, it enables
|
||||
# us to define what options the commmand takes.
|
||||
# Note that an options can be both required and optional.
|
||||
takes_options = (
|
||||
Flag('all',
|
||||
# the doc keyword argument is what you see when you go
|
||||
# `ipa COMMAND --help` or `ipa help COMMAND`
|
||||
doc='retrieve and print all attributes from the server. Affects command output.',
|
||||
flags=['no_output'],
|
||||
),
|
||||
)
|
||||
|
||||
has_output = (
|
||||
# Here, you can see a custom output pattern. The pattern constructor
|
||||
# takes the output name (key in the dictionary returned by execute),
|
||||
# the allowed type(s) (can be a tuple with several types), a
|
||||
# simple description and a list of flags. Currently, only
|
||||
# the 'no_display' flag is supported by the Command.output_for_cli
|
||||
# method, but you can always use your own if you plan
|
||||
# to override it - I'll show you how later.
|
||||
output.Output('result', dict, 'user entry without DN'),
|
||||
output.Output('dn', unicode, 'DN of the user entry', ['no_display']),
|
||||
)
|
||||
|
||||
# Notice the ** argument notation for options. It is not required, but
|
||||
# we strongly recommend you to use it. In some cases, special options
|
||||
# are added automatically to commands and not listing them or using **
|
||||
# may lead to exception flying around... and nobody likes exceptions
|
||||
# flying around.
|
||||
def execute(self, username, **options):
|
||||
# OK, I said earlier that this command is going to communicate
|
||||
# with the LDAP backend, You could always use python-ldap to do
|
||||
# that, but there's also this nice class we have... it's called
|
||||
# ldap2 and this is how you get a handle to it:
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# ldap2 enables you to do a lot of crazy stuff with LDAP and it's
|
||||
# specially crafted to suit IPA plugin needs. I recommend you either
|
||||
# look at ipaserver/plugins/ldap2 or checkout some of the generated
|
||||
# HTML docs on www.freeipa.org as I won't be able to cover everything
|
||||
# it offers in this file.
|
||||
|
||||
# We want to retrieve an user entry from LDAP. We need to know its
|
||||
# DN first. There's a bunch of method in ldap2 to build DNs. For our
|
||||
# purpose, this will do:
|
||||
dn = ldap.make_dn_from_attr(
|
||||
'uid', username, self.api.env.container_user
|
||||
)
|
||||
# Note that api.env contains a lot of useful constant. We recommend
|
||||
# you to check them out and use them whenever possible.
|
||||
|
||||
# Let's check if the --all option is enabled. If it is, let's
|
||||
# retrieve all of the entry attributes. If not, only retrieve some
|
||||
# basic stuff like the username, first and last names.
|
||||
if options.get('all', False):
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = ['uid', 'givenname', 'sn']
|
||||
|
||||
# Give us the entry, LDAP!
|
||||
(dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
|
||||
|
||||
return dict(result=entry_attrs, dn=dn)
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exshowuser)
|
||||
|
||||
|
||||
# Now let's a take a look on how you can modify the command output if you don't
|
||||
# like the default.
|
||||
|
||||
class exshowuser2(exshowuser):
|
||||
"""
|
||||
Example command: exusershow with custom output
|
||||
"""
|
||||
# Just some values we're going to use for textui.print_entry
|
||||
attr_order = ['uid', 'givenname', 'sn']
|
||||
attr_labels = {
|
||||
'uid': 'User login', 'givenname': 'First name', 'sn': 'Last name'
|
||||
}
|
||||
|
||||
def output_for_cli(self, textui, output, *args, **options):
|
||||
# Now we've done it! We have overridden the default output_for_cli.
|
||||
# textui is a class that implements a lot of useful outputting methods,
|
||||
# please use it when you can
|
||||
# output contains the dict returned by execute
|
||||
# args, options contain the command parameters
|
||||
textui.print_dashed('User entry:')
|
||||
textui.print_indented('DN: %s' % output['dn'])
|
||||
textui.print_entry(output['result'], self.attr_order, self.attr_labels)
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exshowuser2)
|
||||
|
||||
# Alright, so now you'll always want to define your own output_for_cli...
|
||||
# No, you won't! Because the default output_for_cli isn't as stupid as it looks.
|
||||
# It can take information from the command parameters and output patterns
|
||||
# to produce nice output like all real IPA commands have.
|
||||
|
||||
class exshowuser3(exshowuser):
|
||||
"""
|
||||
Example command: exusershow that takes full advantage of the default output
|
||||
"""
|
||||
takes_args = (
|
||||
# We're going to rename the username argument to uid to match
|
||||
# the attribute name it represent. The cli_name kwarg is what
|
||||
# users will see in the CLI and label is what the default
|
||||
# output_for_cli is going to use when printing the attribute value.
|
||||
Str('uid',
|
||||
cli_name='username',
|
||||
label='User login',
|
||||
),
|
||||
)
|
||||
|
||||
# has_output_params works the same way as takes_args and takes_options,
|
||||
# but is only used to define output attributes. These won't show up
|
||||
# as parameters for the command.
|
||||
has_output_params = (
|
||||
Str('givenname',
|
||||
label='First name',
|
||||
),
|
||||
Str('sn',
|
||||
label='Last name',
|
||||
),
|
||||
)
|
||||
|
||||
# standard_entry includes an entry 'result' (dict), a summary 'summary'
|
||||
# and the entry primary key 'value'
|
||||
# It also makes the command automatically add two special options:
|
||||
# --all and --raw. Look at the description of nearly any real IPA command
|
||||
# to see what they're about.
|
||||
has_output = output.standard_entry
|
||||
|
||||
# Since --all and --raw are added automatically thanks to standard_entry,
|
||||
# we need to clear takes_options from the base class otherwise we would
|
||||
# get a parameter conflict.
|
||||
takes_options = tuple()
|
||||
|
||||
def execute(self, *args, **options):
|
||||
# Let's just call execute of the base class, extract it's output
|
||||
# and fit it into the standard_entry output pattern.
|
||||
output = super(exshowuser3, self).execute(*args, **options)
|
||||
output['result']['dn'] = output['dn']
|
||||
return dict(result=output['result'], value=args[0])
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exshowuser3)
|
||||
|
||||
|
||||
# Pretty cool, right? But you will probably want to implement a set of commands
|
||||
# to manage a certain type of entries (like users in the above examples).
|
||||
# To save you the massive PITA of parameter copy&paste, we introduced
|
||||
# the Object and Method plugin classes. Let's see how they work.
|
||||
|
||||
from ipalib import Object, Method
|
||||
|
||||
# First, we're going to create an object that represent the user entry.
|
||||
class exuser(Object):
|
||||
"""
|
||||
Example plugin: user object
|
||||
"""
|
||||
# takes_params is an attribute of Object. It is used to define output
|
||||
# parameters for associated Methods. Methods can also use them to
|
||||
# to generate their own parameters as you'll see in a while.
|
||||
takes_params = (
|
||||
Str('uid',
|
||||
cli_name='username',
|
||||
label='User login',
|
||||
# The primary_key kwarg is used to, well, specify the object's
|
||||
# primary key.
|
||||
primary_key=True,
|
||||
),
|
||||
Str('givenname?',
|
||||
cli_name='first',
|
||||
label='First name',
|
||||
),
|
||||
Str('sn?',
|
||||
cli_name='last',
|
||||
label='Last name',
|
||||
),
|
||||
)
|
||||
|
||||
# register the object, uncomment this line if you want to try it out
|
||||
#api.register(exuser)
|
||||
|
||||
# Next, we're going to create a set of methods to manage this type of object
|
||||
# i.e. to manage user entries. We're only going to do "read" commands, because
|
||||
# we don't want to damage your user entries - adding, deleting, modifying is a
|
||||
# bit more complicated and will be covered later in this file.
|
||||
|
||||
# Methods are automatically associated with a parent Object based on class
|
||||
# names. They can then access their parent Object using self.obj.
|
||||
# Simply said, Methods are just Commands associated with an Object.
|
||||
|
||||
class exuser_show(Method):
|
||||
has_output = output.standard_entry
|
||||
|
||||
# get_args is a method of Command used to generate positional arguments
|
||||
# we're going to use it to extract parameters from the parent
|
||||
# Object
|
||||
def get_args(self):
|
||||
# self.obj.primary_key contains a reference the parameter with
|
||||
# primary_key kwarg set to True.
|
||||
# Parameters can be cloned to create new instance with additional
|
||||
# kwargs. Here we add the attribute kwargs, that tells the framework
|
||||
# the parameters corresponds to an LDAP attribute. The query kwargs
|
||||
# tells the framework to skip parameter validation (i.e. do NOT call
|
||||
# validators).
|
||||
yield self.obj.primary_key.clone(attribute=True, query=True)
|
||||
|
||||
def execute(self, *args, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
dn = ldap.make_dn_from_attr(
|
||||
'uid', args[0], self.api.env.container_user
|
||||
)
|
||||
|
||||
if options.get('all', False):
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = [p.name for p in self.output_params()]
|
||||
|
||||
(dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
|
||||
entry_attrs['dn'] = dn
|
||||
|
||||
return dict(result=entry_attrs, value=args[0])
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exuser_show)
|
||||
|
||||
class exuser_find(Method):
|
||||
# standard_list_of_entries is an output pattern that
|
||||
# define a dict with a list of entries, their count
|
||||
# and a truncated flag. The truncated flag is used to mark
|
||||
# truncated (incomplete) search results - for example due to
|
||||
# timeouts.
|
||||
has_output = output.standard_list_of_entries
|
||||
|
||||
# get_options is similar to get_args, but is used to generate
|
||||
# options instead of positional arguments
|
||||
def get_options(self):
|
||||
for option in self.obj.params():
|
||||
yield option.clone(
|
||||
attribute=True, query=True, required=False
|
||||
)
|
||||
|
||||
def execute(self, *args, **options):
|
||||
ldap = self.api.Backend.ldap2
|
||||
|
||||
# args_options_2_entry is a helper method of Command used
|
||||
# to create a dictionary from the command parameters that
|
||||
# have the attribute kwargs set to True.
|
||||
search_kw = self.args_options_2_entry(*args, **options)
|
||||
|
||||
# make_filter will create an LDAP filter from attribute values
|
||||
# exact=False means the values are surrounded with * when constructing
|
||||
# the filter and rules=ldap.MATCH_ALL means the filter is going
|
||||
# to use the & operators. More complex filters can be constructed
|
||||
# by joining simpler filters using ldap2.combine_filters.
|
||||
attr_filter = ldap.make_filter(
|
||||
search_kw, exact=False, rules=ldap.MATCH_ALL
|
||||
)
|
||||
|
||||
if options.get('all', False):
|
||||
attrs_list = ['*']
|
||||
else:
|
||||
attrs_list = [p.name for p in self.output_params()]
|
||||
|
||||
# perform the search
|
||||
(entries, truncated) = ldap.find_entries(
|
||||
attr_filter, attrs_list, self.api.env.container_user,
|
||||
scope=ldap.SCOPE_ONELEVEL
|
||||
)
|
||||
|
||||
# find_entries returns DNs and attributes separately, but the output
|
||||
# patter expects them in one dict. We need to arrange that.
|
||||
for e in entries:
|
||||
e[1]['dn'] = e[0]
|
||||
entries = [e for (dn, e) in entries]
|
||||
|
||||
return dict(result=entries, count=len(entries), truncated=truncated)
|
||||
|
||||
# register the command, uncomment this line if you want to try it out
|
||||
#api.register(exuser_find)
|
||||
|
||||
# As most commands associated with objects are used to manage entries in LDAP,
|
||||
# we defined a basic set of base classes for your plugins implementing CRUD
|
||||
# operations. This is maily to save you from defining your own has_output,
|
||||
# get_args, get_options and to have a standardized way of doing things for the
|
||||
# sake of consistency. We won't cover them here, because you probably won't
|
||||
# need to use them. So why did we botter? Well, you're going to see in
|
||||
# a while. If interested anyway, check them out in ipalib/crud.py.
|
||||
|
||||
|
||||
# At this point, if you've already seen some of the real plugins, you might
|
||||
# be going like "WTH is this !@#^&? The user_show plugin is only like 4 lines
|
||||
# of code and does much more than the exshowuser crap. Well yes, that's because
|
||||
# it is based on one of the awesome plugin base classes we created to save
|
||||
# authors from doing all the dirty work. Let's take a look at them.
|
||||
|
||||
# COMING SOON: baseldap.py classes, extending existing plugins, etc.
|
||||
|
||||
|
49
doc/examples/python-api.py
Executable file
49
doc/examples/python-api.py
Executable file
@ -0,0 +1,49 @@
|
||||
#!/usr/bin/python
|
||||
# Authors:
|
||||
# Jason Gerard DeRose <jderose@redhat.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from ipalib import api
|
||||
|
||||
# 1. Initialize ipalib
|
||||
#
|
||||
# Run ./python-api.py --help to see the global options. Some useful options:
|
||||
#
|
||||
# -v Produce more verbose output
|
||||
# -d Produce full debugging output
|
||||
# -e in_server=True Force running in server mode
|
||||
# -e xmlrpc_uri=https://foo.com/ipa/xml # Connect to a specific server
|
||||
|
||||
api.bootstrap_with_global_options(context='example')
|
||||
api.finalize()
|
||||
|
||||
# You will need to create a connection. If you're in_server, call
|
||||
# Backend.ldap.connect(), otherwise Backend.xmlclient.connect().
|
||||
|
||||
if api.env.in_server:
|
||||
api.Backend.ldap2.connect(
|
||||
ccache=api.Backend.krb.default_ccname()
|
||||
)
|
||||
else:
|
||||
api.Backend.xmlclient.connect()
|
||||
|
||||
|
||||
# Now that you're connected, you can make calls to api.Command.whatever():
|
||||
print 'The admin user:'
|
||||
print api.Command.user_show(u'admin')
|
956
freeipa.spec.in
Normal file
956
freeipa.spec.in
Normal file
@ -0,0 +1,956 @@
|
||||
# Define ONLY_CLIENT to only make the ipa-client and ipa-python subpackages
|
||||
%{!?ONLY_CLIENT:%global ONLY_CLIENT 0}
|
||||
|
||||
%global httpd_conf /etc/httpd/conf.d
|
||||
%global plugin_dir %{_libdir}/dirsrv/plugins
|
||||
%if ! (0%{?fedora} > 12 || 0%{?rhel} > 5)
|
||||
%{!?python_sitelib: %global python_sitelib %(%{__python} -c "from
|
||||
distutils.sysconfig import get_python_lib; print(get_python_lib())")}
|
||||
%{!?python_sitearch: %global python_sitearch %(%{__python} -c "from
|
||||
distutils.sysconfig import get_python_lib; print(get_python_lib(1))")}
|
||||
%endif
|
||||
%global POLICYCOREUTILSVER 1.33.12-1
|
||||
%global gettext_domain ipa
|
||||
|
||||
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.2.9
|
||||
BuildRequires: svrcore-devel
|
||||
BuildRequires: /usr/share/selinux/devel/Makefile
|
||||
BuildRequires: policycoreutils >= %{POLICYCOREUTILSVER}
|
||||
%endif
|
||||
BuildRequires: nspr-devel
|
||||
BuildRequires: nss-devel
|
||||
BuildRequires: openssl-devel
|
||||
BuildRequires: openldap-devel
|
||||
BuildRequires: krb5-devel
|
||||
BuildRequires: krb5-workstation
|
||||
BuildRequires: libuuid-devel
|
||||
%if 0%{?fedora} >= 16
|
||||
BuildRequires: libcurl-devel >= 7.21.7-2
|
||||
BuildRequires: xmlrpc-c-devel >= 1.27.4
|
||||
%else
|
||||
%if 0%{?fedora} == 15
|
||||
BuildRequires: libcurl-devel >= 7.21.3-9
|
||||
BuildRequires: xmlrpc-c-devel >= 1.25.4
|
||||
%else
|
||||
BuildRequires: libcurl-devel
|
||||
BuildRequires: xmlrpc-c-devel
|
||||
%endif
|
||||
%endif
|
||||
BuildRequires: popt-devel
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: m4
|
||||
BuildRequires: libtool
|
||||
BuildRequires: gettext
|
||||
BuildRequires: python-devel
|
||||
BuildRequires: authconfig
|
||||
BuildRequires: python-ldap
|
||||
BuildRequires: python-setuptools
|
||||
BuildRequires: python-krbV
|
||||
BuildRequires: python-nss
|
||||
%if 0%{?fedora} >= 15
|
||||
BuildRequires: python-netaddr >= 0.7.5-3
|
||||
%else
|
||||
BuildRequires: python-netaddr
|
||||
%endif
|
||||
BuildRequires: python-kerberos
|
||||
BuildRequires: python-rhsm
|
||||
BuildRequires: pyOpenSSL
|
||||
BuildRequires: pylint
|
||||
BuildRequires: libipa_hbac-python
|
||||
|
||||
%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: %{name}-server-selinux = %{version}-%{release}
|
||||
Requires(pre): 389-ds-base >= 1.2.10-0.4.a4
|
||||
Requires: openldap-clients
|
||||
Requires: nss
|
||||
Requires: nss-tools
|
||||
Requires: krb5-server
|
||||
Requires: krb5-server-ldap
|
||||
Requires: krb5-pkinit-openssl
|
||||
Requires: cyrus-sasl-gssapi%{?_isa}
|
||||
Requires: ntp
|
||||
Requires: httpd
|
||||
Requires: mod_wsgi
|
||||
Requires: mod_auth_kerb
|
||||
Requires: mod_nss >= 1.0.8-10
|
||||
Requires: python-ldap
|
||||
Requires: python-krbV
|
||||
Requires: acl
|
||||
Requires: python-pyasn1 >= 0.0.9a
|
||||
%if 0%{?fedora} >= 15
|
||||
Requires: selinux-policy >= 3.9.16-18
|
||||
%else
|
||||
Requires: selinux-policy >= 3.9.7-27
|
||||
%endif
|
||||
Requires(post): selinux-policy-base
|
||||
Requires: slapi-nis >= 0.21
|
||||
%if 0%{?fedora} >= 15
|
||||
Requires: pki-ca >= 9.0.15
|
||||
Requires: pki-silent >= 9.0.15
|
||||
Requires: pki-setup >= 9.0.15
|
||||
%else
|
||||
Requires: pki-ca >= 9.0.5
|
||||
Requires: pki-silent >= 9.0.5
|
||||
%endif
|
||||
Requires: dogtag-pki-common-theme
|
||||
Requires: dogtag-pki-ca-theme
|
||||
%if 0%{?rhel}
|
||||
Requires: subscription-manager
|
||||
%endif
|
||||
Requires(preun): python initscripts chkconfig
|
||||
Requires(postun): python initscripts chkconfig
|
||||
|
||||
# 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.
|
||||
Conflicts: bind-dyndb-ldap < 1.0.0-0.1.b1
|
||||
Conflicts: bind < 9.8.1-1
|
||||
|
||||
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-selinux
|
||||
Summary: SELinux rules for freeipa-server daemons
|
||||
Group: System Environment/Base
|
||||
Requires(post): %{name}-server = %{version}-%{release}
|
||||
Requires(postun): %{name}-server = %{version}-%{release}
|
||||
Requires(pre): policycoreutils >= %{POLICYCOREUTILSVER}
|
||||
|
||||
Obsoletes: ipa-server-selinux >= 1.0
|
||||
|
||||
%description server-selinux
|
||||
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 SELinux rules for the
|
||||
daemons included in freeipa-server
|
||||
%endif
|
||||
|
||||
|
||||
%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
|
||||
%if 0%{?fedora} >= 16
|
||||
Requires: libcurl >= 7.21.7-2
|
||||
Requires: xmlrpc-c >= 1.27.4
|
||||
%else
|
||||
%if 0%{?fedora} == 15
|
||||
Requires: libcurl >= 7.21.3-9
|
||||
Requires: xmlrpc-c >= 1.25.4
|
||||
%else
|
||||
Requires: libcurl
|
||||
Requires: xmlrpc-c
|
||||
%endif
|
||||
%endif
|
||||
Requires: sssd >= 1.5.1
|
||||
Requires: certmonger >= 0.26
|
||||
Requires: nss-tools
|
||||
Requires: bind-utils
|
||||
|
||||
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
|
||||
|
||||
%package python
|
||||
Summary: Python libraries used by IPA
|
||||
Group: System Environment/Libraries
|
||||
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
|
||||
Requires: python-kerberos >= 1.1-3
|
||||
%endif
|
||||
Requires: authconfig
|
||||
Requires: gnupg
|
||||
Requires: iproute
|
||||
Requires: pyOpenSSL
|
||||
Requires: python-nss >= 0.11
|
||||
Requires: python-lxml
|
||||
%if 0%{?fedora} >= 15
|
||||
Requires: python-netaddr >= 0.7.5-3
|
||||
%else
|
||||
Requires: python-netaddr
|
||||
%endif
|
||||
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.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -n freeipa-%{version} -q
|
||||
|
||||
%build
|
||||
export CFLAGS="$CFLAGS %{optflags}"
|
||||
export CPPFLAGS="$CPPFLAGS %{optflags}"
|
||||
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
|
||||
|
||||
%if ! %{ONLY_CLIENT}
|
||||
make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} all
|
||||
cd selinux
|
||||
# This isn't multi-process make capable yet
|
||||
make all
|
||||
%else
|
||||
make IPA_VERSION_IS_GIT_SNAPSHOT=no %{?_smp_mflags} client
|
||||
%endif
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
%if ! %{ONLY_CLIENT}
|
||||
make install DESTDIR=%{buildroot}
|
||||
cd selinux
|
||||
make install DESTDIR=%{buildroot}
|
||||
cd ..
|
||||
%else
|
||||
make client-install DESTDIR=%{buildroot}
|
||||
%endif
|
||||
%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
|
||||
|
||||
# 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 %{buildroot}%{_usr}/share/ipa/html/
|
||||
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/hbac-deny-remove.html \
|
||||
%{buildroot}%{_usr}/share/ipa/html/hbac-deny-remove.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
|
||||
install -m755 ipa.init %{buildroot}%{_initrddir}/ipa
|
||||
%endif
|
||||
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/ipa/
|
||||
/bin/touch %{buildroot}%{_sysconfdir}/ipa/default.conf
|
||||
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
|
||||
install -pm 644 ipa-compliance.cron %{buildroot}%{_sysconfdir}/cron.d/ipa-compliance
|
||||
%endif
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%if ! %{ONLY_CLIENT}
|
||||
%post server
|
||||
if [ $1 = 1 ]; then
|
||||
/sbin/chkconfig --add ipa
|
||||
/sbin/chkconfig --add ipa_kpasswd
|
||||
fi
|
||||
if [ $1 -gt 1 ] ; then
|
||||
/usr/sbin/ipa-upgradeconfig || :
|
||||
/usr/sbin/ipa-ldap-updater --upgrade >/dev/null 2>&1 || :
|
||||
fi
|
||||
|
||||
%preun server
|
||||
if [ $1 = 0 ]; then
|
||||
/sbin/chkconfig --del ipa
|
||||
/sbin/chkconfig --del ipa_kpasswd
|
||||
/sbin/service ipa stop >/dev/null 2>&1 || :
|
||||
fi
|
||||
|
||||
%postun server
|
||||
if [ "$1" -ge "1" ]; then
|
||||
/sbin/service ipa condrestart >/dev/null 2>&1 || :
|
||||
fi
|
||||
|
||||
%pre server-selinux
|
||||
if [ -s /etc/selinux/config ]; then
|
||||
. %{_sysconfdir}/selinux/config
|
||||
FILE_CONTEXT=%{_sysconfdir}/selinux/targeted/contexts/files/file_contexts
|
||||
if [ "${SELINUXTYPE}" == targeted -a -f ${FILE_CONTEXT} ]; then \
|
||||
cp -f ${FILE_CONTEXT} ${FILE_CONTEXT}.%{name}
|
||||
fi
|
||||
fi
|
||||
|
||||
%post server-selinux
|
||||
semodule -s targeted -i /usr/share/selinux/targeted/ipa_kpasswd.pp /usr/share/selinux/targeted/ipa_httpd.pp /usr/share/selinux/targeted/ipa_dogtag.pp
|
||||
. %{_sysconfdir}/selinux/config
|
||||
FILE_CONTEXT=%{_sysconfdir}/selinux/targeted/contexts/files/file_contexts
|
||||
selinuxenabled
|
||||
if [ $? == 0 -a "${SELINUXTYPE}" == targeted -a -f ${FILE_CONTEXT}.%{name} ]; then
|
||||
fixfiles -C ${FILE_CONTEXT}.%{name} restore
|
||||
rm -f ${FILE_CONTEXT}.%name
|
||||
fi
|
||||
|
||||
%preun server-selinux
|
||||
if [ $1 = 0 ]; then
|
||||
if [ -s /etc/selinux/config ]; then
|
||||
. %{_sysconfdir}/selinux/config
|
||||
FILE_CONTEXT=%{_sysconfdir}/selinux/targeted/contexts/files/file_contexts
|
||||
if [ "${SELINUXTYPE}" == targeted -a -f ${FILE_CONTEXT} ]; then \
|
||||
cp -f ${FILE_CONTEXT} ${FILE_CONTEXT}.%{name}
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
%postun server-selinux
|
||||
if [ $1 = 0 ]; then
|
||||
semodule -s targeted -r ipa_kpasswd ipa_httpd ipa_dogtag
|
||||
. %{_sysconfdir}/selinux/config
|
||||
FILE_CONTEXT=%{_sysconfdir}/selinux/targeted/contexts/files/file_contexts
|
||||
selinuxenabled
|
||||
if [ $? == 0 -a "${SELINUXTYPE}" == targeted -a -f ${FILE_CONTEXT}.%{name} ]; then
|
||||
fixfiles -C ${FILE_CONTEXT}.%{name} restore
|
||||
rm -f ${FILE_CONTEXT}.%name
|
||||
fi
|
||||
fi
|
||||
%endif
|
||||
|
||||
|
||||
%if ! %{ONLY_CLIENT}
|
||||
%files server
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING README Contributors.txt
|
||||
%{_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}/ipa_kpasswd
|
||||
%{_sbindir}/ipactl
|
||||
%{_sbindir}/ipa-upgradeconfig
|
||||
%{_sbindir}/ipa-compliance
|
||||
%{_sysconfdir}/cron.d/ipa-compliance
|
||||
%attr(755,root,root) %{_initrddir}/ipa
|
||||
%attr(755,root,root) %{_initrddir}/ipa_kpasswd
|
||||
%dir %{python_sitelib}/ipaserver
|
||||
%{python_sitelib}/ipaserver/*
|
||||
%dir %{_usr}/share/ipa
|
||||
%{_usr}/share/ipa/wsgi.py*
|
||||
%{_usr}/share/ipa/*.ldif
|
||||
%{_usr}/share/ipa/*.uldif
|
||||
%{_usr}/share/ipa/*.template
|
||||
%dir %{_usr}/share/ipa/html
|
||||
%{_usr}/share/ipa/html/ssbrowser.html
|
||||
%{_usr}/share/ipa/html/browserconfig.html
|
||||
%{_usr}/share/ipa/html/unauthorized.html
|
||||
%{_usr}/share/ipa/html/hbac-deny-remove.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/ipa_migration.css
|
||||
%{_usr}/share/ipa/migration/migration.py*
|
||||
%dir %{_usr}/share/ipa/ui
|
||||
%{_usr}/share/ipa/ui/index.html
|
||||
%{_usr}/share/ipa/ui/*.png
|
||||
%{_usr}/share/ipa/ui/*.gif
|
||||
%{_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 %{_sysconfdir}/ipa
|
||||
%dir %{_sysconfdir}/ipa/html
|
||||
%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
|
||||
%config(noreplace) %{_sysconfdir}/ipa/html/hbac-deny-remove.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/ipa.conf
|
||||
%{_usr}/share/ipa/ipa-rewrite.conf
|
||||
%{_usr}/share/ipa/ipa-pki-proxy.conf
|
||||
%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
|
||||
%dir %{_localstatedir}/lib/ipa
|
||||
%attr(700,root,root) %dir %{_localstatedir}/lib/ipa/sysrestore
|
||||
%dir %{_localstatedir}/cache/ipa
|
||||
%attr(700,apache,apache) %dir %{_localstatedir}/cache/ipa/sessions
|
||||
%attr(700,root,root) %dir %{_localstatedir}/cache/ipa/kpasswd
|
||||
%{_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/ipa_kpasswd.8.gz
|
||||
%{_mandir}/man8/ipactl.8.gz
|
||||
%{_mandir}/man1/ipa-compliance.1.gz
|
||||
|
||||
%files server-selinux
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING README Contributors.txt
|
||||
%{_usr}/share/selinux/targeted/ipa_kpasswd.pp
|
||||
%{_usr}/share/selinux/targeted/ipa_httpd.pp
|
||||
%{_usr}/share/selinux/targeted/ipa_dogtag.pp
|
||||
%endif
|
||||
|
||||
%files client
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING README Contributors.txt
|
||||
%{_sbindir}/ipa-client-install
|
||||
%{_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-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
|
||||
|
||||
%files python -f %{gettext_domain}.lang
|
||||
%defattr(-,root,root,-)
|
||||
%doc COPYING README Contributors.txt
|
||||
%dir %{python_sitelib}/ipapython
|
||||
%dir %{python_sitelib}/ipapython/platform
|
||||
%{python_sitelib}/ipapython/*.py*
|
||||
%{python_sitelib}/ipapython/platform/*.py*
|
||||
%dir %{python_sitelib}/ipalib
|
||||
%{python_sitelib}/ipalib/*
|
||||
%{python_sitearch}/default_encoding_utf8.so
|
||||
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
|
||||
%{python_sitelib}/ipapython-*.egg-info
|
||||
%{python_sitelib}/freeipa-*.egg-info
|
||||
%{python_sitearch}/python_default_encoding-*.egg-info
|
||||
%endif
|
||||
%ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf
|
||||
|
||||
%changelog
|
||||
* Fri Oct 14 2011 Rob Crittenden <rcritten@redhat.com> - 2.1.1-3
|
||||
- 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 <ayoung@redhat.com> - 2.1.1-2
|
||||
- Add explicit dependency on pki-setup.
|
||||
|
||||
* Mon Sep 12 2011 Alexander Bokovoy <abokovoy@redhat.com> - 2.1.1-1
|
||||
- Make sure platform adaptation is packaged in -python sub-package
|
||||
|
||||
* Fri Sep 9 2011 Martin Kosek <mkosek@redhat.com> - 2.1.0-4
|
||||
- Add soft dependency for bind and bind-dyndb-ldap required versions
|
||||
|
||||
* Wed Aug 31 2011 Rob Crittenden <rcritten@redhat.com> - 2.1.0-3
|
||||
- Set min nvr of 389-ds-base to 1.2.9.7-1 for BZ 728605
|
||||
|
||||
* Mon Aug 29 2011 Rob Crittenden <rcritten@redhat.com> - 2.1.0-2
|
||||
- Set min nvr of pki-ca to 9.0.12 for fix in BZ 700505
|
||||
|
||||
* Tue Aug 23 2011 Jan Cholasta <jcholast@redhat.com> - 2.1.0-1
|
||||
- Add subscription-manager dependency for RHEL.
|
||||
|
||||
* Thu Aug 11 2011 Martin Kosek <mkosek@redhat.com> - 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 <mkosek@redhat.com> - 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 <edewata@redhat.com> - 2.0.90-10
|
||||
- Add *.ico files
|
||||
|
||||
* Tue Jul 29 2011 Alexander Bokovoy <abokovoy@redhat.com> - 2.0.90-9
|
||||
- Add libipa_hbac-python dependency for hbactest plugin
|
||||
|
||||
* Thu Jul 28 2011 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 2.0.90-7
|
||||
- Make cyrus-sasl-gssapi requires arch-specific
|
||||
|
||||
* Thu Jul 14 2011 Rob Crittenden <rcritten@redhat.com> - 2.0.90-6
|
||||
- Add ipa-csreplica-manage tool.
|
||||
|
||||
* Wed Jul 6 2011 Adam Young <ayoung@redhat.com> - 2.0.90-5
|
||||
- Add HTML file describing issues with HBAC deny rules
|
||||
|
||||
* Fri Jun 17 2011 Rob Crittenden <rcritten@redhat.com> - 2.0.90-4
|
||||
- Ship ipa-ca-install utility
|
||||
|
||||
* Thu May 12 2011 Rob Crittenden <rcritten@redhat.com> - 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 <mkosek@redhat.com> - 2.0.90-2
|
||||
- Add BuildRequires on pylint, python-rhsm to enable a build with enforced
|
||||
pylint check
|
||||
|
||||
* Tue May 3 2011 Rob Crittenden <rcritten@redhat.com> - 2.0.90-1
|
||||
- Bump version to 2.0.90
|
||||
|
||||
* Tue Apr 5 2011 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-46
|
||||
- Automatically apply updates when the package is upgraded.
|
||||
|
||||
* Thu Feb 17 2011 Jakub Hrozek <jhrozek@redhat.com> - 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 <rcritten@redhat.com> - 1.99-44
|
||||
- Set minimum version of sssd to 1.5.1
|
||||
|
||||
* Thu Feb 2 2011 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-42
|
||||
- Apply changes discovered in Fedora package review process (#672986)
|
||||
|
||||
* Tue Jan 25 2011 Rob Crittenden <rcritten@redhat.com> - 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
|
||||
|
||||
* Thu Jan 19 2011 Adam Young <ayoung@redhat.com> - 1.99-40
|
||||
- Moved directory install/static to install/ui
|
||||
|
||||
* Thu Jan 13 2011 Simo Sorce <ssorce@redhat.com> - 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 <ssorce@redhat.com> - 1.99-38
|
||||
- Remove radius subpackages
|
||||
|
||||
* Thu Jan 13 2011 Rob Crittenden <rcritten@redhat.com> - 1.99-37
|
||||
- Set minimum pki-ca and pki-silent versions to 9.0.0
|
||||
|
||||
* Wed Jan 12 2011 Rob Crittenden <rcritten@redhat.com> - 1.99-36
|
||||
- Drop BuildRequires on mozldap-devel
|
||||
|
||||
* Mon Dec 13 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-35
|
||||
- Add Requires on krb5-pkinit-openssl
|
||||
|
||||
* Fri Dec 10 2010 Jr Aquino <jr.aquino@citrix.com> - 1.99-34
|
||||
- Add ipa-host-net-manage script
|
||||
|
||||
* Tue Dec 7 2010 Simo Sorce <ssorce@redhat.com> - 1.99-33
|
||||
- Add ipa init script
|
||||
|
||||
* Fri Nov 19 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-32
|
||||
- Set minimum level of 389-ds-base to 1.2.7 for enhanced memberof plugin
|
||||
|
||||
* Wed Nov 3 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-31
|
||||
- remove ipa-fix-CVE-2008-3274
|
||||
|
||||
* Wed Oct 6 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-30
|
||||
- Remove duplicate %%files entries on share/ipa/static
|
||||
- Add python default encoding shared library
|
||||
|
||||
* Mon Sep 20 2010 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-26
|
||||
- Add BuildRequires for authconfig
|
||||
|
||||
* Mon Jul 19 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-25
|
||||
- Bump up minimum version of python-nss to pick up nss_is_initialize() API
|
||||
|
||||
* Thu Jun 24 2010 Adam Young <ayoung@redhat.com> - 1.99-24
|
||||
- Removed python-asset based webui
|
||||
|
||||
* Thu Jun 24 2010 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-22
|
||||
- Drop Requires of python-krbV on ipa-client
|
||||
|
||||
* Mon May 17 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-21
|
||||
- Load ipa_dogtag.pp in post install
|
||||
|
||||
* Mon Apr 26 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-20
|
||||
- Set minimum level of sssd to 1.1.1 to pull in required hbac fixes.
|
||||
|
||||
* Thu Mar 4 2010 Rob Crittenden <rcritten@redhat.com> - 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 <jderose@redhat.com> - 1.99-18
|
||||
- Fixed share/ipa/wsgi.py so .pyc, .pyo files are included
|
||||
|
||||
* Wed Feb 24 2010 Jason Gerard DeRose <jderose@redhat.com> - 1.99-17
|
||||
- Added Require mod_wsgi, added share/ipa/wsgi.py
|
||||
|
||||
* Thu Feb 11 2010 Jason Gerard DeRose <jderose@redhat.com> - 1.99-16
|
||||
- Require python-wehjit >= 0.2.2
|
||||
|
||||
* Wed Feb 3 2010 Rob Crittenden <rcritten@redhat.com> - 1.99-15
|
||||
- Add sssd and certmonger as a Requires on ipa-client
|
||||
|
||||
* Wed Jan 27 2010 Jason Gerard DeRose <jderose@redhat.com> - 1.99-14
|
||||
- Require python-wehjit >= 0.2.0
|
||||
|
||||
* Fri Dec 4 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-13
|
||||
- Add ipa-rmkeytab tool
|
||||
|
||||
* Tue Dec 1 2009 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-11
|
||||
- Remove v1-style /etc/ipa/ipa.conf, replacing with /etc/ipa/default.conf
|
||||
|
||||
* Fri Nov 13 2009 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.99-9
|
||||
- Remove ipa_webgui, its functions rolled into ipa_httpd
|
||||
|
||||
* Mon Oct 12 2009 Jason Gerard DeRose <jderose@redhat.com> - 1.99-8
|
||||
- Removed python-cherrypy from BuildRequires and Requires
|
||||
- Added Requires python-assets, python-wehjit
|
||||
|
||||
* Mon Aug 24 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-7
|
||||
- Added httpd SELinux policy so CRLs can be read
|
||||
|
||||
* Thu May 21 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-6
|
||||
- Move ipalib to ipa-python subpackage
|
||||
- Bump minimum version of slapi-nis to 0.15
|
||||
|
||||
* Thu May 6 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-5
|
||||
- Set 0.14 as minimum version for slapi-nis
|
||||
|
||||
* Wed Apr 22 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-4
|
||||
- Add Requires: python-nss to ipa-python sub-package
|
||||
|
||||
* Thu Mar 5 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-3
|
||||
- Remove the IPA DNA plugin, use the DS one
|
||||
|
||||
* Wed Mar 4 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-2
|
||||
- Build radius separately
|
||||
- Fix a few minor issues
|
||||
|
||||
* Tue Feb 3 2009 Rob Crittenden <rcritten@redhat.com> - 1.99-1
|
||||
- Replace TurboGears requirement with python-cherrypy
|
||||
|
||||
* Sat Jan 17 2009 Tomas Mraz <tmraz@redhat.com> - 1.2.1-3
|
||||
- rebuild with new openssl
|
||||
|
||||
* Fri Dec 19 2008 Dan Walsh <dwalsh@redhat.com> - 1.2.1-2
|
||||
- Fix SELinux code
|
||||
|
||||
* Mon Dec 15 2008 Simo Sorce <ssorce@redhat.com> - 1.2.1-1
|
||||
- Fix breakage caused by python-kerberos update to 1.1
|
||||
|
||||
* Fri Dec 5 2008 Simo Sorce <ssorce@redhat.com> - 1.2.1-0
|
||||
- New upstream release 1.2.1
|
||||
|
||||
* Sat Nov 29 2008 Ignacio Vazquez-Abrams <ivazqueznet+rpm@gmail.com> - 1.2.0-4
|
||||
- Rebuild for Python 2.6
|
||||
|
||||
* Fri Nov 14 2008 Simo Sorce <ssorce@redhat.com> - 1.2.0-3
|
||||
- Respin after the tarball has been re-released upstream
|
||||
New hash is 506c9c92dcaf9f227cba5030e999f177
|
||||
|
||||
* Thu Nov 13 2008 Simo Sorce <ssorce@redhat.com> - 1.2.0-2
|
||||
- Conditionally restart also dirsrv and httpd when upgrading
|
||||
|
||||
* Wed Oct 29 2008 Rob Crittenden <rcritten@redhat.com> - 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 <ssorce@redhat.com> - 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 <rcritten@redhat.com> - 1.1.0-2
|
||||
- Add call to /usr/sbin/upgradeconfig to post install
|
||||
|
||||
* Wed Jun 11 2008 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.0.0-3
|
||||
- Added patch to fix problem reported by ldapmodify
|
||||
|
||||
* Fri Apr 25 2008 Rob Crittenden <rcritten@redhat.com> - 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 <rcritten@redhat.com> - 1.0.0-1
|
||||
- Update to upstream version 1.0.0
|
||||
|
||||
* Tue Mar 18 2008 Rob Crittenden <rcritten@redhat.com> 0.99-12
|
||||
- Pull upstream changelog 722
|
||||
- Add Conflicts mod_ssl (435360)
|
||||
|
||||
* Thu Feb 29 2008 Rob Crittenden <rcritten@redhat.com> 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 <rcritten@redhat.com> 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 <rcritten@redhat.com> 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 <rcritten@redhat.com> 0.99-8
|
||||
- Marked with wrong license. IPA is GPLv2.
|
||||
|
||||
* Tue Jan 29 2008 Rob Crittenden <rcritten@redhat.com> 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 <rcritten@redhat.com> 0.99-6
|
||||
- Pull upstream changelog 608 which renamed several files
|
||||
|
||||
* Thu Jan 24 2008 Rob Crittenden <rcritten@redhat.com> 0.99-5
|
||||
- package the sessions dir /var/cache/ipa/sessions
|
||||
- Pull upstream changelog 597
|
||||
|
||||
* Thu Jan 24 2008 Rob Crittenden <rcritten@redhat.com> 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 <rcritten@redhat.com> 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 <rcritten@redhat.com> 0.99-2
|
||||
- Added auto* BuildRequires
|
||||
|
||||
* Mon Jan 21 2008 Rob Crittenden <rcritten@redhat.com> 0.99-1
|
||||
- Unified spec file
|
||||
|
||||
* Thu Jan 17 2008 Rob Crittenden <rcritten@redhat.com> - 0.6.0-2
|
||||
- Fixed License in specfile
|
||||
- Include files from /usr/lib/python*/site-packages/ipaserver
|
||||
|
||||
* Fri Dec 21 2007 Karl MacMillan <kmacmill@redhat.com> - 0.6.0-1
|
||||
- Version bump for release
|
||||
|
||||
* Wed Nov 21 2007 Karl MacMillan <kmacmill@mentalrootkit.com> - 0.5.0-1
|
||||
- Preverse mode on ipa-keytab-util
|
||||
- Version bump for relase and rpm name change
|
||||
|
||||
* Thu Nov 15 2007 Rob Crittenden <rcritten@redhat.com> - 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 <kmacmill@redhat.com> - 0.4.1-1
|
||||
- Version bump for release
|
||||
|
||||
* Wed Oct 31 2007 Karl MacMillan <kmacmill@redhat.com> - 0.4.0-6
|
||||
- Add dep for freeipa-admintools and acl
|
||||
|
||||
* Wed Oct 24 2007 Rob Crittenden <rcritten@redhat.com> - 0.4.0-5
|
||||
- Add dependency for python-krbV
|
||||
|
||||
* Fri Oct 19 2007 Rob Crittenden <rcritten@redhat.com> - 0.4.0-4
|
||||
- Require mod_nss-1.0.7-2 for mod_proxy fixes
|
||||
|
||||
* Thu Oct 18 2007 Karl MacMillan <kmacmill@redhat.com> - 0.4.0-3
|
||||
- Convert to autotools-based build
|
||||
|
||||
* Tue Sep 25 2007 Karl MacMillan <kmacmill@redhat.com> - 0.4.0-2
|
||||
|
||||
* Fri Sep 7 2007 Karl MacMillan <kmacmill@redhat.com> - 0.3.0-1
|
||||
- Added support for libipa-dna-plugin
|
||||
|
||||
* Fri Aug 10 2007 Karl MacMillan <kmacmill@redhat.com> - 0.2.0-1
|
||||
- Added support for ipa_kpasswd and ipa_pwd_extop
|
||||
|
||||
* Mon Aug 5 2007 Rob Crittenden <rcritten@redhat.com> - 0.1.0-3
|
||||
- Abstracted client class to work directly or over RPC
|
||||
|
||||
* Wed Aug 1 2007 Rob Crittenden <rcritten@redhat.com> - 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 <kmacmill@redhat.com> - 0.1.0-1
|
||||
- Initial rpm version
|
53
install/Makefile.am
Normal file
53
install/Makefile.am
Normal file
@ -0,0 +1,53 @@
|
||||
# This file will be processed with automake-1.7 to create Makefile.in
|
||||
#
|
||||
AUTOMAKE_OPTIONS = 1.7
|
||||
|
||||
NULL =
|
||||
|
||||
SUBDIRS = \
|
||||
conf \
|
||||
html \
|
||||
migration \
|
||||
share \
|
||||
ui \
|
||||
tools \
|
||||
updates \
|
||||
po \
|
||||
$(NULL)
|
||||
|
||||
install-exec-local:
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
|
||||
chmod 700 $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
|
||||
mkdir -p $(DESTDIR)$(localstatedir)/cache/ipa/sessions
|
||||
chmod 700 $(DESTDIR)$(localstatedir)/cache/ipa/sessions
|
||||
|
||||
uninstall-local:
|
||||
-rmdir $(DESTDIR)$(localstatedir)/lib/ipa/sysrestore
|
||||
-rmdir $(DESTDIR)$(localstatedir)/lib/ipa
|
||||
-rmdir $(DESTDIR)$(localstatedir)/cache/ipa/sessions
|
||||
-rmdir $(DESTDIR)$(localstatedir)/cache/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)
|
15
install/README.schema
Normal file
15
install/README.schema
Normal file
@ -0,0 +1,15 @@
|
||||
Ground rules on adding new schema
|
||||
|
||||
Brand new schema, particularly when written specifically for IPA, should be
|
||||
added in share/*.ldif. Any new files need to be explicitly loaded in
|
||||
ipaserver/install/dsinstance.py. These simply get copied directly into
|
||||
the new instance schema directory.
|
||||
|
||||
Existing schema (e.g. in an LDAP draft) may either be added as a separate
|
||||
ldif in share or as an update in the updates directory. The advantage of
|
||||
adding the schema as an update is if 389-ds ever adds the schema then the
|
||||
installation won't fail due to existing schema failing to load during
|
||||
bootstrap.
|
||||
|
||||
If the new schema requires a new container then this should be added
|
||||
to install/bootstrap-template.ldif.
|
16
install/conf/Makefile.am
Normal file
16
install/conf/Makefile.am
Normal file
@ -0,0 +1,16 @@
|
||||
NULL =
|
||||
|
||||
appdir = $(IPA_DATA_DIR)
|
||||
app_DATA = \
|
||||
ipa.conf \
|
||||
ipa-pki-proxy.conf \
|
||||
ipa-rewrite.conf \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
27
install/conf/ipa-pki-proxy.conf
Normal file
27
install/conf/ipa-pki-proxy.conf
Normal file
@ -0,0 +1,27 @@
|
||||
# VERSION 1 - DO NOT REMOVE THIS LINE
|
||||
|
||||
ProxyRequests Off
|
||||
|
||||
# matches for ee port
|
||||
<LocationMatch "^/ca/ee/ca/checkRequest|^/ca/ee/ca/getCertChain|^/ca/ee/ca/getTokenInfo|^/ca/ee/ca/tokenAuthenticate|^/ca/ocsp|^/ca/ee/ca/updateNumberRange">
|
||||
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
|
||||
NSSVerifyClient none
|
||||
ProxyPassMatch ajp://localhost:9447/
|
||||
ProxyPassReverse ajp://localhost:9447/
|
||||
</LocationMatch>
|
||||
|
||||
# matches for admin port
|
||||
<LocationMatch "^/ca/admin/ca/getCertChain|^/ca/admin/ca/getConfigEntries|^/ca/admin/ca/getCookie|^/ca/admin/ca/getStatus|^/ca/admin/ca/securityDomainLogin|^/ca/admin/ca/getDomainXML">
|
||||
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
|
||||
NSSVerifyClient none
|
||||
ProxyPassMatch ajp://localhost:9447/
|
||||
ProxyPassReverse ajp://localhost:9447/
|
||||
</LocationMatch>
|
||||
|
||||
# matches for agent port and eeca port
|
||||
<LocationMatch "^/ca/agent/ca/displayBySerial|^/ca/agent/ca/doRevoke|^/ca/agent/ca/doUnrevoke|^/ca/agent/ca/updateDomainXML|^/ca/eeca/ca/profileSubmitSSLClient">
|
||||
NSSOptions +StdEnvVars +ExportCertData +StrictRequire +OptRenegotiate
|
||||
NSSVerifyClient require
|
||||
ProxyPassMatch ajp://localhost:9447/
|
||||
ProxyPassReverse ajp://localhost:9447/
|
||||
</LocationMatch>
|
21
install/conf/ipa-rewrite.conf
Normal file
21
install/conf/ipa-rewrite.conf
Normal file
@ -0,0 +1,21 @@
|
||||
# VERSION 2 - DO NOT REMOVE THIS LINE
|
||||
|
||||
RewriteEngine on
|
||||
RewriteLog /var/log/httpd/rewrite.log
|
||||
RewriteLogLevel 0
|
||||
|
||||
|
||||
# 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)
|
||||
RewriteRule ^/ipa/(.*) https://$FQDN/ipa/$$1 [L,R=301,NC]
|
121
install/conf/ipa.conf
Normal file
121
install/conf/ipa.conf
Normal file
@ -0,0 +1,121 @@
|
||||
#
|
||||
# VERSION 2 - DO NOT REMOVE THIS LINE
|
||||
#
|
||||
# LoadModule auth_kerb_module modules/mod_auth_kerb.so
|
||||
|
||||
ProxyRequests Off
|
||||
|
||||
|
||||
#We use xhtml, a file format that the browser validates
|
||||
DirectoryIndex index.html
|
||||
|
||||
|
||||
|
||||
# ipa-rewrite.conf is loaded separately
|
||||
|
||||
# This is required so the auto-configuration works with Firefox 2+
|
||||
AddType application/java-archive jar
|
||||
|
||||
|
||||
# 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 /var/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:
|
||||
<Location "/ipa/errors">
|
||||
SetHandler None
|
||||
</Location>
|
||||
<Location "/ipa/config">
|
||||
SetHandler None
|
||||
</Location>
|
||||
<Location "/ipa/crl">
|
||||
SetHandler None
|
||||
</Location>
|
||||
|
||||
|
||||
# Protect /ipa with Kerberos
|
||||
<Location "/ipa">
|
||||
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
|
||||
</Location>
|
||||
|
||||
|
||||
# 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
|
||||
<Directory "/usr/share/ipa/html">
|
||||
SetHandler None
|
||||
AllowOverride None
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
|
||||
# For CRL publishing
|
||||
Alias /ipa/crl "/var/lib/pki-ca/publish"
|
||||
<Directory "/var/lib/pki-ca/publish">
|
||||
SetHandler None
|
||||
AllowOverride None
|
||||
Options Indexes FollowSymLinks
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
|
||||
# webUI is now completely static, and served out of that directory
|
||||
Alias /ipa/ui "/usr/share/ipa/ui"
|
||||
<Directory "/usr/share/ipa/ui">
|
||||
SetHandler None
|
||||
AllowOverride None
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
|
||||
|
||||
# Protect our CGIs
|
||||
<Directory /var/www/cgi-bin>
|
||||
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
|
||||
</Directory>
|
||||
|
||||
|
||||
# migration related pages
|
||||
Alias /ipa/migration "/usr/share/ipa/migration"
|
||||
<Directory "/usr/share/ipa/migration">
|
||||
AllowOverride None
|
||||
Satisfy Any
|
||||
Allow from all
|
||||
Options ExecCGI
|
||||
AddHandler wsgi-script .py
|
||||
</Directory>
|
84
install/configure.ac
Normal file
84
install/configure.ac
Normal file
@ -0,0 +1,84 @@
|
||||
AC_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_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(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
|
||||
conf/Makefile
|
||||
html/Makefile
|
||||
migration/Makefile
|
||||
share/Makefile
|
||||
ui/Makefile
|
||||
tools/Makefile
|
||||
tools/man/Makefile
|
||||
updates/Makefile
|
||||
po/Makefile
|
||||
])
|
||||
|
||||
AC_OUTPUT
|
18
install/html/Makefile.am
Normal file
18
install/html/Makefile.am
Normal file
@ -0,0 +1,18 @@
|
||||
NULL =
|
||||
|
||||
appdir = $(IPA_SYSCONF_DIR)/html
|
||||
app_DATA = \
|
||||
ssbrowser.html \
|
||||
browserconfig.html \
|
||||
unauthorized.html \
|
||||
hbac-deny-remove.html \
|
||||
ipa_error.css \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
40
install/html/browserconfig.html
Normal file
40
install/html/browserconfig.html
Normal file
@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<script type="text/javascript" src="../ui/jquery.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_error.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
if (navigator.userAgent.indexOf("Firefox") != -1 ||
|
||||
navigator.userAgent.indexOf("SeaMonkey") != -1) {
|
||||
$('.textblockkrb').css('display', 'block');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
|
||||
<div class="textblockkrb" style="display: none;">
|
||||
<h1>Configure Browser</h1>
|
||||
<p> Click the below button to configure your browser </p>
|
||||
<object data="jar:/ipa/errors/configure.jar!/preferences.html"
|
||||
type="text/html" class="browser-config"></object>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
82
install/html/hbac-deny-remove.html
Normal file
82
install/html/hbac-deny-remove.html
Normal file
@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<script type="text/javascript" src="../ui/jquery.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_error.css" />
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
<div class="textblockkrb">
|
||||
<h1>Removal of HBAC Deny Rules.</h1>
|
||||
<p>FreeIPA has dropped support for DENY rules from the HBAC
|
||||
specification. </p>
|
||||
<p>The former design of HBAC specifies that<p>
|
||||
<ol>
|
||||
<li> If no ALLOW rules match, access is denied</li>
|
||||
<li> If one or more ALLOW rules match and no DENY rules match,
|
||||
access is allowed</li>
|
||||
<li>If one or more DENY rules match, access is denied</li>
|
||||
</ol>
|
||||
<p>Thus, DENY rules exist only to provide exceptions from the ALLOW
|
||||
rules. There exists no ALLOW+DENY combination that cannot be
|
||||
constructed from ALLOW rules only.[1]</P>
|
||||
|
||||
<p>DENY rules introduce a lot of edge-cases for evaluation. The most
|
||||
important of which is the availability of the group membership for
|
||||
the user logging in. Depending on the mechanism used to log in (for
|
||||
example, GSSAPI over SSH or cross-realm Kerberos trust where the
|
||||
user is provided by the PAC), SSSD's cache may not have a complete
|
||||
list of groups for this user. If the login is occurring during
|
||||
offline mode (where SSSD cannot contact the LDAP server to refresh
|
||||
the user's groups), SSSD cannot determine whether DENY rules would
|
||||
match for the user. This therefore translates into a potential
|
||||
security issue.</p>
|
||||
|
||||
<p>We implemented a workaround in the SSSD evaluator to resolve this by
|
||||
guaranteeing that we do a full lookup of all groups referenced by
|
||||
rules while we are retrieving the rules from FreeIPA. However, this
|
||||
requires at least one additional lookup against the LDAP server
|
||||
(possibly many if there is need to resolve nestings). This results
|
||||
in a significantly slower login while online.</p>
|
||||
|
||||
<p>We also have issues related to source host evaluation. Some
|
||||
applications will provide an IP address instead of a hostname in the
|
||||
pam_rhost attribute. Our only recourse here is to perform a
|
||||
reverse-DNS lookup to try and identify the real hostname(s) of the
|
||||
server. However, in many real-world environments, reverse DNS is
|
||||
unavailable or misconfigured. In the case of ALLOW rules, this would
|
||||
lead to a match failure and an implicit denial. However, a failure
|
||||
to properly match a DENY rule can result in unexpected access being
|
||||
granted. This is a potentially serious security issue.</p>
|
||||
|
||||
<p>Given these edge cases (and performance issues of the noted
|
||||
workaround), The FreeIPA team decided to drop DENY rules from the
|
||||
HBAC specification and limit HBAC only to ALLOW rules (which are
|
||||
much safer). Beyond the obvious advantages for our implementation,
|
||||
this should make it less complex for users to write their rules.</p>
|
||||
|
||||
<p>[1] Some rules are complex to simulate, such as "Allow access from
|
||||
all PAM services EXCEPT telnet". But a safer and clearer
|
||||
implementation approach does all access via whitelist. If a FreeIPA
|
||||
implementation is using an exception rule, the administrators
|
||||
should re-evaluate the justification.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
865
install/html/ipa_error.css
Normal file
865
install/html/ipa_error.css
Normal file
@ -0,0 +1,865 @@
|
||||
/* Authors:
|
||||
* Pavel Zuna <pzuna@redhat.com>
|
||||
* Adam Young <ayoung@redhat.com>
|
||||
* Endi Sukma Dewata <edewata@redhat.com>
|
||||
* Kyle Baker <kybaker@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat
|
||||
*/
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('../ui/overpass_regular-web.eot');
|
||||
src: url('../ui/overpass_regular-web.eot?#iefix') format('eot'),
|
||||
url('../ui/overpass_regular-web.woff') format('woff'),
|
||||
url('../ui/overpass_regular-web.ttf') format('truetype'),
|
||||
url('../ui/overpass_regular-web.svg#webfontLTZe4IYH') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass Bold';
|
||||
src: url('../ui/overpass_bold-web.eot');
|
||||
src: url('../ui/overpass_bold-web.eot?#iefix') format('eot'),
|
||||
url('../ui/overpass_bold-web.woff') format('woff'),
|
||||
url('../ui/overpass_bold-web.ttf') format('truetype'),
|
||||
url('../ui/overpass_bold-web.svg#webfontzAU82Ltw') format('svg');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
body{
|
||||
background-image:url("../ui/outer-bg.png");
|
||||
background-repeat:repeat-x;
|
||||
background-position:left top;
|
||||
background-color:#F9F9F9;
|
||||
border-width: 0;
|
||||
font-family:"Liberation Sans",Arial,Sans;
|
||||
font-size:11px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.center-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
.ui-widget {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.input_link {
|
||||
padding: .4em 1em .4em 2em;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input_link span.ui-icon {
|
||||
-moz-border-radius: 0.3em;
|
||||
border: 1px solid #B8B8B8;
|
||||
margin: -0.9em 0.4em 0em -0.3em;
|
||||
position: absolute;
|
||||
left: .2em;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
/* ---- Header ---- */
|
||||
div.header {
|
||||
background-color:#0C3B00;
|
||||
width: 100%;
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
div.header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.header a:link {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.header a:visited {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.header span.header-logo {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
div.header span.header-logo a img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.header span.header-loggedinas {
|
||||
width: 96em;
|
||||
color: #fff;
|
||||
display: block;
|
||||
padding-left: 71em;
|
||||
margin-top: -2.6em;
|
||||
margin-left: auto;
|
||||
margin-right: 27.6em;
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
/* ---- Navigation ---- */
|
||||
div.tabs {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 40em;
|
||||
}
|
||||
|
||||
div#content {
|
||||
margin-top: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
div.content div.content-buttons {
|
||||
float: right;
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
div.content div.content-buttons img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: normal;
|
||||
color: #333333;
|
||||
text-transform: uppercase;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.section-expand{
|
||||
float:left;
|
||||
-moz-border-radius: 0.3em;
|
||||
background-color: -moz-linear-gradient(top, #959595, #5e5e5e);
|
||||
border: 1px solid #b8b8b8;
|
||||
color: #fff;
|
||||
margin-right: 0.5em;
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: #EEEEEE;
|
||||
clear: both;
|
||||
color: #FFFFFF;
|
||||
height: 0.1em;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.details-section {
|
||||
margin-left: 4.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-top: 1.8em;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 1.8em;
|
||||
padding-right: 1.8em;
|
||||
}
|
||||
|
||||
.undo {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
dl.entryattrs {
|
||||
clear: both;
|
||||
margin-left: 1.5em;
|
||||
margin-top: 1.8em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
dl.entryattrs dt {
|
||||
clear: left;
|
||||
float: left;
|
||||
padding-bottom: 1.8em;
|
||||
padding-right: 1.8em;
|
||||
text-align: right;
|
||||
width: 16em;
|
||||
margin: 0.5em -0.5em 0 -6em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd {
|
||||
float: left;
|
||||
padding-bottom: 1.8em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd.first {
|
||||
margin-left: 0;
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd.other {
|
||||
clear: both;
|
||||
margin-left: 10.7em;
|
||||
}
|
||||
|
||||
dl.entryattrs input {
|
||||
margin-right: 0.5em;
|
||||
margin-top: -1.2em;
|
||||
min-width: 27.5em;
|
||||
}
|
||||
|
||||
|
||||
span.attrhint {
|
||||
font-size: 8pt;
|
||||
left: 5em;
|
||||
margin-left: 12.5em;
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
|
||||
/*Navigation */
|
||||
.tabs1 .ui-tabs-nav{
|
||||
padding-left: 2.5em;
|
||||
padding-top: 2em;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-image: url("../ui/Mainnav-background.png");
|
||||
-moz-border-radius: 0;
|
||||
}
|
||||
|
||||
.ui-tabs {
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#the positions for these are in the large icon image,
|
||||
#and need to be specified in pixels.
|
||||
.ui-icon-plus {
|
||||
background-position: -16px -129px;
|
||||
}
|
||||
|
||||
.ui-icon-minus {
|
||||
background-position: -48px -129px;
|
||||
}
|
||||
|
||||
.ui-icon-trash {
|
||||
background-position: -176px -97px;
|
||||
}
|
||||
|
||||
.ui-widget-content .ui-icon {
|
||||
background-image: url("../ui/ui-icons_222222_256x240.png");
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
.ui-widget-content {
|
||||
}
|
||||
|
||||
|
||||
.ui-widget-content a {
|
||||
text-decoration: none;
|
||||
color: #1d85d5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.ui-widget-header {
|
||||
background: url("../ui/modal-background.png") repeat scroll 50% 50% #1f9123;
|
||||
border: 1px solid #244c16;
|
||||
color: #EEEEEE;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.ui-widget input, .ui-widget select,
|
||||
.ui-widget textarea, .ui-widget button {
|
||||
font-family: "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.3em;
|
||||
margin-right: .1em;
|
||||
}
|
||||
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
|
||||
-moz-border-radius: .3em;
|
||||
background: -moz-linear-gradient(top, #959595, #5e5e5e);
|
||||
border: 1px solid #777777;
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li {
|
||||
-moz-border-radius: 0 !important;
|
||||
background-image: url("../ui/Mainnav-offtab.png");
|
||||
margin: 0;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
vertical-align:baseline;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li.ui-tabs-selected {
|
||||
padding: 0 0;
|
||||
background-image: url("../ui/Mainnav-ontab.png");
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li a{
|
||||
-moz-border-radius: 0 !important;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
width:5.5em;
|
||||
padding: none;
|
||||
color: #7E7E7E;
|
||||
margin: 0 auto;
|
||||
text-align:center;
|
||||
font-size:1.5em;
|
||||
}
|
||||
|
||||
|
||||
.tabs1 .ui-tabs-nav li > a:link, span.main-nav-off > a:visited{
|
||||
color: #7E7E7E;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li.ui-tabs-selected a{
|
||||
color: #3D752A;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-panel {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
padding: 0 0 0 0;
|
||||
background: none;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav {
|
||||
padding: 0.3em 6em 0 4em;
|
||||
margin: 0;
|
||||
height: 2.4em;
|
||||
background-image: url("../ui/Subnav-background.png");
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li {
|
||||
width:auto;
|
||||
padding-left: 1em;
|
||||
margin: 0;
|
||||
background: #326122 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li.ui-tabs-selected {
|
||||
padding-left: 1em;
|
||||
height: 1em;
|
||||
background: #326122 !important;
|
||||
}
|
||||
|
||||
|
||||
.tabs2 .ui-tabs-nav li a{
|
||||
width:auto;
|
||||
padding: 0.4em 0.6em ;
|
||||
-moz-border-radius: 2em !important;
|
||||
border-radius: 2em !important;
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
font-family: "Liberation Sans", Arial, Sans;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li > a:link, span.main-nav-off > a:visited{
|
||||
color:white;
|
||||
}
|
||||
|
||||
|
||||
.tabs2 .ui-tabs-nav li a:hover{
|
||||
background: none repeat scroll 0 0 #1C3612;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li.ui-tabs-selected a{
|
||||
background: none repeat scroll 0 0 #1C3612;
|
||||
color: white;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Entity */
|
||||
|
||||
.entity-container{
|
||||
position: relative;
|
||||
left: 22em;
|
||||
width: 80%;
|
||||
margin: 0.06em;
|
||||
padding: 0.06em;
|
||||
background: #e8e8e8;
|
||||
}
|
||||
|
||||
.action-panel {
|
||||
position: fixed;
|
||||
height: 33em;
|
||||
left: auto;
|
||||
border: none;
|
||||
float: none;
|
||||
margin-top: 6.3em;
|
||||
margin-left: -19.5em;
|
||||
margin-right: 0;
|
||||
padding-left: 0;
|
||||
position: fixed;
|
||||
width: 18em;
|
||||
background-image:url("../ui/panel-background.png");
|
||||
background-repeat:no-repeat;
|
||||
background-position:right;
|
||||
}
|
||||
|
||||
.action-panel h3{
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
background: #EEEEEE;
|
||||
padding: .5em;
|
||||
border-right: 1px solid #dfdfdf;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.action-panel ul {
|
||||
list-style-type:none;
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
.action-panel h3{
|
||||
margin: 0;
|
||||
background: #e8e8e8;
|
||||
}
|
||||
|
||||
.action-panel li {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.1em;
|
||||
color: #1d85d5;
|
||||
list-style-type: none;
|
||||
min-height: 2.1em;
|
||||
padding: none;
|
||||
}
|
||||
|
||||
.action-panel li.search-facet {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: #1D85D5;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet {
|
||||
font-family: "Liberation Sans",Arial,sans-serif;
|
||||
color: #1d85d5;
|
||||
cursor: pointer;
|
||||
margin-left:1.2em;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-selected {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: black;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-disabled {
|
||||
font-family: "Liberation Sans",Arial,sans-serif;
|
||||
color: gray;
|
||||
cursor: default;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-relation-label {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: #8a8a8a;
|
||||
cursor: default;
|
||||
text-transform: uppercase;
|
||||
margin-left:1.8em;
|
||||
}
|
||||
|
||||
.action-panel li.facet-group-member {
|
||||
margin-left: 2.9em
|
||||
}
|
||||
|
||||
|
||||
.action-button {
|
||||
background: none;
|
||||
background-image:none;
|
||||
font-family: "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.action-controls {
|
||||
position: relative;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.client {
|
||||
font-size: 10px;
|
||||
margin-top: 0.4em;
|
||||
float: left;
|
||||
min-width: 70em;
|
||||
}
|
||||
|
||||
/* Migration */
|
||||
|
||||
body#header-bg {
|
||||
background: url("../ui/Static-Background.png") repeat-x scroll left top #EDEDED;
|
||||
}
|
||||
|
||||
.container_1 {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 960px;
|
||||
background: url("../ui/centered-bg.png") no-repeat scroll 0 7em transparent;
|
||||
min-height: 40em;
|
||||
}
|
||||
|
||||
#formwindow {
|
||||
-moz-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;
|
||||
}
|
||||
|
||||
.formcontent {
|
||||
padding: 0 1em 2em 2em;
|
||||
}
|
||||
|
||||
#error-box {
|
||||
-moz-border-radius: 0.3em 0.3em 0.3em 0.3em;
|
||||
background-color: #FFEBE8;
|
||||
border: 1px solid #DD3C10;
|
||||
margin: 0 2em 1em;
|
||||
padding: 1em 1em 0 0;
|
||||
}
|
||||
|
||||
.# {
|
||||
background: url("../ui/ipalogo.png") no-repeat scroll left top transparent;
|
||||
border: none;
|
||||
float: left;
|
||||
height: 36px;
|
||||
width: 205px;
|
||||
}
|
||||
|
||||
#formwindow h4 {
|
||||
background-color: #F0F0F0;
|
||||
font-size: 1.6em;
|
||||
padding: 18px 15px 14px 22px;
|
||||
text-transform: uppercase;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#login li {
|
||||
padding-bottom: 15px;
|
||||
text-align: right;
|
||||
width: 370px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#login li input {
|
||||
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) inset;
|
||||
margin-left: 15px;
|
||||
padding: 2px 10px;
|
||||
width: 248px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.formbutton input {
|
||||
float: right;
|
||||
margin: 1em 1em 1em 0;
|
||||
-moz-border-radius: 0.3em 0.3em 0.3em 0.3em;
|
||||
background: -moz-linear-gradient(center top, #959595, #5e5e5e) repeat scroll 0 0 transparent;
|
||||
border: 1px solid #777777;
|
||||
color: #ffffff;
|
||||
font-weight: normal;
|
||||
padding: 0.5em 0.8em;
|
||||
}
|
||||
|
||||
.textblock {
|
||||
text-align: center;
|
||||
margin-top: 6em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.textblockkrb {
|
||||
text-align: left;
|
||||
margin-top: 5em;
|
||||
font-size: 1.1em;
|
||||
padding-left: 3em;
|
||||
padding-right: 3em;
|
||||
}
|
||||
|
||||
.textblockkrb ul li {
|
||||
list-style-type: none;
|
||||
padding: .15em;
|
||||
}
|
||||
|
||||
|
||||
h3 {
|
||||
color: #333333;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: #333333;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 3em;
|
||||
margin-left: 5em;
|
||||
margin-top: -3em;
|
||||
}
|
||||
|
||||
/* Browser configuration */
|
||||
|
||||
object.browser-config {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Search */
|
||||
|
||||
.search-controls {
|
||||
-moz-border-radius: .7em .7em 0 0;
|
||||
height:2.5em;
|
||||
background: -moz-linear-gradient(top, #eeeeee, #dfdfdf);
|
||||
position: relative;
|
||||
padding: 1em 1.5em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.search-table > a:link,a:visted{
|
||||
color:black;
|
||||
}
|
||||
|
||||
.search-table{
|
||||
padding: 0;
|
||||
width:100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.search-table td{
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.search-table th{
|
||||
padding-left: 0.5em;
|
||||
background-color:#f6f6f6;
|
||||
color:#333333;
|
||||
text-align: left;
|
||||
border: 1px solid #dfdfdf;
|
||||
}
|
||||
|
||||
.search-table tfoot tr td span{
|
||||
border-top: 1px solid #dfdfdf;
|
||||
padding: 0.9em 0 0 1em;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.search-table tr:nth-child(even){
|
||||
# background-color:#CCC;
|
||||
}
|
||||
|
||||
.search-table tr:nth-child(odd){
|
||||
# background-color:#FFF;
|
||||
}
|
||||
|
||||
.entity-views{
|
||||
list-style-type:none;
|
||||
}
|
||||
|
||||
.entity-views li {
|
||||
display:inline;
|
||||
cursor: pointer;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
.strikethrough { text-decoration: line-through; }
|
||||
|
||||
|
||||
.key-status-valid {
|
||||
list-style-type: circle;
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.key-status-missing {
|
||||
list-style-type: circle;
|
||||
color: #daa520;
|
||||
}
|
||||
|
||||
.key-status-active {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.certificate-status-valid {
|
||||
list-style-type: circle;
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.certificate-status-revoked {
|
||||
list-style-type: circle;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.certificate-status-missing {
|
||||
list-style-type: circle;
|
||||
color: #daa520;
|
||||
}
|
||||
|
||||
.certificate-status-active {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
dl.modal {
|
||||
clear: both;
|
||||
margin-left: 1em;
|
||||
margin-top: 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
dl.modal dt {
|
||||
clear: left;
|
||||
float: left;
|
||||
padding-bottom: 0;
|
||||
padding-right: 0;
|
||||
text-align: right;
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
dl.modal dd {
|
||||
float: left;
|
||||
padding-bottom: 0;
|
||||
margin-left: 0.8em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ui-widget-content {
|
||||
border:0;
|
||||
}
|
||||
|
||||
table.scrollable thead {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.scrollable tbody {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adder-dialog-filter {
|
||||
height: 2.5em;
|
||||
}
|
||||
|
||||
.adder-dialog-results {
|
||||
position: relative;
|
||||
height: 20.0em;
|
||||
}
|
||||
|
||||
.adder-dialog-available {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 25.0em;
|
||||
}
|
||||
|
||||
.adder-dialog-buttons {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
left: 25em;
|
||||
right: 25;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.adder-dialog-selected {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.adder-dialog-internal {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 4.5em;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.adder-dialog-external {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 25em;
|
||||
height: 4em;
|
||||
}
|
66
install/html/ssbrowser.html
Normal file
66
install/html/ssbrowser.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<script type="text/javascript" src="../ui/jquery.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_error.css" />
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
<div class="textblockkrb">
|
||||
<h3>Browser Kerberos Setup</h3>
|
||||
<img alt="Internet Explorer" src="../ui/ie-icon.png"><h5>Internet Explorer Configuration</h5>
|
||||
<p>Once you are able to log into the workstation with your kerberos key you are now able to use that ticket in Internet Explorer. </p>
|
||||
|
||||
<strong>Login to the Windows machine using an account of your Kerberos realm (administrative domain)</strong><br>
|
||||
<strong>In Internet Explorer, click Tools, and then click Internet Options.</strong>
|
||||
<br>
|
||||
<ul>
|
||||
<li> 1. Click the Security tab </li>
|
||||
<li> 2. Click Local intranet </li>
|
||||
<li> 3. Click Sites </li>
|
||||
<li> 4. Click Advanced </li>
|
||||
<li> 5. Add your domain to the list </li>
|
||||
<br>
|
||||
<li> 1. Click the Security tab </li>
|
||||
<li> 2. Click Local intranet </li>
|
||||
<li> 3. Click Custom Level </li>
|
||||
<li> 4. Select Automatic logon only in Intranet zone </li>
|
||||
<br>
|
||||
<li> Visit a kerberized web site using IE (You must use the fully-qualified Domain Name in the URL)</li>
|
||||
<li><strong> You are all set. </strong></li>
|
||||
</ul>
|
||||
|
||||
<br>
|
||||
|
||||
<img alt="Firefox" src="../ui/firefox-icon.png"><h5>Firefox Configuration</h5>
|
||||
|
||||
<p>You can configure Firefox to use Kerberos for Single Sign-on. The following instructions will guide you in configuring your web browser <br>
|
||||
to send your Kerberos credentials to the appropriate Key Distribution Center which enables Single Sign-on. </p>
|
||||
|
||||
<ul><li> 1. In the address bar of Firefox, type <tt>about:config</tt> to display the list of current configuration options.</li>
|
||||
<li> 2. In the Filter field, type <tt>negotiate</tt> to restrict the list of options. </li>
|
||||
<li> 3. Double-click the <tt>network.negotiate-auth.trusted-uris</tt> entry to display the Enter string value dialog box. </li>
|
||||
<li> 4. Enter the name of the domain against which you want to authenticate, for example, <tt>.example.com.</tt> </li>
|
||||
<li> 5. Repeat the above procedure for the <tt>network.negotiate-auth.delegation-uris</tt> entry, using the same domain. </li>
|
||||
<br>
|
||||
<li><strong> You are all set. </strong></li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
58
install/html/unauthorized.html
Normal file
58
install/html/unauthorized.html
Normal file
@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<script type="text/javascript" src="../ui/jquery.js"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_error.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
$("#import-cert-auth-link").click(function() {
|
||||
$("#first-time").css("display", "none");
|
||||
$("#next-link").css("display", "block");
|
||||
return true;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
|
||||
<div class="textblockkrb">
|
||||
<h1>Unable to verify your Kerberos credentials</h1>
|
||||
<p>
|
||||
Please make sure that you have valid Kerberos tickets (obtainable via <b>kinit</b>),
|
||||
and that you have configured your browser correctly.
|
||||
</p>
|
||||
|
||||
<div id="first-time">
|
||||
<b>If this is your first time:</b>
|
||||
<ul>
|
||||
<li><a id="import-cert-auth-link" href="/ipa/errors/ca.crt">Click here to
|
||||
Import the IPA Certificate Authority.</a></li>
|
||||
<li>Make sure you select <b>all three</b> checkboxes.</li>
|
||||
<li>Click the <b>OK</b> Button.</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="next-link" style="display: none;">
|
||||
<p><a href="browserconfig.html">Click here to continue.</a></p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
18
install/migration/Makefile.am
Normal file
18
install/migration/Makefile.am
Normal file
@ -0,0 +1,18 @@
|
||||
NULL =
|
||||
|
||||
appdir = $(IPA_DATA_DIR)/migration
|
||||
app_DATA = \
|
||||
error.html \
|
||||
index.html \
|
||||
invalid.html \
|
||||
ipa_migration.css \
|
||||
migration.py \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(app_DATA) \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
*~ \
|
||||
Makefile.in
|
35
install/migration/error.html
Normal file
35
install/migration/error.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_migration.css" />
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div id="formwindow">
|
||||
<h4>We're Sorry</h4>
|
||||
<div class="formcontent">
|
||||
<p>
|
||||
<strong>There was a problem with your request. Please, try again later.</strong>
|
||||
</p>
|
||||
<p>
|
||||
<label>If the problem persists, contact your administrator.</label>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
50
install/migration/index.html
Normal file
50
install/migration/index.html
Normal file
@ -0,0 +1,50 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="../ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_migration.css" />
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
<div class="textblock">
|
||||
<h3>Password Migration</h3>
|
||||
<p>If you have been sent here by your administrator, your personal
|
||||
information is being migrated to a new identity management solution
|
||||
(IPA).</p>
|
||||
<p>Please, enter your credentials in the form below to complete the
|
||||
process. Upon successful login your kerberos account will be
|
||||
activated.</p>
|
||||
</div>
|
||||
<div id="formwindow">
|
||||
<h4>Login</h4>
|
||||
<form id="login" action="migration.py" method="post" name="">
|
||||
<ul>
|
||||
<li>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" name="username" value="" accesskey="u" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" name="password" value="" accesskey="p" />
|
||||
</li>
|
||||
<ul>
|
||||
<div class="formbutton">
|
||||
<input name="submit" value="Migrate" type="submit" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
57
install/migration/invalid.html
Normal file
57
install/migration/invalid.html
Normal file
@ -0,0 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>IPA: Identity Policy Audit</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="..ui/jquery-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="ipa_migration.css" />
|
||||
</head>
|
||||
|
||||
<body id="header-bg">
|
||||
|
||||
<div class="container_1">
|
||||
<div class="header-logo">
|
||||
<img src="../ui/ipalogo.png" /><img src="../ui/ipabanner.png" />
|
||||
</div>
|
||||
<div class="textblock">
|
||||
<h3>Password Migration</h3>
|
||||
<p>If you have been sent here by your administrator, your personal
|
||||
information is being migrated to a new identity management solution
|
||||
(IPA).</p>
|
||||
<p>Please, enter your credentials in the form below to complete the
|
||||
process. Upon successful login your kerberos account will be
|
||||
activated.</p>
|
||||
</div>
|
||||
<div id="formwindow">
|
||||
<h4>Login</h4>
|
||||
<div id="error-box">
|
||||
<div class="formcontent">
|
||||
<p><strong>Please re-enter your username or password</strong></p>
|
||||
<p>The password or username you entered is incorrect. Please try again (make sure your caps lock is off).</p>
|
||||
<p>If the problem persists, contact your administrator.</p>
|
||||
</div>
|
||||
</div>
|
||||
<form id="login" action="migration.py" method="post" name="">
|
||||
<ul>
|
||||
<li>
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" name="username" value="" accesskey="u" />
|
||||
</li>
|
||||
<li>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" name="password" value="" accesskey="p" />
|
||||
</li>
|
||||
<ul>
|
||||
<div class="formbutton">
|
||||
<input name="submit" value="Migrate" type="submit" />
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
863
install/migration/ipa_migration.css
Normal file
863
install/migration/ipa_migration.css
Normal file
@ -0,0 +1,863 @@
|
||||
/* Authors:
|
||||
* Pavel Zuna <pzuna@redhat.com>
|
||||
* Adam Young <ayoung@redhat.com>
|
||||
* Endi Sukma Dewata <edewata@redhat.com>
|
||||
* Kyle Baker <kybaker@redhat.com>
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat
|
||||
*/
|
||||
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass';
|
||||
src: url('../ui/overpass_regular-web.eot');
|
||||
src: url('../ui/overpass_regular-web.eot?#iefix') format('eot'),
|
||||
url('../ui/overpass_regular-web.woff') format('woff'),
|
||||
url('../ui/overpass_regular-web.ttf') format('truetype'),
|
||||
url('../ui/overpass_regular-web.svg#webfontLTZe4IYH') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Overpass Bold';
|
||||
src: url('../ui/overpass_bold-web.eot');
|
||||
src: url('../ui/overpass_bold-web.eot?#iefix') format('eot'),
|
||||
url('../ui/overpass_bold-web.woff') format('woff'),
|
||||
url('../ui/overpass_bold-web.ttf') format('truetype'),
|
||||
url('../ui/overpass_bold-web.svg#webfontzAU82Ltw') format('svg');
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
|
||||
}
|
||||
|
||||
body{
|
||||
background-image:url("../ui/outer-bg.png");
|
||||
background-repeat:repeat-x;
|
||||
background-position:left top;
|
||||
background-color:#F9F9F9;
|
||||
border-width: 0;
|
||||
font-family:"Liberation Sans",Arial,Sans;
|
||||
font-size:11px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.center-container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
.ui-widget {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.input_link {
|
||||
padding: .4em 1em .4em 2em;
|
||||
text-decoration: none;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.input_link span.ui-icon {
|
||||
-moz-border-radius: 0.3em;
|
||||
border: 1px solid #B8B8B8;
|
||||
margin: -0.9em 0.4em 0em -0.3em;
|
||||
position: absolute;
|
||||
left: .2em;
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
/* ---- Header ---- */
|
||||
div.header {
|
||||
background-color:#0C3B00;
|
||||
width: 100%;
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
div.header a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
div.header a:link {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.header a:visited {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.header span.header-logo {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
div.header span.header-logo a img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.header span.header-loggedinas {
|
||||
width: 96em;
|
||||
color: #fff;
|
||||
display: block;
|
||||
padding-left: 71em;
|
||||
margin-top: -2.6em;
|
||||
margin-left: auto;
|
||||
margin-right: 27.6em;
|
||||
width: 20em;
|
||||
}
|
||||
|
||||
/* ---- Navigation ---- */
|
||||
div.tabs {
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 40em;
|
||||
}
|
||||
|
||||
div#content {
|
||||
margin-top: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
div.content div.content-buttons {
|
||||
float: right;
|
||||
margin-right: 1.5em;
|
||||
}
|
||||
|
||||
div.content div.content-buttons img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: "Overpass Bold","Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: normal;
|
||||
color: #333333;
|
||||
text-transform: uppercase;
|
||||
margin-left: 1em;
|
||||
margin-bottom: 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.section-expand{
|
||||
float:left;
|
||||
-moz-border-radius: 0.3em;
|
||||
background-color: -moz-linear-gradient(top, #959595, #5e5e5e);
|
||||
border: 1px solid #b8b8b8;
|
||||
color: #fff;
|
||||
margin-right: 0.5em;
|
||||
margin-top: 0.1em;
|
||||
}
|
||||
|
||||
hr {
|
||||
background-color: #EEEEEE;
|
||||
clear: both;
|
||||
color: #FFFFFF;
|
||||
height: 0.1em;
|
||||
margin-left: 1.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.details-section {
|
||||
margin-left: 4.5em;
|
||||
margin-right: 1.5em;
|
||||
margin-top: 1.8em;
|
||||
white-space: nowrap;
|
||||
padding-bottom: 1.8em;
|
||||
padding-right: 1.8em;
|
||||
}
|
||||
|
||||
.undo {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
dl.entryattrs {
|
||||
clear: both;
|
||||
margin-left: 1.5em;
|
||||
margin-top: 1.8em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
dl.entryattrs dt {
|
||||
clear: left;
|
||||
float: left;
|
||||
padding-bottom: 1.8em;
|
||||
padding-right: 1.8em;
|
||||
text-align: right;
|
||||
width: 16em;
|
||||
margin: 0.5em -0.5em 0 -6em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd {
|
||||
float: left;
|
||||
padding-bottom: 1.8em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd.first {
|
||||
margin-left: 0;
|
||||
margin-top: 0.7em;
|
||||
}
|
||||
|
||||
dl.entryattrs dd.other {
|
||||
clear: both;
|
||||
margin-left: 10.7em;
|
||||
}
|
||||
|
||||
dl.entryattrs input {
|
||||
margin-right: 0.5em;
|
||||
margin-top: -1.2em;
|
||||
min-width: 27.5em;
|
||||
}
|
||||
|
||||
|
||||
span.attrhint {
|
||||
font-size: 8pt;
|
||||
left: 5em;
|
||||
margin-left: 12.5em;
|
||||
position: absolute;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
|
||||
/*Navigation */
|
||||
.tabs1 .ui-tabs-nav{
|
||||
padding-left: 2.5em;
|
||||
padding-top: 2em;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-image: url("../ui/Mainnav-background.png");
|
||||
-moz-border-radius: 0;
|
||||
}
|
||||
|
||||
.ui-tabs {
|
||||
padding:0;
|
||||
}
|
||||
|
||||
#the positions for these are in the large icon image,
|
||||
#and need to be specified in pixels.
|
||||
.ui-icon-plus {
|
||||
background-position: -16px -129px;
|
||||
}
|
||||
|
||||
.ui-icon-minus {
|
||||
background-position: -48px -129px;
|
||||
}
|
||||
|
||||
.ui-icon-trash {
|
||||
background-position: -176px -97px;
|
||||
}
|
||||
|
||||
.ui-widget-content .ui-icon {
|
||||
background-image: url("../ui/ui-icons_222222_256x240.png");
|
||||
background-color: #e2e2e2;
|
||||
}
|
||||
|
||||
.ui-widget-content {
|
||||
}
|
||||
|
||||
|
||||
.ui-widget-content a {
|
||||
text-decoration: none;
|
||||
color: #1d85d5;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.ui-widget-header {
|
||||
background: url("../ui/modal-background.png") repeat scroll 50% 50% #1f9123;
|
||||
border: 1px solid #244c16;
|
||||
color: #EEEEEE;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav {
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
.ui-widget input, .ui-widget select,
|
||||
.ui-widget textarea, .ui-widget button {
|
||||
font-family: "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.3em;
|
||||
margin-right: .1em;
|
||||
}
|
||||
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default {
|
||||
-moz-border-radius: .3em;
|
||||
background: -moz-linear-gradient(top, #959595, #5e5e5e);
|
||||
border: 1px solid #777777;
|
||||
color: #fff;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li {
|
||||
-moz-border-radius: 0 !important;
|
||||
background-image: url("../ui/Mainnav-offtab.png");
|
||||
margin: 0;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
vertical-align:baseline;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li.ui-tabs-selected {
|
||||
padding: 0 0;
|
||||
background-image: url("../ui/Mainnav-ontab.png");
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li a{
|
||||
-moz-border-radius: 0 !important;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
width:5.5em;
|
||||
padding: none;
|
||||
color: #7E7E7E;
|
||||
margin: 0 auto;
|
||||
text-align:center;
|
||||
font-size:1.5em;
|
||||
}
|
||||
|
||||
|
||||
.tabs1 .ui-tabs-nav li > a:link, span.main-nav-off > a:visited{
|
||||
color: #7E7E7E;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-nav li.ui-tabs-selected a{
|
||||
color: #3D752A;
|
||||
}
|
||||
|
||||
.tabs1 .ui-tabs-panel {
|
||||
display: block;
|
||||
border-width: 0;
|
||||
padding: 0 0 0 0;
|
||||
background: none;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav {
|
||||
padding: 0.3em 6em 0 4em;
|
||||
margin: 0;
|
||||
height: 2.4em;
|
||||
background-image: url("../ui/Subnav-background.png");
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li {
|
||||
width:auto;
|
||||
padding-left: 1em;
|
||||
margin: 0;
|
||||
background: #326122 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li.ui-tabs-selected {
|
||||
padding-left: 1em;
|
||||
height: 1em;
|
||||
background: #326122 !important;
|
||||
}
|
||||
|
||||
|
||||
.tabs2 .ui-tabs-nav li a{
|
||||
width:auto;
|
||||
padding: 0.4em 0.6em ;
|
||||
-moz-border-radius: 2em !important;
|
||||
border-radius: 2em !important;
|
||||
color: white;
|
||||
font-size: 1em;
|
||||
font-family: "Liberation Sans", Arial, Sans;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li > a:link, span.main-nav-off > a:visited{
|
||||
color:white;
|
||||
}
|
||||
|
||||
|
||||
.tabs2 .ui-tabs-nav li a:hover{
|
||||
background: none repeat scroll 0 0 #1C3612;
|
||||
}
|
||||
|
||||
.tabs2 .ui-tabs-nav li.ui-tabs-selected a{
|
||||
background: none repeat scroll 0 0 #1C3612;
|
||||
color: white;
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Entity */
|
||||
|
||||
.entity-container{
|
||||
position: relative;
|
||||
left: 22em;
|
||||
width: 80%;
|
||||
margin: 0.06em;
|
||||
padding: 0.06em;
|
||||
background: #e8e8e8;
|
||||
}
|
||||
|
||||
.action-panel {
|
||||
position: fixed;
|
||||
height: 33em;
|
||||
left: auto;
|
||||
border: none;
|
||||
float: none;
|
||||
margin-top: 6.3em;
|
||||
margin-left: -19.5em;
|
||||
margin-right: 0;
|
||||
padding-left: 0;
|
||||
position: fixed;
|
||||
width: 18em;
|
||||
background-image:url("../ui/panel-background.png");
|
||||
background-repeat:no-repeat;
|
||||
background-position:right;
|
||||
}
|
||||
|
||||
.action-panel h3{
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
background: #EEEEEE;
|
||||
padding: .5em;
|
||||
border-right: 1px solid #dfdfdf;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.action-panel ul {
|
||||
list-style-type:none;
|
||||
padding-left: .5em;
|
||||
}
|
||||
|
||||
.action-panel h3{
|
||||
margin: 0;
|
||||
background: #e8e8e8;
|
||||
}
|
||||
|
||||
.action-panel li {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.1em;
|
||||
color: #1d85d5;
|
||||
list-style-type: none;
|
||||
min-height: 2.1em;
|
||||
padding: none;
|
||||
}
|
||||
|
||||
.action-panel li.search-facet {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: #1D85D5;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet {
|
||||
font-family: "Liberation Sans",Arial,sans-serif;
|
||||
color: #1d85d5;
|
||||
cursor: pointer;
|
||||
margin-left:1.2em;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-selected {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: black;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-disabled {
|
||||
font-family: "Liberation Sans",Arial,sans-serif;
|
||||
color: gray;
|
||||
cursor: default;
|
||||
text-decoration: none;
|
||||
text-transform: none;
|
||||
|
||||
}
|
||||
|
||||
.action-panel li.entity-facet-relation-label {
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, Sans;
|
||||
color: #8a8a8a;
|
||||
cursor: default;
|
||||
text-transform: uppercase;
|
||||
margin-left:1.8em;
|
||||
}
|
||||
|
||||
.action-panel li.facet-group-member {
|
||||
margin-left: 2.9em
|
||||
}
|
||||
|
||||
|
||||
.action-button {
|
||||
background: none;
|
||||
background-image:none;
|
||||
font-family: "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.action-controls {
|
||||
position: relative;
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.client {
|
||||
font-size: 10px;
|
||||
margin-top: 0.4em;
|
||||
float: left;
|
||||
min-width: 70em;
|
||||
}
|
||||
|
||||
/* Migration */
|
||||
|
||||
body#header-bg {
|
||||
background: url("../ui/Static-Background.png") repeat-x scroll left top #EDEDED;
|
||||
}
|
||||
|
||||
.container_1 {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 960px;
|
||||
background: url("../ui/centered-bg.png") no-repeat scroll 0 7em transparent;
|
||||
min-height: 40em;
|
||||
}
|
||||
|
||||
#formwindow {
|
||||
-moz-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;
|
||||
}
|
||||
|
||||
.formcontent {
|
||||
padding: 0 1em 2em 2em;
|
||||
}
|
||||
|
||||
#error-box {
|
||||
-moz-border-radius: 0.3em 0.3em 0.3em 0.3em;
|
||||
background-color: #FFEBE8;
|
||||
border: 1px solid #DD3C10;
|
||||
margin: 0 2em 1em;
|
||||
padding: 1em 1em 0 0;
|
||||
}
|
||||
|
||||
.# {
|
||||
background: url("../ui/ipalogo.png") no-repeat scroll left top transparent;
|
||||
border: none;
|
||||
float: left;
|
||||
height: 36px;
|
||||
width: 205px;
|
||||
}
|
||||
|
||||
#formwindow h4 {
|
||||
background-color: #F0F0F0;
|
||||
font-size: 1.6em;
|
||||
padding: 18px 15px 14px 22px;
|
||||
text-transform: uppercase;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#login li {
|
||||
padding-bottom: 15px;
|
||||
text-align: right;
|
||||
width: 370px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#login li input {
|
||||
-moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2) inset;
|
||||
margin-left: 15px;
|
||||
padding: 2px 10px;
|
||||
width: 248px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
.formbutton input {
|
||||
float: right;
|
||||
margin: 1em 1em 1em 0;
|
||||
-moz-border-radius: 0.3em 0.3em 0.3em 0.3em;
|
||||
background: -moz-linear-gradient(center top, #959595, #5e5e5e) repeat scroll 0 0 transparent;
|
||||
border: 1px solid #777777;
|
||||
color: #ffffff;
|
||||
font-weight: normal;
|
||||
padding: 0.5em 0.8em;
|
||||
}
|
||||
|
||||
.textblock {
|
||||
text-align: center;
|
||||
margin-top: 6em;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.textblockkrb {
|
||||
text-align: left;
|
||||
margin-top: 5em;
|
||||
font-size: 1.1em;
|
||||
padding-left: 3em;
|
||||
|
||||
}
|
||||
|
||||
.textblockkrb ul li {
|
||||
list-style-type: none;
|
||||
padding: .15em;
|
||||
|
||||
}
|
||||
|
||||
|
||||
h3 {
|
||||
color: #333333;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.5em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h5 {
|
||||
color: #333333;
|
||||
font-family: "Overpass Bold", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: 3em;
|
||||
margin-left: 5em;
|
||||
margin-top: -3em;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Search */
|
||||
|
||||
.search-controls {
|
||||
-moz-border-radius: .7em .7em 0 0;
|
||||
height:2.5em;
|
||||
background: -moz-linear-gradient(top, #eeeeee, #dfdfdf);
|
||||
position: relative;
|
||||
padding: 1em 1.5em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.search-table > a:link,a:visted{
|
||||
color:black;
|
||||
}
|
||||
|
||||
.search-table{
|
||||
padding: 0;
|
||||
width:100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.search-table td{
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.search-table th{
|
||||
padding-left: 0.5em;
|
||||
background-color:#f6f6f6;
|
||||
color:#333333;
|
||||
text-align: left;
|
||||
border: 1px solid #dfdfdf;
|
||||
}
|
||||
|
||||
.search-table tfoot tr td span{
|
||||
border-top: 1px solid #dfdfdf;
|
||||
padding: 0.9em 0 0 1em;
|
||||
display: block;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.search-table tr:nth-child(even){
|
||||
# background-color:#CCC;
|
||||
}
|
||||
|
||||
.search-table tr:nth-child(odd){
|
||||
# background-color:#FFF;
|
||||
}
|
||||
|
||||
.entity-views{
|
||||
list-style-type:none;
|
||||
}
|
||||
|
||||
.entity-views li {
|
||||
display:inline;
|
||||
cursor: pointer;
|
||||
padding: 0.4em;
|
||||
}
|
||||
|
||||
.strikethrough { text-decoration: line-through; }
|
||||
|
||||
|
||||
.key-status-valid {
|
||||
list-style-type: circle;
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.key-status-missing {
|
||||
list-style-type: circle;
|
||||
color: #daa520;
|
||||
}
|
||||
|
||||
.key-status-active {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
.certificate-status-valid {
|
||||
list-style-type: circle;
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
.certificate-status-revoked {
|
||||
list-style-type: circle;
|
||||
color: #ff0000;
|
||||
}
|
||||
|
||||
.certificate-status-missing {
|
||||
list-style-type: circle;
|
||||
color: #daa520;
|
||||
}
|
||||
|
||||
.certificate-status-active {
|
||||
list-style-type: disc;
|
||||
}
|
||||
|
||||
dl.modal {
|
||||
clear: both;
|
||||
margin-left: 1em;
|
||||
margin-top: 1em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
dl.modal dt {
|
||||
clear: left;
|
||||
float: left;
|
||||
padding-bottom: 0;
|
||||
padding-right: 0;
|
||||
text-align: right;
|
||||
width: 10em;
|
||||
}
|
||||
|
||||
dl.modal dd {
|
||||
float: left;
|
||||
padding-bottom: 0;
|
||||
margin-left: 0.8em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ui-widget-content {
|
||||
border:0;
|
||||
}
|
||||
|
||||
table.scrollable thead {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table.scrollable tbody {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.adder-dialog-filter {
|
||||
height: 2.5em;
|
||||
}
|
||||
|
||||
.adder-dialog-results {
|
||||
position: relative;
|
||||
height: 20.0em;
|
||||
}
|
||||
|
||||
.adder-dialog-available {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 25.0em;
|
||||
}
|
||||
|
||||
.adder-dialog-buttons {
|
||||
position: absolute;
|
||||
top: 1.5em;
|
||||
left: 25em;
|
||||
right: 25;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.adder-dialog-selected {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.adder-dialog-internal {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 4.5em;
|
||||
width: 25em;
|
||||
}
|
||||
|
||||
.adder-dialog-external {
|
||||
border: 1px solid black;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 25em;
|
||||
height: 4em;
|
||||
}
|
572
install/migration/jquery-ui.css
vendored
Normal file
572
install/migration/jquery-ui.css
vendored
Normal file
@ -0,0 +1,572 @@
|
||||
/*
|
||||
* jQuery UI CSS Framework @VERSION
|
||||
*
|
||||
* 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/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute; left: -99999999px; }
|
||||
.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:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
|
||||
.ui-helper-clearfix { display: inline-block; }
|
||||
/* required comment for clearfix to work in Opera \*/
|
||||
* html .ui-helper-clearfix { height:1%; }
|
||||
.ui-helper-clearfix { display:block; }
|
||||
/* end clearfix */
|
||||
.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 @VERSION
|
||||
*
|
||||
* 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/Theming/API
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,%20Arial,%20sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=0px&bgColorHeader=333333&bgTextureHeader=14_loop.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=111111&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: Verdana, Arial, sans-serif; font-size: 1.1em; }
|
||||
.ui-widget .ui-widget { font-size: 1em; }
|
||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana, Arial, sans-serif; font-size: 1em; }
|
||||
.ui-widget-content { border: 1px solid #cccccc; background: #f9f9f9 url(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: #333333 url(ui-bg_loop_8_333333_21x21.png) 50% 50% repeat; 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: #111111 url(ui-bg_glass_40_111111_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(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(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(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(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(ui-icons_222222_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(ui-icons_bbbbbb_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(ui-icons_ededed_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(ui-icons_ffffff_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(ui-icons_222222_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(ui-icons_4ca300_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(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-tl { -moz-border-radius-topleft: 0px; -webkit-border-top-left-radius: 0px; border-top-left-radius: 0px; }
|
||||
.ui-corner-tr { -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; }
|
||||
.ui-corner-bl { -moz-border-radius-bottomleft: 0px; -webkit-border-bottom-left-radius: 0px; border-bottom-left-radius: 0px; }
|
||||
.ui-corner-br { -moz-border-radius-bottomright: 0px; -webkit-border-bottom-right-radius: 0px; border-bottom-right-radius: 0px; }
|
||||
.ui-corner-top { -moz-border-radius-topleft: 0px; -webkit-border-top-left-radius: 0px; border-top-left-radius: 0px; -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; }
|
||||
.ui-corner-bottom { -moz-border-radius-bottomleft: 0px; -webkit-border-bottom-left-radius: 0px; border-bottom-left-radius: 0px; -moz-border-radius-bottomright: 0px; -webkit-border-bottom-right-radius: 0px; border-bottom-right-radius: 0px; }
|
||||
.ui-corner-right { -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; -moz-border-radius-bottomright: 0px; -webkit-border-bottom-right-radius: 0px; border-bottom-right-radius: 0px; }
|
||||
.ui-corner-left { -moz-border-radius-topleft: 0px; -webkit-border-top-left-radius: 0px; border-top-left-radius: 0px; -moz-border-radius-bottomleft: 0px; -webkit-border-bottom-left-radius: 0px; border-bottom-left-radius: 0px; }
|
||||
.ui-corner-all { -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; }
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { background: #aaaaaa url(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(ui-bg_highlight-soft_50_aaaaaa_1x100.png) 50% top repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
|
||||
* jQuery UI Resizable @VERSION
|
||||
*
|
||||
* 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/Resizable#theming
|
||||
*/
|
||||
.ui-resizable { position: relative;}
|
||||
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; 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 @VERSION
|
||||
*
|
||||
* 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/Selectable#theming
|
||||
*/
|
||||
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
|
||||
/*
|
||||
* jQuery UI Accordion @VERSION
|
||||
*
|
||||
* 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/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 @VERSION
|
||||
*
|
||||
* 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/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 @VERSION
|
||||
*
|
||||
* 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 @VERSION
|
||||
*
|
||||
* 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/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 @VERSION
|
||||
*
|
||||
* 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/Dialog#theming
|
||||
*/
|
||||
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
|
||||
.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
|
||||
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 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 @VERSION
|
||||
*
|
||||
* 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/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 @VERSION
|
||||
*
|
||||
* 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/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 @VERSION
|
||||
*
|
||||
* 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/Datepicker#theming
|
||||
*/
|
||||
.ui-datepicker { width: 17em; padding: .2em .2em 0; }
|
||||
.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%; }
|
||||
|
||||
/* 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 @VERSION
|
||||
*
|
||||
* 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/Progressbar#theming
|
||||
*/
|
||||
.ui-progressbar { height:2em; text-align: left; }
|
||||
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
|
120
install/migration/migration.py
Normal file
120
install/migration/migration.py
Normal file
@ -0,0 +1,120 @@
|
||||
# Authors:
|
||||
# Pavel Zuna <pzuna@redhat.com>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
Password migration script
|
||||
"""
|
||||
|
||||
import cgi
|
||||
import errno
|
||||
import glob
|
||||
import ldap
|
||||
import wsgiref
|
||||
import logging
|
||||
from ipapython.ipautil import get_ipa_basedn
|
||||
|
||||
BASE_DN = ''
|
||||
LDAP_URI = 'ldaps://localhost:636'
|
||||
|
||||
def convert_exception(error):
|
||||
"""
|
||||
Convert an LDAP exception into something more readable.
|
||||
"""
|
||||
if not isinstance(error, ldap.TIMEOUT):
|
||||
desc = error.args[0]['desc'].strip()
|
||||
info = error.args[0].get('info', '').strip()
|
||||
else:
|
||||
desc = ''
|
||||
info = ''
|
||||
|
||||
return '%s (%s)' % (desc, info)
|
||||
|
||||
def wsgi_redirect(start_response, loc):
|
||||
start_response('302 Found', [('Location', loc)])
|
||||
return []
|
||||
|
||||
def get_ui_url(environ):
|
||||
full_url = wsgiref.util.request_uri(environ)
|
||||
index = full_url.rfind(environ.get('SCRIPT_NAME',''))
|
||||
if index == -1:
|
||||
raise ValueError('Cannot strip the script URL from full URL "%s"' % full_url)
|
||||
return full_url[:index] + "/ipa/ui"
|
||||
|
||||
def get_base_dn():
|
||||
"""
|
||||
Retrieve LDAP server base DN.
|
||||
"""
|
||||
global BASE_DN
|
||||
|
||||
if BASE_DN:
|
||||
return BASE_DN
|
||||
try:
|
||||
conn = ldap.initialize(LDAP_URI)
|
||||
conn.simple_bind_s('', '')
|
||||
BASE_DN = get_ipa_basedn(conn)
|
||||
except ldap.LDAPError, e:
|
||||
logging.error('migration context search failed: %s' % e)
|
||||
return ''
|
||||
finally:
|
||||
conn.unbind_s()
|
||||
|
||||
return BASE_DN
|
||||
|
||||
def bind(username, password):
|
||||
base_dn = get_base_dn()
|
||||
if not base_dn:
|
||||
logging.error('migration unable to get base dn')
|
||||
raise IOError(errno.EIO, 'Cannot get Base DN')
|
||||
bind_dn = 'uid=%s,cn=users,cn=accounts,%s' % (username, base_dn)
|
||||
try:
|
||||
conn = ldap.initialize(LDAP_URI)
|
||||
conn.simple_bind_s(bind_dn, password)
|
||||
except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM,
|
||||
ldap.NO_SUCH_OBJECT), e:
|
||||
logging.error('migration invalid credentials for %s: %s' % (bind_dn, convert_exception(e)))
|
||||
raise IOError(errno.EPERM, 'Invalid LDAP credentials for user %s' % username)
|
||||
except ldap.LDAPError, e:
|
||||
logging.error('migration bind failed: %s' % convert_exception(e))
|
||||
raise IOError(errno.EIO, 'Bind error')
|
||||
finally:
|
||||
conn.unbind_s()
|
||||
|
||||
def application(environ, start_response):
|
||||
global LDAP_URI
|
||||
|
||||
if environ.get('REQUEST_METHOD', None) != 'POST':
|
||||
return wsgi_redirect(start_response, 'index.html')
|
||||
|
||||
form_data = cgi.FieldStorage(fp=environ['wsgi.input'], environ=environ)
|
||||
if not form_data.has_key('username') or not form_data.has_key('password'):
|
||||
return wsgi_redirect(start_response, 'invalid.html')
|
||||
|
||||
slapd_sockets = glob.glob('/var/run/slapd-*.socket')
|
||||
if slapd_sockets:
|
||||
LDAP_URI = 'ldapi://%s' % slapd_sockets[0].replace('/', '%2f')
|
||||
|
||||
try:
|
||||
bind(form_data['username'].value, form_data['password'].value)
|
||||
except IOError as err:
|
||||
if err.errno == errno.EPERM:
|
||||
return wsgi_redirect(start_response, 'invalid.html')
|
||||
if err.errno == errno.EIO:
|
||||
return wsgi_redirect(start_response, 'error.html')
|
||||
|
||||
ui_url = get_ui_url(environ)
|
||||
return wsgi_redirect(start_response, ui_url)
|
22
install/po/LINGUAS
Normal file
22
install/po/LINGUAS
Normal file
@ -0,0 +1,22 @@
|
||||
# Languages in the sort order on Transifex
|
||||
as # Assamese
|
||||
bn_IN # Bengali (India)
|
||||
zh_CN # Chinese (China)
|
||||
zh_TW # Chinese (Taiwan)
|
||||
nl # Dutch
|
||||
fr # French
|
||||
de # German
|
||||
el # Greek
|
||||
gu # Gujarati
|
||||
id # Indonesian
|
||||
ja_JP # Japanese (Japan)
|
||||
ja # Japanese
|
||||
kn # Kannada
|
||||
fa # Persian
|
||||
pl # Polish
|
||||
pt_BR # Portuguese (Brazilian)
|
||||
pt # Portuguese
|
||||
ru # Russian
|
||||
es # Spanish (Castilian)
|
||||
sv # Swedish
|
||||
uk # Ukrainian
|
208
install/po/Makefile.in
Normal file
208
install/po/Makefile.in
Normal file
@ -0,0 +1,208 @@
|
||||
prefix = @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@
|
||||
TX = @TX@
|
||||
|
||||
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 "^tests/" -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)
|
||||
|
||||
PY_EXPLICIT_FILES = \
|
||||
ipa \
|
||||
install/tools/ipa-replica-manage \
|
||||
install/tools/ipa-server-certinstall \
|
||||
install/tools/ipa-replica-conncheck \
|
||||
install/tools/ipa-replica-install \
|
||||
install/tools/ipa-nis-manage \
|
||||
install/tools/ipa-upgradeconfig \
|
||||
install/tools/ipa-replica-prepare \
|
||||
install/tools/ipa-compat-manage \
|
||||
install/tools/ipa-managed-entries \
|
||||
install/tools/ipa-server-install \
|
||||
install/tools/ipa-ldap-updater \
|
||||
install/tools/ipa-dns-install \
|
||||
install/tools/ipa-ca-install \
|
||||
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_lang test mo-files debug
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
update-po: update-pot
|
||||
$(MAKE) $(po_files)
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
rm -f $(DOMAIN).pot.update $(DOMAIN).pot.update.tmp $(DOMAIN).pot.tmp
|
||||
|
||||
clean: mostlyclean
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
maintainer-clean: distclean
|
||||
|
||||
# We test our translations by taking the original untranslated string
|
||||
# (e.g. msgid) and prepend a prefix character and then append a suffix
|
||||
# character. The test consists of asserting that the first character in the
|
||||
# translated string is the prefix, the last character in the translated string
|
||||
# is the suffix and the everything between the first and last character exactly
|
||||
# matches the original msgid.
|
||||
#
|
||||
# We use unicode characters not in the ascii character set for the prefix and
|
||||
# suffix to enhance the test. To make reading the translated string easier the
|
||||
# prefix is the unicode right pointing arrow and the suffix left pointing arrow,
|
||||
# thus the translated string looks like the original string enclosed in
|
||||
# arrows. In ASCII art the string "foo" would render as:
|
||||
# -->foo<--
|
||||
#
|
||||
# Unicode right pointing arrow: u'\u2192', utf-8 = '\xe2\x86\x92'
|
||||
# Unicode left pointing arrow: u'\u2190', utf-8 = '\xe2\x86\x90'
|
||||
#
|
||||
# The sed command below performs the prefix and suffix substitution.
|
||||
#
|
||||
# When msginit is invoked with an English target locale it copies the msgid
|
||||
# into the msgstr. This is an undocumented feature of msginit. Otherwise the
|
||||
# msgstr will be set to the empty string (i.e. untranslated). We depend on
|
||||
# the msgid being copied to the msgstr.
|
||||
|
||||
test_lang:
|
||||
rm -rf test.po test_locale
|
||||
$(MSGINIT) --no-translator -i $(DOMAIN).pot -l en_US -o test.po
|
||||
$(SED) -i -r -e 's/Language: en_US/Language: xh_ZA/' test.po
|
||||
$(SED) -i -r -e 's/^msgstr[ \t]+"(..*)"[ \t]*$$/msgstr "\xe2\x86\x92\1\xe2\x86\x90"/' test.po
|
||||
$(SED) -i -r -e 's/^msgstr[ \t]+"(.*)(\\n)(.)"[ \t]*$$/msgstr "\1\xe2\x86\x90\2"/' test.po
|
||||
$(MKDIR_P) test_locale/xh_ZA/LC_MESSAGES
|
||||
$(MSGFMT) -o test_locale/xh_ZA/LC_MESSAGES/ipa.mo test.po
|
||||
|
||||
test: test_lang
|
||||
./test_i18n.py
|
||||
|
||||
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)
|
||||
|
131
install/po/README
Normal file
131
install/po/README
Normal file
@ -0,0 +1,131 @@
|
||||
Q: 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: How do I pick up new strings to translate from the source files after the
|
||||
source have been modified?
|
||||
|
||||
A: make update-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: 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 invailid Plural's 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 <jdennis@redhat.com>
|
7813
install/po/as.po
Normal file
7813
install/po/as.po
Normal file
File diff suppressed because it is too large
Load Diff
7815
install/po/bn_IN.po
Normal file
7815
install/po/bn_IN.po
Normal file
File diff suppressed because it is too large
Load Diff
16
install/po/contributing_translators.txt
Normal file
16
install/po/contributing_translators.txt
Normal file
@ -0,0 +1,16 @@
|
||||
bn_IN: Bengali India
|
||||
sankarshan mukhopadhyay <sankarshan@fedoraproject.org>
|
||||
es: Spanish
|
||||
Héctor Daniel Cabrera <logan@fedoraproject.org>
|
||||
id: Indonesian
|
||||
Teguh DC <dheche@songolimo.net>
|
||||
kn: Kannada
|
||||
gundachandru <gundachandru@gmail.com>
|
||||
pl: Polish
|
||||
Piotr Drąg <piotrdrag@gmail.com>
|
||||
ru: Russian
|
||||
Andrew Martynov <andrewm@inventa.ru>
|
||||
uk: Ukrainian
|
||||
Yuri Chornoivan <yurchor@ukr.net>
|
||||
zh_CN: Chinese Simplified
|
||||
Jake Li <gnozil@gmail.com>
|
7814
install/po/de.po
Normal file
7814
install/po/de.po
Normal file
File diff suppressed because it is too large
Load Diff
7813
install/po/el.po
Normal file
7813
install/po/el.po
Normal file
File diff suppressed because it is too large
Load Diff
9672
install/po/es.po
Normal file
9672
install/po/es.po
Normal file
File diff suppressed because it is too large
Load Diff
7794
install/po/fa.po
Normal file
7794
install/po/fa.po
Normal file
File diff suppressed because it is too large
Load Diff
7814
install/po/fr.po
Normal file
7814
install/po/fr.po
Normal file
File diff suppressed because it is too large
Load Diff
7813
install/po/gu.po
Normal file
7813
install/po/gu.po
Normal file
File diff suppressed because it is too large
Load Diff
7814
install/po/he.po
Normal file
7814
install/po/he.po
Normal file
File diff suppressed because it is too large
Load Diff
7798
install/po/id.po
Normal file
7798
install/po/id.po
Normal file
File diff suppressed because it is too large
Load Diff
7880
install/po/ipa.pot
Normal file
7880
install/po/ipa.pot
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user